From 9f46488805e86b1bc341ea1620b866016c2ce5ed Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 20 May 2020 14:34:42 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-0-stable-ee --- qa/spec/factory/resource/user_spec.rb | 8 +- qa/spec/git/repository_spec.rb | 127 +++++++++++++---- qa/spec/resource/ssh_key_spec.rb | 21 +++ qa/spec/service/docker_run/gitlab_runner_spec.rb | 173 +++++++++++++++++++++++ qa/spec/specs/helpers/quarantine_spec.rb | 8 -- qa/spec/specs/runner_spec.rb | 14 ++ 6 files changed, 313 insertions(+), 38 deletions(-) create mode 100644 qa/spec/resource/ssh_key_spec.rb create mode 100644 qa/spec/service/docker_run/gitlab_runner_spec.rb (limited to 'qa/spec') diff --git a/qa/spec/factory/resource/user_spec.rb b/qa/spec/factory/resource/user_spec.rb index 820c506b715..d59ee24c758 100644 --- a/qa/spec/factory/resource/user_spec.rb +++ b/qa/spec/factory/resource/user_spec.rb @@ -2,7 +2,7 @@ describe QA::Resource::User do describe "#fabricate_via_api!" do - Response = Struct.new(:code, :body) + response = Struct.new(:code, :body) it 'fetches an existing user' do existing_users = [ @@ -13,8 +13,8 @@ describe QA::Resource::User do web_url: '' } ] - users_response = Response.new('200', JSON.dump(existing_users)) - single_user_response = Response.new('200', JSON.dump(existing_users.first)) + users_response = response.new('200', JSON.dump(existing_users)) + single_user_response = response.new('200', JSON.dump(existing_users.first)) expect(subject).to receive(:api_get_from).with("/users?username=name").and_return(users_response) expect(subject).to receive(:api_get_from).with("/users/0").and_return(single_user_response) @@ -26,7 +26,7 @@ describe QA::Resource::User do end it 'tries to create a user if it does not exist' do - expect(subject).to receive(:api_get_from).with("/users?username=foo").and_return(Response.new('200', '[]')) + expect(subject).to receive(:api_get_from).with("/users?username=foo").and_return(response.new('200', '[]')) expect(subject).to receive(:api_post).and_return({ web_url: '' }) subject.username = 'foo' diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb index 6cca9f55e11..8355c77f493 100644 --- a/qa/spec/git/repository_spec.rb +++ b/qa/spec/git/repository_spec.rb @@ -3,55 +3,119 @@ describe QA::Git::Repository do include Helpers::StubENV - shared_context 'git directory' do - let(:repository) { described_class.new } + shared_context 'unresolvable git directory' do + let(:repo_uri) { 'http://foo/bar.git' } + let(:repo_uri_with_credentials) { 'http://root@foo/bar.git' } + let(:repository) { described_class.new.tap { |r| r.uri = repo_uri } } let(:tmp_git_dir) { Dir.mktmpdir } let(:tmp_netrc_dir) { Dir.mktmpdir } before do stub_env('GITLAB_USERNAME', 'root') - cd_empty_temp_directory - set_bad_uri - allow(repository).to receive(:tmp_home_dir).and_return(tmp_netrc_dir) end + around do |example| + FileUtils.cd(tmp_git_dir) do + example.run + end + end + after do - # Switch to a safe dir before deleting tmp dirs to avoid dir access errors - FileUtils.cd __dir__ FileUtils.remove_entry_secure(tmp_git_dir, true) FileUtils.remove_entry_secure(tmp_netrc_dir, true) end + end - def cd_empty_temp_directory - FileUtils.cd tmp_git_dir + shared_examples 'command with retries' do + let(:extra_args) { {} } + let(:result_output) { +'Command successful' } + let(:result) { described_class::Result.new(any_args, 0, result_output) } + let(:command_return) { result_output } + + context 'when command is successful' do + it 'returns the #run command Result output' do + expect(repository).to receive(:run).with(command, extra_args.merge(max_attempts: 3)).and_return(result) + + expect(call_method).to eq(command_return) + end end - def set_bad_uri - repository.uri = 'http://foo/bar.git' + context 'when command is not successful the first time' do + context 'and retried command is successful' do + it 'retries the command twice and returns the successful #run command Result output' do + expect(Open3).to receive(:capture2e).and_return([+'', double(exitstatus: 1)]).twice + expect(Open3).to receive(:capture2e).and_return([result_output, double(exitstatus: 0)]) + + expect(call_method).to eq(command_return) + end + end + + context 'and retried command is not successful after 3 attempts' do + it 'raises a RepositoryCommandError exception' do + expect(Open3).to receive(:capture2e).and_return([+'FAILURE', double(exitstatus: 42)]).exactly(3).times + + expect { call_method }.to raise_error(described_class::RepositoryCommandError, /The command .* failed \(42\) with the following output:\nFAILURE/) + end + end end end context 'with default credentials' do - include_context 'git directory' do + include_context 'unresolvable git directory' do before do repository.use_default_credentials end end describe '#clone' do - it 'is unable to resolve host' do - expect { repository.clone }.to raise_error(described_class::RepositoryCommandError, /The command .* failed \(128\) with the following output/) + let(:opts) { '' } + let(:call_method) { repository.clone } + let(:command) { "git clone #{opts} #{repo_uri_with_credentials} ./" } + + context 'when no opts is given' do + it_behaves_like 'command with retries' + end + + context 'when opts is given' do + let(:opts) { '--depth 1' } + + it_behaves_like 'command with retries' do + let(:call_method) { repository.clone(opts) } + end + end + end + + describe '#shallow_clone' do + it_behaves_like 'command with retries' do + let(:call_method) { repository.shallow_clone } + let(:command) { "git clone --depth 1 #{repo_uri_with_credentials} ./" } + end + end + + describe '#delete_tag' do + it_behaves_like 'command with retries' do + let(:tag_name) { 'v1.0' } + let(:call_method) { repository.delete_tag(tag_name) } + let(:command) { "git push origin --delete #{tag_name}" } end end describe '#push_changes' do - before do - `git init` # need a repo to push from + let(:branch) { 'master' } + let(:call_method) { repository.push_changes } + let(:command) { "git push #{repo_uri_with_credentials} #{branch}" } + + context 'when no branch is given' do + it_behaves_like 'command with retries' end - it 'fails to push changes' do - expect { repository.push_changes }.to raise_error(described_class::RepositoryCommandError, /The command .* failed \(1\) with the following output/) + context 'when branch is given' do + let(:branch) { 'my-branch' } + + it_behaves_like 'command with retries' do + let(:call_method) { repository.push_changes(branch) } + end end end @@ -59,6 +123,7 @@ describe QA::Git::Repository do [0, 1, 2].each do |version| it "configures git to use protocol version #{version}" do expect(repository).to receive(:run).with("git config protocol.version #{version}") + repository.git_protocol = version end end @@ -69,21 +134,31 @@ describe QA::Git::Repository do end describe '#fetch_supported_git_protocol' do - Result = Struct.new(:response) + let(:call_method) { repository.fetch_supported_git_protocol } + + it_behaves_like 'command with retries' do + let(:command) { "git ls-remote #{repo_uri_with_credentials}" } + let(:result_output) { +'packet: git< version 2' } + let(:command_return) { '2' } + let(:extra_args) { { env: "GIT_TRACE_PACKET=1" } } + end it "reports the detected version" do - expect(repository).to receive(:run).and_return(Result.new("packet: git< version 2")) - expect(repository.fetch_supported_git_protocol).to eq('2') + expect(repository).to receive(:run).and_return(described_class::Result.new(any_args, 0, "packet: git< version 2")) + + expect(call_method).to eq('2') end it 'reports unknown if version is unknown' do - expect(repository).to receive(:run).and_return(Result.new("packet: git< version -1")) - expect(repository.fetch_supported_git_protocol).to eq('unknown') + expect(repository).to receive(:run).and_return(described_class::Result.new(any_args, 0, "packet: git< version -1")) + + expect(call_method).to eq('unknown') end it 'reports unknown if content does not identify a version' do - expect(repository).to receive(:run).and_return(Result.new("foo")) - expect(repository.fetch_supported_git_protocol).to eq('unknown') + expect(repository).to receive(:run).and_return(described_class::Result.new(any_args, 0, "foo")) + + expect(call_method).to eq('unknown') end end @@ -96,7 +171,7 @@ describe QA::Git::Repository do end context 'with specific credentials' do - include_context 'git directory' + include_context 'unresolvable git directory' context 'before setting credentials' do it 'does not add credentials to .netrc' do diff --git a/qa/spec/resource/ssh_key_spec.rb b/qa/spec/resource/ssh_key_spec.rb new file mode 100644 index 00000000000..b2b5ec070e1 --- /dev/null +++ b/qa/spec/resource/ssh_key_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +describe QA::Resource::SSHKey do + describe '#key' do + it 'generates a default key' do + expect(subject.key).to be_a(QA::Runtime::Key::RSA) + end + end + + describe '#title' do + it 'generates a default title' do + expect(subject.title).to match(/E2E test key: \d+/) + end + + it 'is possible to set the title' do + subject.title = 'I am in a title' + + expect(subject.title).to eq('E2E test key: I am in a title') + end + end +end diff --git a/qa/spec/service/docker_run/gitlab_runner_spec.rb b/qa/spec/service/docker_run/gitlab_runner_spec.rb new file mode 100644 index 00000000000..db1bb74ca8f --- /dev/null +++ b/qa/spec/service/docker_run/gitlab_runner_spec.rb @@ -0,0 +1,173 @@ +# frozen_string_literal: true + +module QA + describe Service::DockerRun::GitlabRunner do + let(:runner_name) { 'test-runner' } + let(:address) { 'gitlab.test' } + let(:token) { 'abc123' } + + let(:tags) { %w[qa test] } + + subject do + described_class.new(runner_name).tap do |runner| + runner.address = address + runner.token = token + end + end + + it 'defaults to run untagged' do + expect(subject.run_untagged).to be(true) + end + + describe '#register!' do + let(:register) { subject.send(:register!) } + + before do + allow(subject).to receive(:shell) + end + + context 'defaults' do + before do + register + end + + it 'runs non-interactively' do + expect(subject).to have_received(:shell).with(/ --non-interactive /) + end + + it 'sets pertinent information' do + expect(subject).to have_received(:shell).with(/--name #{runner_name} /) + expect(subject).to have_received(:shell).with(/--url #{subject.address} /) + expect(subject).to have_received(:shell).with(/--registration-token #{subject.token} /) + end + + it 'runs untagged' do + expect(subject).to have_received(:shell).with(/--run-untagged=true /) + end + + it 'has no tags' do + expect(subject.tags).to be_falsey + end + + it 'runs daemonized' do + expect(subject).to have_received(:shell).with(/ -d /) + end + + it 'cleans itself up' do + expect(subject).to have_received(:shell).with(/ --rm /) + end + end + + context 'running untagged' do + before do + register + end + + it 'passes --run-untagged=true' do + expect(subject).to have_received(:shell).with(/--run-untagged=true /) + end + + it 'does not pass tag list' do + expect(subject).not_to have_received(:shell).with(/--tag-list/) + end + end + + context 'running tagged' do + context 'with only tags set' do + before do + subject.tags = tags + + register + end + + it 'does not pass --run-untagged' do + expect(subject).not_to have_received(:shell).with(/--run-untagged=true/) + end + + it 'passes the tags with comma-separation' do + expect(subject).to have_received(:shell).with(/--tag-list #{tags.join(',')} /) + end + end + + context 'with specifying only run_untagged' do + before do + subject.run_untagged = false + end + + it 'raises an error if tags are not specified' do + expect { register }.to raise_error(/must specify tags/i) + end + end + + context 'when specifying contradicting variables' do + before do + subject.tags = tags + subject.run_untagged = true + end + + it 'raises an error' do + expect { register }.to raise_error(/conflicting options/i) + end + end + end + + context 'executors' do + it 'defaults to the shell executor' do + register + + expect(subject).to have_received(:shell).with(/--executor shell /) + end + + context 'docker' do + before do + subject.executor = :docker + + register + end + + it 'specifies the docker executor' do + expect(subject).to have_received(:shell).with(/--executor docker /) + end + + it 'mounts the docker socket to the host runner' do + expect(subject).to have_received(:shell).with(/-v \/var\/run\/docker.sock:\/var\/run\/docker.sock /) + end + + it 'runs in privileged mode' do + expect(subject).to have_received(:shell).with(/--privileged /) + end + + it 'has a default image' do + expect(subject).to have_received(:shell).with(/--docker-image \b.+\b /) + end + + it 'does not verify TLS' do + expect(subject).to have_received(:shell).with(/--docker-tlsverify=false /) + end + + it 'passes privileged mode' do + expect(subject).to have_received(:shell).with(/--docker-privileged=true /) + end + + it 'passes the host network' do + expect(subject).to have_received(:shell).with(/--docker-network-mode=#{subject.network}/) + end + end + end + end + + describe '#tags=' do + before do + subject.tags = tags + end + + it 'sets the tags' do + expect(subject.tags).to eq(tags) + end + + it 'sets run_untagged' do + expect(subject.run_untagged).to be(false) + end + end + end +end diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb index d5c6820f0a9..1f09c3f73ac 100644 --- a/qa/spec/specs/helpers/quarantine_spec.rb +++ b/qa/spec/specs/helpers/quarantine_spec.rb @@ -31,14 +31,6 @@ RSpec.configure do |c| config.color_mode = :off - # Load airborne again to avoid "undefined method `match_expected_default?'" errors - # that happen because a hook calls a method added via a custom RSpec setting - # that is removed when the RSpec configuration is sandboxed. - # If this needs to be changed (e.g., to load other libraries as well), see - # this discussion for alternative solutions: - # https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/25223#note_143392053 - load 'airborne.rb' - ex.run end end diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb index 1a3efe0b46c..361588fa14f 100644 --- a/qa/spec/specs/runner_spec.rb +++ b/qa/spec/specs/runner_spec.rb @@ -14,6 +14,8 @@ describe QA::Specs::Runner do describe '#perform' do before do allow(QA::Runtime::Browser).to receive(:configure!) + + QA::Runtime::Scenario.define(:gitlab_address, "http://gitlab.test") end it_behaves_like 'excludes orchestrated' @@ -80,6 +82,18 @@ describe QA::Specs::Runner do end end + context 'when running against live environment' do + before do + QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com") + end + + it 'includes default args and excludes the skip_live_env tag' do + expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~skip_live_env', *described_class::DEFAULT_TEST_PATH_ARGS]) + + subject.perform + end + end + context 'testable features' do shared_examples 'one supported feature' do |feature| before do -- cgit v1.2.3