diff --git a/lib/docker/container.rb b/lib/docker/container.rb index 3c0cc044..10ea8d98 100644 --- a/lib/docker/container.rb +++ b/lib/docker/container.rb @@ -60,8 +60,11 @@ def exec(command, options = {}, &block) detach = options.delete(:detach) || false user = options.delete(:user) stdin = options.delete(:stdin) - stdout = options.delete(:stdout) || !detach - stderr = options.delete(:stderr) || !detach + # `options.delete(:stdout) || !detach` turns an explicit false back into + # true, so these have to be tested for presence rather than truthiness. + # They default to the inverse of :detach when the caller says nothing. + stdout = options.key?(:stdout) ? options.delete(:stdout) : !detach + stderr = options.key?(:stderr) ? options.delete(:stderr) : !detach wait = options.delete(:wait) opts = { diff --git a/spec/docker/container_spec.rb b/spec/docker/container_spec.rb index d5c8a34f..f27b1c05 100644 --- a/spec/docker/container_spec.rb +++ b/spec/docker/container_spec.rb @@ -578,6 +578,30 @@ end end + # `stderr = options.delete(:stderr) || !detach` turns an explicit false back + # into true, so both stream options were impossible to switch off. + context 'when stderr is false' do + let(:output) { + subject.exec(['bash', '-c', 'echo out; echo err 1>&2'], stderr: false) + } + + it 'captures stdout but not stderr' do + expect(output[0]).to eq(["out\n"]) + expect(output[1]).to be_empty + end + end + + context 'when stdout is false' do + let(:output) { + subject.exec(['bash', '-c', 'echo out; echo err 1>&2'], stdout: false) + } + + it 'captures stderr but not stdout' do + expect(output[0]).to be_empty + expect(output[1]).to eq(["err\n"]) + end + end + context 'when passed a block' do it 'streams the stdout/stderr messages' do chunk = nil