diff --git a/lib/docker/connection.rb b/lib/docker/connection.rb index d678d243..03c21af0 100644 --- a/lib/docker/connection.rb +++ b/lib/docker/connection.rb @@ -129,7 +129,12 @@ def podman? end def rootless? - @rootless ||= (info['Rootless'] == true) + # `||=` cannot cache a false result, so this has to test for the ivar + # itself. #info is not memoized, so re-evaluating means another /info + # request on every call against a non-rootless daemon. + return @rootless if defined?(@rootless) + + @rootless = (info['Rootless'] == true) end def version diff --git a/spec/docker/connection_spec.rb b/spec/docker/connection_spec.rb index 86291298..9778e8d1 100644 --- a/spec/docker/connection_spec.rb +++ b/spec/docker/connection_spec.rb @@ -112,6 +112,44 @@ end end + describe '#rootless?' do + subject { described_class.new('http://example.com:2375', {}) } + + # `@rootless ||= ...` cannot cache a false result, so on every non-rootless + # daemon each call re-issued the /info request. + it 'only queries /info once' do + expect(subject).to receive(:get).with('/info').once + .and_return('{"Rootless":false}') + + 3.times { subject.rootless? } + end + + it 'reports false for a non-rootless daemon' do + allow(subject).to receive(:get).with('/info') + .and_return('{"Rootless":false}') + + expect(subject.rootless?).to be false + end + + it 'reports true for a rootless daemon' do + allow(subject).to receive(:get).with('/info') + .and_return('{"Rootless":true}') + + expect(subject.rootless?).to be true + end + end + + describe '#podman?' do + subject { described_class.new('http://example.com:2375', {}) } + + it 'only queries /version once' do + expect(subject).to receive(:get).with('/version').once + .and_return('{"Components":[{"Name":"Engine"}]}') + + 3.times { subject.podman? } + end + end + describe '#to_s' do let(:url) { 'http://google.com:4000' } let(:options) { {} }