diff options
author | Mike Greiling <mike@pixelcog.com> | 2017-10-24 07:52:21 +0000 |
---|---|---|
committer | Mike Greiling <mike@pixelcog.com> | 2017-10-24 07:52:21 +0000 |
commit | f7bdfe5098c9a5a3a426344ba1d7dd668212cf7e (patch) | |
tree | 5a1cb2a90b0a2b5114f6f23712b68724b3e8a7e0 /spec/lib/gitlab/git/popen_spec.rb | |
parent | 9cd528aa7ac5066570cb50b909951a6c6b723935 (diff) | |
parent | e16add2267648d3d3ef1d98f9b53f67a29428791 (diff) | |
download | gitlab-ce-es-module-autosave.tar.gz |
Merge branch 'master' into 'es-module-autosave'es-module-autosave
# Conflicts:
# app/assets/javascripts/issuable_form.js
# app/assets/javascripts/notes.js
Diffstat (limited to 'spec/lib/gitlab/git/popen_spec.rb')
-rw-r--r-- | spec/lib/gitlab/git/popen_spec.rb | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/spec/lib/gitlab/git/popen_spec.rb b/spec/lib/gitlab/git/popen_spec.rb new file mode 100644 index 00000000000..2b65bc1cf15 --- /dev/null +++ b/spec/lib/gitlab/git/popen_spec.rb @@ -0,0 +1,132 @@ +require 'spec_helper' + +describe 'Gitlab::Git::Popen' do + let(:path) { Rails.root.join('tmp').to_s } + + let(:klass) do + Class.new(Object) do + include Gitlab::Git::Popen + end + end + + context 'popen' do + context 'zero status' do + let(:result) { klass.new.popen(%w(ls), path) } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to be_zero } + it { expect(output).to include('tests') } + end + + context 'non-zero status' do + let(:result) { klass.new.popen(%w(cat NOTHING), path) } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to eq(1) } + it { expect(output).to include('No such file or directory') } + end + + context 'unsafe string command' do + it 'raises an error when it gets called with a string argument' do + expect { klass.new.popen('ls', path) }.to raise_error(RuntimeError) + end + end + + context 'with custom options' do + let(:vars) { { 'foobar' => 123, 'PWD' => path } } + let(:options) { { chdir: path } } + + it 'calls popen3 with the provided environment variables' do + expect(Open3).to receive(:popen3).with(vars, 'ls', options) + + klass.new.popen(%w(ls), path, { 'foobar' => 123 }) + end + end + + context 'use stdin' do + let(:result) { klass.new.popen(%w[cat], path) { |stdin| stdin.write 'hello' } } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to be_zero } + it { expect(output).to eq('hello') } + end + end + + context 'popen_with_timeout' do + let(:timeout) { 1.second } + + context 'no timeout' do + context 'zero status' do + let(:result) { klass.new.popen_with_timeout(%w(ls), timeout, path) } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to be_zero } + it { expect(output).to include('tests') } + end + + context 'non-zero status' do + let(:result) { klass.new.popen_with_timeout(%w(cat NOTHING), timeout, path) } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to eq(1) } + it { expect(output).to include('No such file or directory') } + end + + context 'unsafe string command' do + it 'raises an error when it gets called with a string argument' do + expect { klass.new.popen_with_timeout('ls', timeout, path) }.to raise_error(RuntimeError) + end + end + end + + context 'timeout' do + context 'timeout' do + it "raises a Timeout::Error" do + expect { klass.new.popen_with_timeout(%w(sleep 1000), timeout, path) }.to raise_error(Timeout::Error) + end + + it "handles processes that do not shutdown correctly" do + expect { klass.new.popen_with_timeout(['bash', '-c', "trap -- '' SIGTERM; sleep 1000"], timeout, path) }.to raise_error(Timeout::Error) + end + end + + context 'timeout period' do + let(:time_taken) do + begin + start = Time.now + klass.new.popen_with_timeout(%w(sleep 1000), timeout, path) + rescue + Time.now - start + end + end + + it { expect(time_taken).to be >= timeout } + end + + context 'clean up' do + let(:instance) { klass.new } + + it 'kills the child process' do + expect(instance).to receive(:kill_process_group_for_pid).and_wrap_original do |m, *args| + # is the PID, and it should not be running at this point + m.call(*args) + + pid = args.first + begin + Process.getpgid(pid) + raise "The child process should have been killed" + rescue Errno::ESRCH + end + end + + expect { instance.popen_with_timeout(['bash', '-c', "trap -- '' SIGTERM; sleep 1000"], timeout, path) }.to raise_error(Timeout::Error) + end + end + end + end +end |