diff options
Diffstat (limited to 'spec/lib/gitlab')
31 files changed, 1568 insertions, 216 deletions
diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb index c0427639746..d2e7243ee05 100644 --- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb +++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' -describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do +describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :truncate do describe '#perform' do - set(:merge_request) { create(:merge_request) } - set(:merge_request_diff) { merge_request.merge_request_diff } + let(:merge_request) { create(:merge_request) } + let(:merge_request_diff) { merge_request.merge_request_diff } let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) } def diffs_to_hashes(diffs) @@ -70,8 +70,8 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do before do merge_request.reload_diff(true) - convert_to_yaml(start_id, merge_request_diff.commits, merge_request_diff.diffs) - convert_to_yaml(stop_id, updated_merge_request_diff.commits, updated_merge_request_diff.diffs) + convert_to_yaml(start_id, merge_request_diff.commits, diffs_to_hashes(merge_request_diff.merge_request_diff_files)) + convert_to_yaml(stop_id, updated_merge_request_diff.commits, diffs_to_hashes(updated_merge_request_diff.merge_request_diff_files)) MergeRequestDiffCommit.delete_all MergeRequestDiffFile.delete_all @@ -80,10 +80,32 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do context 'when BUFFER_ROWS is exceeded' do before do stub_const("#{described_class}::BUFFER_ROWS", 1) + + allow(Gitlab::Database).to receive(:bulk_insert).and_call_original + end + + it 'inserts commit rows in chunks of BUFFER_ROWS' do + # There are 29 commits in each diff, so we should have slices of 20 + 9 + 20 + 9. + stub_const("#{described_class}::BUFFER_ROWS", 20) + + expect(Gitlab::Database).to receive(:bulk_insert) + .with('merge_request_diff_commits', anything) + .exactly(4) + .times + .and_call_original + + subject.perform(start_id, stop_id) end - it 'updates and continues' do - expect(described_class::MergeRequestDiff).to receive(:transaction).twice + it 'inserts diff rows in chunks of DIFF_FILE_BUFFER_ROWS' do + # There are 20 files in each diff, so we should have slices of 20 + 20. + stub_const("#{described_class}::DIFF_FILE_BUFFER_ROWS", 20) + + expect(Gitlab::Database).to receive(:bulk_insert) + .with('merge_request_diff_files', anything) + .exactly(2) + .times + .and_call_original subject.perform(start_id, stop_id) end @@ -91,27 +113,87 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do context 'when BUFFER_ROWS is not exceeded' do it 'only updates once' do - expect(described_class::MergeRequestDiff).to receive(:transaction).once + expect(Gitlab::Database).to receive(:bulk_insert) + .with('merge_request_diff_commits', anything) + .once + .and_call_original + + expect(Gitlab::Database).to receive(:bulk_insert) + .with('merge_request_diff_files', anything) + .once + .and_call_original subject.perform(start_id, stop_id) end end - end - context 'when the merge request diff update fails' do - before do - allow(described_class::MergeRequestDiff) - .to receive(:update_all).and_raise(ActiveRecord::Rollback) - end + context 'when some rows were already inserted due to a previous failure' do + before do + subject.perform(start_id, stop_id) - it 'does not add any diff commits' do - expect { subject.perform(merge_request_diff.id, merge_request_diff.id) } - .not_to change { MergeRequestDiffCommit.count } + convert_to_yaml(start_id, merge_request_diff.commits, diffs_to_hashes(merge_request_diff.merge_request_diff_files)) + convert_to_yaml(stop_id, updated_merge_request_diff.commits, diffs_to_hashes(updated_merge_request_diff.merge_request_diff_files)) + end + + it 'does not raise' do + expect { subject.perform(start_id, stop_id) }.not_to raise_exception + end + + it 'logs a message' do + expect(Rails.logger).to receive(:info) + .with( + a_string_matching(described_class.name).and(matching([start_id, stop_id].inspect)) + ) + .twice + + subject.perform(start_id, stop_id) + end + + it 'ends up with the correct rows' do + expect(updated_merge_request_diff.commits.count).to eq(29) + expect(updated_merge_request_diff.raw_diffs.count).to eq(20) + end end - it 'does not add any diff files' do - expect { subject.perform(merge_request_diff.id, merge_request_diff.id) } - .not_to change { MergeRequestDiffFile.count } + context 'when the merge request diff update fails' do + let(:exception) { ActiveRecord::RecordNotFound } + + let(:perform_ignoring_exceptions) do + begin + subject.perform(start_id, stop_id) + rescue described_class::Error + end + end + + before do + allow_any_instance_of(described_class::MergeRequestDiff::ActiveRecord_Relation) + .to receive(:update_all).and_raise(exception) + end + + it 'raises an error' do + expect { subject.perform(start_id, stop_id) } + .to raise_exception(described_class::Error) + end + + it 'logs the error' do + expect(Rails.logger).to receive(:info).with( + a_string_matching(described_class.name) + .and(matching([start_id, stop_id].inspect)) + .and(matching(exception.name)) + ) + + perform_ignoring_exceptions + end + + it 'still adds diff commits' do + expect { perform_ignoring_exceptions } + .to change { MergeRequestDiffCommit.count } + end + + it 'still adds diff files' do + expect { perform_ignoring_exceptions } + .to change { MergeRequestDiffFile.count } + end end end diff --git a/spec/lib/gitlab/backup/manager_spec.rb b/spec/lib/gitlab/backup/manager_spec.rb index 8772d3d5ada..422f2af7266 100644 --- a/spec/lib/gitlab/backup/manager_spec.rb +++ b/spec/lib/gitlab/backup/manager_spec.rb @@ -26,6 +26,9 @@ describe Backup::Manager do [ '1451606400_2016_01_01_1.2.3_gitlab_backup.tar', '1451520000_2015_12_31_4.5.6_gitlab_backup.tar', + '1451520000_2015_12_31_4.5.6-pre_gitlab_backup.tar', + '1451520000_2015_12_31_4.5.6-rc1_gitlab_backup.tar', + '1451520000_2015_12_31_4.5.6-pre-ee_gitlab_backup.tar', '1451510000_2015_12_30_gitlab_backup.tar', '1450742400_2015_12_22_gitlab_backup.tar', '1449878400_gitlab_backup.tar', @@ -57,6 +60,30 @@ describe Backup::Manager do end end + context 'when no valid file is found' do + let(:files) do + [ + '14516064000_2016_01_01_1.2.3_gitlab_backup.tar', + 'foo_1451520000_2015_12_31_4.5.6_gitlab_backup.tar', + '1451520000_2015_12_31_4.5.6-foo_gitlab_backup.tar' + ] + end + + before do + allow(Gitlab.config.backup).to receive(:keep_time).and_return(1) + + subject.remove_old + end + + it 'removes no files' do + expect(FileUtils).not_to have_received(:rm) + end + + it 'prints a done message' do + expect(progress).to have_received(:puts).with('done. (0 removed)') + end + end + context 'when there are no files older than keep_time' do before do # Set to 30 days @@ -84,16 +111,22 @@ describe Backup::Manager do it 'removes matching files with a human-readable versioned timestamp' do expect(FileUtils).to have_received(:rm).with(files[1]) - end - - it 'removes matching files with a human-readable non-versioned timestamp' do expect(FileUtils).to have_received(:rm).with(files[2]) expect(FileUtils).to have_received(:rm).with(files[3]) end - it 'removes matching files without a human-readable timestamp' do + it 'removes matching files with a human-readable versioned timestamp with tagged EE' do expect(FileUtils).to have_received(:rm).with(files[4]) + end + + it 'removes matching files with a human-readable non-versioned timestamp' do expect(FileUtils).to have_received(:rm).with(files[5]) + expect(FileUtils).to have_received(:rm).with(files[6]) + end + + it 'removes matching files without a human-readable timestamp' do + expect(FileUtils).to have_received(:rm).with(files[7]) + expect(FileUtils).to have_received(:rm).with(files[8]) end it 'does not remove files that are not old enough' do @@ -101,11 +134,11 @@ describe Backup::Manager do end it 'does not remove non-matching files' do - expect(FileUtils).not_to have_received(:rm).with(files[6]) + expect(FileUtils).not_to have_received(:rm).with(files[9]) end it 'prints a done message' do - expect(progress).to have_received(:puts).with('done. (5 removed)') + expect(progress).to have_received(:puts).with('done. (8 removed)') end end @@ -121,14 +154,15 @@ describe Backup::Manager do end it 'removes the remaining expected files' do - expect(FileUtils).to have_received(:rm).with(files[2]) - expect(FileUtils).to have_received(:rm).with(files[3]) expect(FileUtils).to have_received(:rm).with(files[4]) expect(FileUtils).to have_received(:rm).with(files[5]) + expect(FileUtils).to have_received(:rm).with(files[6]) + expect(FileUtils).to have_received(:rm).with(files[7]) + expect(FileUtils).to have_received(:rm).with(files[8]) end it 'sets the correct removed count' do - expect(progress).to have_received(:puts).with('done. (4 removed)') + expect(progress).to have_received(:puts).with('done. (7 removed)') end it 'prints the error from file that could not be removed' do diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb index f8c8b83a3ac..2c7ef622c51 100644 --- a/spec/lib/gitlab/checks/force_push_spec.rb +++ b/spec/lib/gitlab/checks/force_push_spec.rb @@ -5,13 +5,13 @@ describe Gitlab::Checks::ForcePush do context "exit code checking", skip_gitaly_mock: true do it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do - allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) + allow_any_instance_of(Gitlab::Git::RevList).to receive(:popen).and_return(['normal output', 0]) expect { described_class.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error end it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do - allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1]) + allow_any_instance_of(Gitlab::Git::RevList).to receive(:popen).and_return(['error', 1]) expect { described_class.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError) end diff --git a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb new file mode 100644 index 00000000000..15eb01eb472 --- /dev/null +++ b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Policy::Kubernetes do + let(:pipeline) { create(:ci_pipeline, project: project) } + + context 'when kubernetes service is active' do + set(:project) { create(:kubernetes_project) } + + it 'is satisfied by a kubernetes pipeline' do + expect(described_class.new('active')) + .to be_satisfied_by(pipeline) + end + end + + context 'when kubernetes service is inactive' do + set(:project) { create(:project) } + + it 'is not satisfied by a pipeline without kubernetes available' do + expect(described_class.new('active')) + .not_to be_satisfied_by(pipeline) + end + end + + context 'when kubernetes policy is invalid' do + it 'raises an error' do + expect { described_class.new('unknown') } + .to raise_error(described_class::UnknownPolicyError) + end + end +end diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb new file mode 100644 index 00000000000..7211187e511 --- /dev/null +++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Policy::Refs do + describe '#satisfied_by?' do + context 'when matching ref' do + let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'master') } + + it 'is satisfied when pipeline branch matches' do + expect(described_class.new(%w[master deploy])) + .to be_satisfied_by(pipeline) + end + + it 'is not satisfied when pipeline branch does not match' do + expect(described_class.new(%w[feature fix])) + .not_to be_satisfied_by(pipeline) + end + end + + context 'when maching tags' do + context 'when pipeline runs for a tag' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'feature', tag: true) + end + + it 'is satisfied when tags matcher is specified' do + expect(described_class.new(%w[master tags])) + .to be_satisfied_by(pipeline) + end + end + + context 'when pipeline is not created for a tag' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'feature', tag: false) + end + + it 'is not satisfied when tag match is specified' do + expect(described_class.new(%w[master tags])) + .not_to be_satisfied_by(pipeline) + end + end + end + + context 'when also matching a path' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'master') + end + + it 'is satisfied when provided patch matches specified one' do + expect(described_class.new(%W[master@#{pipeline.project_full_path}])) + .to be_satisfied_by(pipeline) + end + + it 'is not satisfied when path differs' do + expect(described_class.new(%w[master@some/fork/repository])) + .not_to be_satisfied_by(pipeline) + end + end + + context 'when maching a source' do + let(:pipeline) { build_stubbed(:ci_pipeline, source: :push) } + + it 'is satisifed when provided source keyword matches' do + expect(described_class.new(%w[pushes])) + .to be_satisfied_by(pipeline) + end + + it 'is not satisfied when provided source keyword does not match' do + expect(described_class.new(%w[triggers])) + .not_to be_satisfied_by(pipeline) + end + end + + context 'when matching a ref by a regular expression' do + let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'docs-something') } + + it 'is satisfied when regexp matches pipeline ref' do + expect(described_class.new(['/docs-.*/'])) + .to be_satisfied_by(pipeline) + end + + it 'is not satisfied when regexp does not match pipeline ref' do + expect(described_class.new(['/fix-.*/'])) + .not_to be_satisfied_by(pipeline) + end + end + end +end diff --git a/spec/lib/gitlab/ci/build/policy_spec.rb b/spec/lib/gitlab/ci/build/policy_spec.rb new file mode 100644 index 00000000000..20ee3dd3e89 --- /dev/null +++ b/spec/lib/gitlab/ci/build/policy_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Policy do + let(:policy) { spy('policy specification') } + + before do + stub_const("#{described_class}::Something", policy) + end + + describe '.fabricate' do + context 'when policy exists' do + it 'fabricates and initializes relevant policy' do + specs = described_class.fabricate(something: 'some value') + + expect(specs).to be_an Array + expect(specs).to be_one + expect(policy).to have_received(:new).with('some value') + end + end + + context 'when some policies are not defined' do + it 'gracefully skips unknown policies' do + expect { described_class.fabricate(unknown: 'first') } + .to raise_error(NameError) + end + end + + context 'when passing a nil value as specs' do + it 'returns an empty array' do + specs = described_class.fabricate(nil) + + expect(specs).to be_an Array + expect(specs).to be_empty + end + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb new file mode 100644 index 00000000000..f54e2326b06 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Create do + set(:project) { create(:project) } + set(:user) { create(:user) } + + let(:pipeline) do + build(:ci_pipeline_with_one_job, project: project, + ref: 'master') + end + + let(:command) do + double('command', project: project, + current_user: user, + seeds_block: nil) + end + + let(:step) { described_class.new(pipeline, command) } + + before do + step.perform! + end + + context 'when pipeline is ready to be saved' do + it 'saves a pipeline' do + expect(pipeline).to be_persisted + end + + it 'does not break the chain' do + expect(step.break?).to be false + end + + it 'creates stages' do + expect(pipeline.reload.stages).to be_one + end + end + + context 'when pipeline has validation errors' do + let(:pipeline) do + build(:ci_pipeline, project: project, ref: nil) + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + it 'appends validation error' do + expect(pipeline.errors.to_a) + .to include /Failed to persist the pipeline/ + end + end + + context 'when there is a seed block present' do + let(:seeds) { spy('pipeline seeds') } + + let(:command) do + double('command', project: project, + current_user: user, + seeds_block: seeds) + end + + it 'executes the block' do + expect(seeds).to have_received(:call).with(pipeline) + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb new file mode 100644 index 00000000000..e165e0fac2a --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Sequence do + set(:project) { create(:project) } + set(:user) { create(:user) } + + let(:pipeline) { build_stubbed(:ci_pipeline) } + let(:command) { double('command' ) } + let(:first_step) { spy('first step') } + let(:second_step) { spy('second step') } + let(:sequence) { [first_step, second_step] } + + subject do + described_class.new(pipeline, command, sequence) + end + + context 'when one of steps breaks the chain' do + before do + allow(first_step).to receive(:break?).and_return(true) + end + + it 'does not process the second step' do + subject.build! do |pipeline, sequence| + expect(sequence).not_to be_complete + end + + expect(second_step).not_to have_received(:perform!) + end + + it 'returns a pipeline object' do + expect(subject.build!).to eq pipeline + end + end + + context 'when all chains are executed correctly' do + before do + sequence.each do |step| + allow(step).to receive(:break?).and_return(false) + end + end + + it 'iterates through entire sequence' do + subject.build! do |pipeline, sequence| + expect(sequence).to be_complete + end + + expect(first_step).to have_received(:perform!) + expect(second_step).to have_received(:perform!) + end + + it 'returns a pipeline object' do + expect(subject.build!).to eq pipeline + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb new file mode 100644 index 00000000000..32bd5de829b --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Skip do + set(:project) { create(:project) } + set(:user) { create(:user) } + set(:pipeline) { create(:ci_pipeline, project: project) } + + let(:command) do + double('command', project: project, + current_user: user, + ignore_skip_ci: false, + save_incompleted: true) + end + + let(:step) { described_class.new(pipeline, command) } + + context 'when pipeline has been skipped by a user' do + before do + allow(pipeline).to receive(:git_commit_message) + .and_return('commit message [ci skip]') + + step.perform! + end + + it 'should break the chain' do + expect(step.break?).to be true + end + + it 'skips the pipeline' do + expect(pipeline.reload).to be_skipped + end + end + + context 'when pipeline has not been skipped' do + before do + step.perform! + end + + it 'should not break the chain' do + expect(step.break?).to be false + end + + it 'should not skip a pipeline chain' do + expect(pipeline.reload).not_to be_skipped + end + end + + context 'when [ci skip] should be ignored' do + let(:command) do + double('command', project: project, + current_user: user, + ignore_skip_ci: true) + end + + it 'does not break the chain' do + step.perform! + + expect(step.break?).to be false + end + end + + context 'when pipeline should be skipped but not persisted' do + let(:command) do + double('command', project: project, + current_user: user, + ignore_skip_ci: false, + save_incompleted: false) + end + + before do + allow(pipeline).to receive(:git_commit_message) + .and_return('commit message [ci skip]') + + step.perform! + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + it 'does not skip pipeline' do + expect(pipeline.reload).not_to be_skipped + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb new file mode 100644 index 00000000000..0bbdd23f4d6 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb @@ -0,0 +1,142 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do + set(:project) { create(:project, :repository) } + set(:user) { create(:user) } + + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: ref, project: project) + end + + let(:command) do + double('command', project: project, current_user: user) + end + + let(:step) { described_class.new(pipeline, command) } + + let(:ref) { 'master' } + + context 'when users has no ability to run a pipeline' do + before do + step.perform! + end + + it 'adds an error about insufficient permissions' do + expect(pipeline.errors.to_a) + .to include /Insufficient permissions/ + end + + it 'breaks the pipeline builder chain' do + expect(step.break?).to eq true + end + end + + context 'when user has ability to create a pipeline' do + before do + project.add_developer(user) + + step.perform! + end + + it 'does not invalidate the pipeline' do + expect(pipeline).to be_valid + end + + it 'does not break the chain' do + expect(step.break?).to eq false + end + end + + describe '#allowed_to_create?' do + subject { step.allowed_to_create? } + + context 'when user is a developer' do + before do + project.add_developer(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to merge' do + let!(:protected_branch) do + create(:protected_branch, + :developers_can_merge, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :developers_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + end + + context 'when user is a master' do + before do + project.add_master(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_truthy } + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_truthy } + + context 'when no one can create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :no_one_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_falsey } + end + end + end + + context 'when owner cannot create pipeline' do + it { is_expected.to be_falsey } + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb new file mode 100644 index 00000000000..3740df88f42 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Validate::Config do + set(:project) { create(:project) } + set(:user) { create(:user) } + + let(:command) do + double('command', project: project, + current_user: user, + save_incompleted: true) + end + + let!(:step) { described_class.new(pipeline, command) } + + before do + step.perform! + end + + context 'when pipeline has no YAML configuration' do + let(:pipeline) do + build_stubbed(:ci_pipeline, project: project) + end + + it 'appends errors about missing configuration' do + expect(pipeline.errors.to_a) + .to include 'Missing .gitlab-ci.yml file' + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + end + + context 'when YAML configuration contains errors' do + let(:pipeline) do + build(:ci_pipeline, project: project, config: 'invalid YAML') + end + + it 'appends errors about YAML errors' do + expect(pipeline.errors.to_a) + .to include 'Invalid configuration format' + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + context 'when saving incomplete pipeline is allowed' do + let(:command) do + double('command', project: project, + current_user: user, + save_incompleted: true) + end + + it 'fails the pipeline' do + expect(pipeline.reload).to be_failed + end + end + + context 'when saving incomplete pipeline is not allowed' do + let(:command) do + double('command', project: project, + current_user: user, + save_incompleted: false) + end + + it 'does not drop pipeline' do + expect(pipeline).not_to be_failed + expect(pipeline).not_to be_persisted + end + end + end + + context 'when pipeline has no stages / jobs' do + let(:config) do + { rspec: { + script: 'ls', + only: ['something'] + } } + end + + let(:pipeline) do + build(:ci_pipeline, project: project, config: config) + end + + it 'appends an error about missing stages' do + expect(pipeline.errors.to_a) + .to include 'No stages / jobs for this pipeline.' + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + end + + context 'when pipeline contains configuration validation errors' do + let(:config) { { rspec: {} } } + + let(:pipeline) do + build(:ci_pipeline, project: project, config: config) + end + + it 'appends configuration validation errors to pipeline errors' do + expect(pipeline.errors.to_a) + .to include "jobs:rspec config can't be blank" + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + end + + context 'when pipeline is correct and complete' do + let(:pipeline) do + build(:ci_pipeline_with_one_job, project: project) + end + + it 'does not invalidate the pipeline' do + expect(pipeline).to be_valid + end + + it 'does not break the chain' do + expect(step.break?).to be false + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb new file mode 100644 index 00000000000..bb356efe9ad --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do + set(:project) { create(:project, :repository) } + set(:user) { create(:user) } + + let(:command) do + double('command', project: project, current_user: user) + end + + let!(:step) { described_class.new(pipeline, command) } + + before do + step.perform! + end + + context 'when pipeline ref and sha exists' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'master', sha: '123', project: project) + end + + it 'does not break the chain' do + expect(step.break?).to be false + end + + it 'does not append pipeline errors' do + expect(pipeline.errors).to be_empty + end + end + + context 'when pipeline ref does not exist' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'something', project: project) + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + it 'adds an error about missing ref' do + expect(pipeline.errors.to_a) + .to include 'Reference not found' + end + end + + context 'when pipeline does not have SHA set' do + let(:pipeline) do + build_stubbed(:ci_pipeline, ref: 'master', sha: nil, project: project) + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + it 'adds an error about missing SHA' do + expect(pipeline.errors.to_a) + .to include 'Commit not found' + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline_duration_spec.rb b/spec/lib/gitlab/ci/pipeline/duration_spec.rb index b26728a843c..7c9836e2da6 100644 --- a/spec/lib/gitlab/ci/pipeline_duration_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/duration_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::PipelineDuration do +describe Gitlab::Ci::Pipeline::Duration do let(:calculated_duration) { calculate(data) } shared_examples 'calculating duration' do @@ -107,9 +107,9 @@ describe Gitlab::Ci::PipelineDuration do def calculate(data) periods = data.shuffle.map do |(first, last)| - Gitlab::Ci::PipelineDuration::Period.new(first, last) + described_class::Period.new(first, last) end - Gitlab::Ci::PipelineDuration.from_periods(periods.sort_by(&:first)) + described_class.from_periods(periods.sort_by(&:first)) end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 2278230f338..d72f8553f55 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' module Gitlab module Ci describe YamlProcessor, :lib do - subject { described_class.new(config, path) } - let(:path) { 'path' } + subject { described_class.new(config) } describe 'our current .gitlab-ci.yml' do let(:config) { File.read("#{Rails.root}/.gitlab-ci.yml") } @@ -17,7 +16,7 @@ module Gitlab end describe '#build_attributes' do - subject { described_class.new(config, path).build_attributes(:rspec) } + subject { described_class.new(config).build_attributes(:rspec) } describe 'coverage entry' do describe 'code coverage regexp' do @@ -167,8 +166,6 @@ module Gitlab end context 'when kubernetes policy is specified' do - let(:pipeline) { create(:ci_empty_pipeline) } - let(:config) do YAML.dump( spinach: { stage: 'test', script: 'spinach' }, @@ -204,7 +201,7 @@ module Gitlab end end - describe "#builds_for_stage_and_ref" do + describe "#pipeline_stage_builds" do let(:type) { 'test' } it "returns builds if no branch specified" do @@ -213,10 +210,10 @@ module Gitlab rspec: { script: "rspec" } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({ + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -241,9 +238,9 @@ module Gitlab rspec: { script: "rspec", only: ["deploy"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0) end it "does not return builds if only has regexp with another branch" do @@ -252,9 +249,9 @@ module Gitlab rspec: { script: "rspec", only: ["/^deploy$/"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0) end it "returns builds if only has specified this branch" do @@ -263,9 +260,9 @@ module Gitlab rspec: { script: "rspec", only: ["master"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1) end it "returns builds if only has a list of branches including specified" do @@ -274,9 +271,9 @@ module Gitlab rspec: { script: "rspec", type: type, only: %w(master deploy) } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1) end it "returns builds if only has a branches keyword specified" do @@ -285,9 +282,9 @@ module Gitlab rspec: { script: "rspec", type: type, only: ["branches"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1) end it "does not return builds if only has a tags keyword" do @@ -296,9 +293,9 @@ module Gitlab rspec: { script: "rspec", type: type, only: ["tags"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0) end it "returns builds if only has special keywords specified and source matches" do @@ -315,9 +312,9 @@ module Gitlab rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1) end end @@ -335,21 +332,27 @@ module Gitlab rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0) end end it "returns builds if only has current repository path" do + seed_pipeline = pipeline(ref: 'deploy') + config = YAML.dump({ before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["branches@path"] } + rspec: { + script: "rspec", + type: type, + only: ["branches@#{seed_pipeline.project_full_path}"] + } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(1) end it "does not return builds if only has different repository path" do @@ -358,9 +361,9 @@ module Gitlab rspec: { script: "rspec", type: type, only: ["branches@fork"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0) end it "returns build only for specified type" do @@ -371,11 +374,11 @@ module Gitlab production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, 'fork') + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) - expect(config_processor.builds_for_stage_and_ref("test", "deploy").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(1) + expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "deploy")).size).to eq(2) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "deploy")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "master")).size).to eq(1) end context 'for invalid value' do @@ -418,9 +421,9 @@ module Gitlab rspec: { script: "rspec", except: ["deploy"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1) end it "returns builds if except has regexp with another branch" do @@ -429,9 +432,9 @@ module Gitlab rspec: { script: "rspec", except: ["/^deploy$/"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1) end it "does not return builds if except has specified this branch" do @@ -440,9 +443,9 @@ module Gitlab rspec: { script: "rspec", except: ["master"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0) end it "does not return builds if except has a list of branches including specified" do @@ -451,9 +454,9 @@ module Gitlab rspec: { script: "rspec", type: type, except: %w(master deploy) } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0) end it "does not return builds if except has a branches keyword specified" do @@ -462,9 +465,9 @@ module Gitlab rspec: { script: "rspec", type: type, except: ["branches"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0) end it "returns builds if except has a tags keyword" do @@ -473,9 +476,9 @@ module Gitlab rspec: { script: "rspec", type: type, except: ["tags"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1) end it "does not return builds if except has special keywords specified and source matches" do @@ -492,9 +495,9 @@ module Gitlab rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0) end end @@ -512,21 +515,27 @@ module Gitlab rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1) end end it "does not return builds if except has current repository path" do + seed_pipeline = pipeline(ref: 'deploy') + config = YAML.dump({ before_script: ["pwd"], - rspec: { script: "rspec", type: type, except: ["branches@path"] } + rspec: { + script: "rspec", + type: type, + except: ["branches@#{seed_pipeline.project_full_path}"] + } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(0) end it "returns builds if except has different repository path" do @@ -535,24 +544,28 @@ module Gitlab rspec: { script: "rspec", type: type, except: ["branches@fork"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1) end it "returns build except specified type" do + master_pipeline = pipeline(ref: 'master') + test_pipeline = pipeline(ref: 'test') + deploy_pipeline = pipeline(ref: 'deploy') + config = YAML.dump({ before_script: ["pwd"], - rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@fork"] }, + rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@#{test_pipeline.project_full_path}"] }, staging: { script: "deploy", type: "deploy", except: ["master"] }, - production: { script: "deploy", type: "deploy", except: ["master@fork"] } + production: { script: "deploy", type: "deploy", except: ["master@#{master_pipeline.project_full_path}"] } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, 'fork') + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) - expect(config_processor.builds_for_stage_and_ref("test", "test").size).to eq(0) - expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(0) + expect(config_processor.pipeline_stage_builds("deploy", deploy_pipeline).size).to eq(2) + expect(config_processor.pipeline_stage_builds("test", test_pipeline).size).to eq(0) + expect(config_processor.pipeline_stage_builds("deploy", master_pipeline).size).to eq(0) end context 'for invalid value' do @@ -591,9 +604,9 @@ module Gitlab describe "Scripts handling" do let(:config_data) { YAML.dump(config) } - let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data, path) } + let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data) } - subject { config_processor.builds_for_stage_and_ref("test", "master").first } + subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first } describe "before_script" do context "in global context" do @@ -674,10 +687,10 @@ module Gitlab before_script: ["pwd"], rspec: { script: "rspec" } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -709,10 +722,10 @@ module Gitlab command: ["/usr/local/bin/init", "run"] }, "docker:dind"], script: "rspec" } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -742,10 +755,10 @@ module Gitlab before_script: ["pwd"], rspec: { script: "rspec" } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -771,10 +784,10 @@ module Gitlab before_script: ["pwd"], rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -797,7 +810,7 @@ module Gitlab end describe 'Variables' do - let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config), path) } + let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } subject { config_processor.builds.first[:yaml_variables] } @@ -918,9 +931,9 @@ module Gitlab rspec: { script: "rspec", when: when_state } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - builds = config_processor.builds_for_stage_and_ref("test", "master") + builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master")) expect(builds.size).to eq(1) expect(builds.first[:when]).to eq(when_state) end @@ -951,8 +964,8 @@ module Gitlab config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( paths: ["logs/", "binaries/"], untracked: true, key: 'key', @@ -970,8 +983,8 @@ module Gitlab config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( paths: ["logs/", "binaries/"], untracked: true, key: 'key', @@ -990,8 +1003,8 @@ module Gitlab config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( paths: ["test/"], untracked: false, key: 'local', @@ -1019,8 +1032,8 @@ module Gitlab config_processor = Gitlab::Ci::YamlProcessor.new(config) - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) + expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ stage: "test", stage_idx: 1, name: "rspec", @@ -1055,9 +1068,9 @@ module Gitlab } }) - config_processor = Gitlab::Ci::YamlProcessor.new(config, path) + config_processor = Gitlab::Ci::YamlProcessor.new(config) - builds = config_processor.builds_for_stage_and_ref("test", "master") + builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master")) expect(builds.size).to eq(1) expect(builds.first[:options][:artifacts][:when]).to eq(when_state) end @@ -1072,7 +1085,7 @@ module Gitlab end let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } - let(:builds) { processor.builds_for_stage_and_ref('deploy', 'master') } + let(:builds) { processor.pipeline_stage_builds('deploy', pipeline(ref: 'master')) } context 'when a production environment is specified' do let(:environment) { 'production' } @@ -1229,7 +1242,7 @@ module Gitlab describe "Hidden jobs" do let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } - subject { config_processor.builds_for_stage_and_ref("test", "master") } + subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")) } shared_examples 'hidden_job_handling' do it "doesn't create jobs that start with dot" do @@ -1277,7 +1290,7 @@ module Gitlab describe "YAML Alias/Anchor" do let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } - subject { config_processor.builds_for_stage_and_ref("build", "master") } + subject { config_processor.pipeline_stage_builds("build", pipeline(ref: "master")) } shared_examples 'job_templates_handling' do it "is correctly supported for jobs" do @@ -1377,182 +1390,182 @@ EOT it "returns errors if tags parameter is invalid" do config = YAML.dump({ rspec: { script: "test", tags: "mysql" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec tags should be an array of strings") end it "returns errors if before_script parameter is invalid" do config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array of strings") end it "returns errors if job before_script parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array of strings") end it "returns errors if after_script parameter is invalid" do config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array of strings") end it "returns errors if job after_script parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array of strings") end it "returns errors if image parameter is invalid" do config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "image config should be a hash or a string") end it "returns errors if job name is blank" do config = YAML.dump({ '' => { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:job name can't be blank") end it "returns errors if job name is non-string" do config = YAML.dump({ 10 => { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:10 name should be a symbol") end it "returns errors if job image parameter is invalid" do config = YAML.dump({ rspec: { script: "test", image: ["test"] } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string") end it "returns errors if services parameter is not an array" do config = YAML.dump({ services: "test", rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "services config should be a array") end it "returns errors if services parameter is not an array of strings" do config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string") end it "returns errors if job services parameter is not an array" do config = YAML.dump({ rspec: { script: "test", services: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:services config should be a array") end it "returns errors if job services parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string") end it "returns error if job configuration is invalid" do config = YAML.dump({ extra: "bundle update" }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra config should be a hash") end it "returns errors if services configuration is not correct" do config = YAML.dump({ extra: { script: 'rspec', services: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra:services config should be a array") end it "returns errors if there are no jobs defined" do config = YAML.dump({ before_script: ["bundle update"] }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job") end it "returns errors if there are no visible jobs defined" do config = YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job") end it "returns errors if job allow_failure parameter is not an boolean" do config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec allow failure should be a boolean value") end it "returns errors if job stage is not a string" do config = YAML.dump({ rspec: { script: "test", type: 1 } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:type config should be a string") end it "returns errors if job stage is not a pre-defined stage" do config = YAML.dump({ rspec: { script: "test", type: "acceptance" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") end it "returns errors if job stage is not a defined stage" do config = YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test") end it "returns errors if stages is not an array" do config = YAML.dump({ stages: "test", rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings") end it "returns errors if stages is not an array of strings" do config = YAML.dump({ stages: [true, "test"], rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings") end it "returns errors if variables is not a map" do config = YAML.dump({ variables: "test", rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs") end it "returns errors if variables is not a map of key-value strings" do config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs") end it "returns errors if job when is not on_success, on_failure or always" do config = YAML.dump({ rspec: { script: "test", when: 1 } }) expect do - Gitlab::Ci::YamlProcessor.new(config, path) + Gitlab::Ci::YamlProcessor.new(config) end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always or manual") end @@ -1694,6 +1707,10 @@ EOT end end end + + def pipeline(**attributes) + build_stubbed(:ci_empty_pipeline, **attributes) + end end end end diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 15012495247..9e528392756 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -347,10 +347,10 @@ describe Gitlab::ClosingIssueExtractor do end it "fetches cross-project URL references" do - message = "Closes #{urls.project_issue_url(issue2.project, issue2)} and #{reference}" + message = "Closes #{urls.project_issue_url(issue2.project, issue2)}, #{reference} and #{urls.project_issue_url(other_issue.project, other_issue)}" expect(subject.closed_by_message(message)) - .to match_array([issue, issue2]) + .to match_array([issue, issue2, other_issue]) end it "ignores invalid cross-project URL references" do diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb index c73708d90a8..f9bfb4c469e 100644 --- a/spec/lib/gitlab/diff/diff_refs_spec.rb +++ b/spec/lib/gitlab/diff/diff_refs_spec.rb @@ -3,6 +3,61 @@ require 'spec_helper' describe Gitlab::Diff::DiffRefs do let(:project) { create(:project, :repository) } + describe '#==' do + let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } + subject { commit.diff_refs } + + context 'when shas are missing' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: nil) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when shas are equal' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: subject.head_sha) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when shas are unequal' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: subject.head_sha.reverse) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when shas are truncated' do + context 'when sha prefixes are too short' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 4], start_sha: subject.start_sha[0, 4], head_sha: subject.head_sha[0, 4]) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when sha prefixes are equal' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 10], start_sha: subject.start_sha[0, 10], head_sha: subject.head_sha[0, 10]) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when sha prefixes are unequal' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 10], start_sha: subject.start_sha[0, 10], head_sha: subject.head_sha[0, 10].reverse) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + end + end + describe '#compare_in' do context 'with diff refs for the initial commit' do let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index d4a2a852c12..7798736a4dc 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -429,6 +429,44 @@ describe Gitlab::Diff::Position do end end + describe '#==' do + let(:commit) { project.commit("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") } + + subject do + described_class.new( + old_path: "files/ruby/popen.rb", + new_path: "files/ruby/popen.rb", + old_line: nil, + new_line: 14, + diff_refs: commit.diff_refs + ) + end + + context 'when positions are equal' do + let(:other) { described_class.new(subject.to_h) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when positions are equal, except for truncated shas' do + let(:other) { described_class.new(subject.to_h.merge(start_sha: subject.start_sha[0, 10])) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when positions are unequal' do + let(:other) { described_class.new(subject.to_h.merge(start_sha: subject.start_sha.reverse)) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + end + describe "#to_json" do let(:hash) do { diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index a3d323fe28a..7dc06c90078 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -1,11 +1,14 @@ require 'spec_helper' describe Gitlab::Gfm::ReferenceRewriter do - let(:text) { 'some text' } - let(:old_project) { create(:project, name: 'old-project') } - let(:new_project) { create(:project, name: 'new-project') } + let(:group) { create(:group) } + let(:old_project) { create(:project, name: 'old-project', group: group) } + let(:new_project) { create(:project, name: 'new-project', group: group) } let(:user) { create(:user) } + let(:old_project_ref) { old_project.to_reference(new_project) } + let(:text) { 'some text' } + before do old_project.team << [user, :reporter] end @@ -39,7 +42,7 @@ describe Gitlab::Gfm::ReferenceRewriter do it { is_expected.not_to include merge_request.to_reference(new_project) } end - context 'description ambigous elements' do + context 'rewrite ambigous references' do context 'url' do let(:url) { 'http://gitlab.com/#1' } let(:text) { "This references #1, but not #{url}" } @@ -66,23 +69,21 @@ describe Gitlab::Gfm::ReferenceRewriter do context 'description with project labels' do let!(:label) { create(:label, id: 123, name: 'test', project: old_project) } - let(:project_ref) { old_project.to_reference(new_project) } context 'label referenced by id' do let(:text) { '#1 and ~123' } - it { is_expected.to eq %Q{#{project_ref}#1 and #{project_ref}~123} } + it { is_expected.to eq %Q{#{old_project_ref}#1 and #{old_project_ref}~123} } end context 'label referenced by text' do let(:text) { '#1 and ~"test"' } - it { is_expected.to eq %Q{#{project_ref}#1 and #{project_ref}~123} } + it { is_expected.to eq %Q{#{old_project_ref}#1 and #{old_project_ref}~123} } end end context 'description with group labels' do let(:old_group) { create(:group) } let!(:group_label) { create(:group_label, id: 321, name: 'group label', group: old_group) } - let(:project_ref) { old_project.to_reference(new_project) } before do old_project.update(namespace: old_group) @@ -90,21 +91,53 @@ describe Gitlab::Gfm::ReferenceRewriter do context 'label referenced by id' do let(:text) { '#1 and ~321' } - it { is_expected.to eq %Q{#{project_ref}#1 and #{project_ref}~321} } + it { is_expected.to eq %Q{#{old_project_ref}#1 and #{old_project_ref}~321} } end context 'label referenced by text' do let(:text) { '#1 and ~"group label"' } - it { is_expected.to eq %Q{#{project_ref}#1 and #{project_ref}~321} } + it { is_expected.to eq %Q{#{old_project_ref}#1 and #{old_project_ref}~321} } end end end + end + + context 'reference contains project milestone' do + let!(:milestone) do + create(:milestone, title: '9.0', project: old_project) + end + + let(:text) { 'milestone: %"9.0"' } + + it { is_expected.to eq %Q[milestone: #{old_project_ref}%"9.0"] } + end + + context 'when referring to group milestone' do + let!(:milestone) do + create(:milestone, title: '10.0', group: group) + end + + let(:text) { 'milestone %"10.0"' } + + it { is_expected.to eq text } + end + + context 'when referable has a nil reference' do + before do + create(:milestone, title: '9.0', project: old_project) + + allow_any_instance_of(Milestone) + .to receive(:to_reference) + .and_return(nil) + end - context 'reference contains milestone' do - let(:milestone) { create(:milestone) } - let(:text) { "milestone ref: #{milestone.to_reference}" } + let(:text) { 'milestone: %"9.0"' } - it { is_expected.to eq text } + it 'raises an error that should be fixed' do + expect { subject }.to raise_error( + described_class::RewriteError, + 'Unspecified reference detected for Milestone' + ) end end end diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 66ba00acb7d..f3945e748ab 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -119,10 +119,13 @@ describe Gitlab::Git::Blob, seed_helper: true do shared_examples 'finding blobs by ID' do let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) } + let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) } + it { expect(raw_blob.id).to eq(SeedRepo::RubyBlob::ID) } it { expect(raw_blob.data[0..10]).to eq("require \'fi") } it { expect(raw_blob.size).to eq(669) } it { expect(raw_blob.truncated?).to be_falsey } + it { expect(bad_blob).to be_nil } context 'large file' do it 'limits the size of a large file' do diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 46e968cc398..a3dff6d0d4b 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -181,7 +181,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end end - describe '.where' do + shared_examples '.where' do context 'path is empty string' do subject do commits = described_class.where( @@ -279,6 +279,14 @@ describe Gitlab::Git::Commit, seed_helper: true do end end + describe '.where with gitaly' do + it_should_behave_like '.where' + end + + describe '.where without gitaly', skip_gitaly_mock: true do + it_should_behave_like '.where' + end + describe '.between' do subject do commits = described_class.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID) diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb index ea3e4680b1d..0ff4f3bd105 100644 --- a/spec/lib/gitlab/git/hook_spec.rb +++ b/spec/lib/gitlab/git/hook_spec.rb @@ -28,6 +28,7 @@ describe Gitlab::Git::Hook do f.write(<<-HOOK) echo 'regular message from the hook' echo 'error message from the hook' 1>&2 + echo 'error message from the hook line 2' 1>&2 exit 1 HOOK end @@ -73,7 +74,7 @@ describe Gitlab::Git::Hook do status, errors = hook.trigger(gl_id, blank, blank, ref) expect(status).to be false - expect(errors).to eq("error message from the hook\n") + expect(errors).to eq("error message from the hook<br>error message from the hook line 2<br>") end end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 556a148c3bc..a0482e30a33 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -389,6 +389,40 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#has_local_branches?' do + shared_examples 'check for local branches' do + it { expect(repository.has_local_branches?).to eq(true) } + + context 'mutable' do + let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } + + after do + ensure_seeds + end + + it 'returns false when there are no branches' do + # Sanity check + expect(repository.has_local_branches?).to eq(true) + + FileUtils.rm_rf(File.join(repository.path, 'packed-refs')) + heads_dir = File.join(repository.path, 'refs/heads') + FileUtils.rm_rf(heads_dir) + FileUtils.mkdir_p(heads_dir) + + expect(repository.has_local_branches?).to eq(false) + end + end + end + + context 'with gitaly' do + it_behaves_like 'check for local branches' + end + + context 'without gitaly', skip_gitaly_mock: true do + it_behaves_like 'check for local branches' + end + end + describe "#delete_branch" do shared_examples "deleting a branch" do let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } @@ -481,7 +515,7 @@ describe Gitlab::Git::Repository, seed_helper: true do end it 'raises an error if it failed' do - expect(Gitlab::Popen).to receive(:popen).and_return(['Error', 1]) + expect(@repo).to receive(:popen).and_return(['Error', 1]) expect do @repo.delete_refs('refs/heads/fix') @@ -1332,6 +1366,84 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#with_repo_branch_commit' do + context 'when comparing with the same repository' do + let(:start_repository) { repository } + + context 'when the branch exists' do + let(:start_branch_name) { 'master' } + + it 'yields the commit' do + expect { |b| repository.with_repo_branch_commit(start_repository, start_branch_name, &b) } + .to yield_with_args(an_instance_of(Gitlab::Git::Commit)) + end + end + + context 'when the branch does not exist' do + let(:start_branch_name) { 'definitely-not-master' } + + it 'yields nil' do + expect { |b| repository.with_repo_branch_commit(start_repository, start_branch_name, &b) } + .to yield_with_args(nil) + end + end + end + + context 'when comparing with another repository' do + let(:start_repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } + + context 'when the branch exists' do + let(:start_branch_name) { 'master' } + + it 'yields the commit' do + expect { |b| repository.with_repo_branch_commit(start_repository, start_branch_name, &b) } + .to yield_with_args(an_instance_of(Gitlab::Git::Commit)) + end + end + + context 'when the branch does not exist' do + let(:start_branch_name) { 'definitely-not-master' } + + it 'yields nil' do + expect { |b| repository.with_repo_branch_commit(start_repository, start_branch_name, &b) } + .to yield_with_args(nil) + end + end + end + end + + describe '#fetch_source_branch' do + let(:local_ref) { 'refs/merge-requests/1/head' } + + context 'when the branch exists' do + let(:source_branch) { 'master' } + + it 'writes the ref' do + expect(repository).to receive(:write_ref).with(local_ref, /\h{40}/) + + repository.fetch_source_branch(repository, source_branch, local_ref) + end + + it 'returns true' do + expect(repository.fetch_source_branch(repository, source_branch, local_ref)).to eq(true) + end + end + + context 'when the branch does not exist' do + let(:source_branch) { 'definitely-not-master' } + + it 'does not write the ref' do + expect(repository).not_to receive(:write_ref) + + repository.fetch_source_branch(repository, source_branch, local_ref) + end + + it 'returns false' do + expect(repository.fetch_source_branch(repository, source_branch, local_ref)).to eq(false) + end + end + end + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) source_branch = repository.branches.find { |branch| branch.name == source_branch_name } rugged = repository.rugged diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index b051a088171..c0eac98d718 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -14,7 +14,7 @@ describe Gitlab::Git::RevList do let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } it 'calls out to `popen`' do - expect(Gitlab::Popen).to receive(:popen).with([ + expect(rev_list).to receive(:popen).with([ Gitlab.config.git.bin_path, "--git-dir=#{project.repository.path_to_repo}", 'rev-list', @@ -36,7 +36,7 @@ describe Gitlab::Git::RevList do let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } it 'calls out to `popen`' do - expect(Gitlab::Popen).to receive(:popen).with([ + expect(rev_list).to receive(:popen).with([ Gitlab.config.git.bin_path, "--git-dir=#{project.repository.path_to_repo}", 'rev-list', diff --git a/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb index c86353abb7c..98cf7966dad 100644 --- a/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb +++ b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state: true, broken_storage: true do let(:storage_name) { 'default' } - let(:circuit_breaker) { described_class.new(storage_name) } + let(:circuit_breaker) { described_class.new(storage_name, hostname) } let(:hostname) { Gitlab::Environment.hostname } let(:cache_key) { "storage_accessible:#{storage_name}:#{hostname}" } @@ -22,7 +22,8 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state: 'failure_wait_time' => 30, 'failure_reset_time' => 1800, 'storage_timeout' => 5 - } + }, + 'nopath' => { 'path' => nil } ) end @@ -59,6 +60,14 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state: expect(breaker).to be_a(described_class) expect(described_class.for_storage('default')).to eq(breaker) end + + it 'returns a broken circuit breaker for an unknown storage' do + expect(described_class.for_storage('unknown').circuit_broken?).to be_truthy + end + + it 'returns a broken circuit breaker when the path is not set' do + expect(described_class.for_storage('nopath').circuit_broken?).to be_truthy + end end describe '#initialize' do diff --git a/spec/lib/gitlab/git/storage/null_circuit_breaker_spec.rb b/spec/lib/gitlab/git/storage/null_circuit_breaker_spec.rb new file mode 100644 index 00000000000..0e645008c88 --- /dev/null +++ b/spec/lib/gitlab/git/storage/null_circuit_breaker_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +describe Gitlab::Git::Storage::NullCircuitBreaker do + let(:storage) { 'default' } + let(:hostname) { 'localhost' } + let(:error) { nil } + + subject(:breaker) { described_class.new(storage, hostname, error: error) } + + context 'with an error' do + let(:error) { Gitlab::Git::Storage::Misconfiguration.new('error') } + + describe '#perform' do + it { expect { breaker.perform { 'ok' } }.to raise_error(error) } + end + + describe '#circuit_broken?' do + it { expect(breaker.circuit_broken?).to be_truthy } + end + + describe '#last_failure' do + it { Timecop.freeze { expect(breaker.last_failure).to eq(Time.now) } } + end + + describe '#failure_count' do + it { expect(breaker.failure_count).to eq(breaker.failure_count_threshold) } + end + + describe '#failure_info' do + it { Timecop.freeze { expect(breaker.failure_info).to eq(Gitlab::Git::Storage::CircuitBreaker::FailureInfo.new(Time.now, breaker.failure_count_threshold)) } } + end + end + + context 'not broken' do + describe '#perform' do + it { expect(breaker.perform { 'ok' }).to eq('ok') } + end + + describe '#circuit_broken?' do + it { expect(breaker.circuit_broken?).to be_falsy } + end + + describe '#last_failure' do + it { expect(breaker.last_failure).to be_nil } + end + + describe '#failure_count' do + it { expect(breaker.failure_count).to eq(0) } + end + + describe '#failure_info' do + it { expect(breaker.failure_info).to eq(Gitlab::Git::Storage::CircuitBreaker::FailureInfo.new(nil, 0)) } + end + end + + describe '#failure_count_threshold' do + it { expect(breaker.failure_count_threshold).to eq(1) } + end + + it 'implements the CircuitBreaker interface' do + ours = described_class.public_instance_methods + theirs = Gitlab::Git::Storage::CircuitBreaker.public_instance_methods + + # These methods are not part of the public API, but are public to allow the + # CircuitBreaker specs to operate. They should be made private over time. + exceptions = %i[ + cache_key + check_storage_accessible! + no_failures? + storage_available? + track_storage_accessible + track_storage_inaccessible + ] + + expect(theirs - ours).to contain_exactly(*exceptions) + end +end diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index ec3abcb0953..1ef3e2e3a5d 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -51,6 +51,10 @@ describe Gitlab::GitalyClient::CommitService do expect(ret).to be_kind_of(Gitlab::GitalyClient::DiffStitcher) end + + it 'encodes paths correctly' do + expect { client.diff_from_parent(commit, paths: ['encoding/test.txt', 'encoding/ใในใ.txt']) }.not_to raise_error + end end describe '#commit_deltas' do diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index a9b861fcff2..9a84d6e6a67 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -38,6 +38,130 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do end end + describe 'allow_n_plus_1_calls' do + context 'when RequestStore is enabled', :request_store do + it 'returns the result of the allow_n_plus_1_calls block' do + expect(described_class.allow_n_plus_1_calls { "result" }).to eq("result") + end + end + + context 'when RequestStore is not active' do + it 'returns the result of the allow_n_plus_1_calls block' do + expect(described_class.allow_n_plus_1_calls { "something" }).to eq("something") + end + end + end + + describe 'enforce_gitaly_request_limits?' do + def call_gitaly(count = 1) + (1..count).each do + described_class.enforce_gitaly_request_limits(:test) + end + end + + context 'when RequestStore is enabled', :request_store do + it 'allows up the maximum number of allowed calls' do + expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS) }.not_to raise_error + end + + context 'when the maximum number of calls has been reached' do + before do + call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS) + end + + it 'fails on the next call' do + expect { call_gitaly(1) }.to raise_error(Gitlab::GitalyClient::TooManyInvocationsError) + end + end + + it 'allows the maximum number of calls to be exceeded within an allow_n_plus_1_calls block' do + expect do + described_class.allow_n_plus_1_calls do + call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) + end + end.not_to raise_error + end + + context 'when the maximum number of calls has been reached within an allow_n_plus_1_calls block' do + before do + described_class.allow_n_plus_1_calls do + call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS) + end + end + + it 'allows up to the maximum number of calls outside of an allow_n_plus_1_calls block' do + expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS) }.not_to raise_error + end + + it 'does not allow the maximum number of calls to be exceeded outside of an allow_n_plus_1_calls block' do + expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) }.to raise_error(Gitlab::GitalyClient::TooManyInvocationsError) + end + end + end + + context 'when RequestStore is not active' do + it 'does not raise errors when the maximum number of allowed calls is exceeded' do + expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 2) }.not_to raise_error + end + + it 'does not fail when the maximum number of calls is exceeded within an allow_n_plus_1_calls block' do + expect do + described_class.allow_n_plus_1_calls do + call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) + end + end.not_to raise_error + end + end + end + + describe 'get_request_count' do + context 'when RequestStore is enabled', :request_store do + context 'when enforce_gitaly_request_limits is called outside of allow_n_plus_1_calls blocks' do + before do + described_class.enforce_gitaly_request_limits(:call) + end + + it 'counts gitaly calls' do + expect(described_class.get_request_count).to eq(1) + end + end + + context 'when enforce_gitaly_request_limits is called inside and outside of allow_n_plus_1_calls blocks' do + before do + described_class.enforce_gitaly_request_limits(:call) + described_class.allow_n_plus_1_calls do + described_class.enforce_gitaly_request_limits(:call) + end + end + + it 'counts gitaly calls' do + expect(described_class.get_request_count).to eq(2) + end + end + + context 'when reset_counts is called' do + before do + described_class.enforce_gitaly_request_limits(:call) + described_class.reset_counts + end + + it 'resets counts' do + expect(described_class.get_request_count).to eq(0) + end + end + end + + context 'when RequestStore is not active' do + before do + described_class.enforce_gitaly_request_limits(:call) + end + + it 'returns zero' do + expect(described_class.get_request_count).to eq(0) + end + end + end + describe 'feature_enabled?' do let(:feature_name) { 'my_feature' } let(:real_feature_name) { "gitaly_#{feature_name}" } diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb index f5c9680bf59..73dd236a5c6 100644 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do let(:metric_class) { Gitlab::HealthChecks::Metric } let(:result_class) { Gitlab::HealthChecks::Result } - let(:repository_storages) { [:default] } + let(:repository_storages) { ['default'] } let(:tmp_dir) { Dir.mktmpdir } let(:storages_paths) do @@ -64,7 +64,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do allow(described_class).to receive(:storage_circuitbreaker_test) { true } end - it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: :default)) } + it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: 'default')) } end context 'storage points to directory that has both read and write rights' do @@ -72,7 +72,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do FileUtils.chmod_R(0755, tmp_dir) end - it { is_expected.to include(result_class.new(true, nil, shard: :default)) } + it { is_expected.to include(result_class.new(true, nil, shard: 'default')) } it 'cleans up files used for testing' do expect(described_class).to receive(:storage_write_test).with(any_args).and_call_original @@ -85,7 +85,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do allow(described_class).to receive(:storage_read_test).with(any_args).and_return(false) end - it { is_expected.to include(result_class.new(false, 'cannot read from storage', shard: :default)) } + it { is_expected.to include(result_class.new(false, 'cannot read from storage', shard: 'default')) } end context 'write test fails' do @@ -93,7 +93,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do allow(described_class).to receive(:storage_write_test).with(any_args).and_return(false) end - it { is_expected.to include(result_class.new(false, 'cannot write to storage', shard: :default)) } + it { is_expected.to include(result_class.new(false, 'cannot write to storage', shard: 'default')) } end end end @@ -109,7 +109,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do it 'provides metrics' do metrics = described_class.metrics - expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to all(have_attributes(labels: { shard: 'default' })) expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) @@ -128,7 +128,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do it 'provides metrics' do metrics = described_class.metrics - expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to all(have_attributes(labels: { shard: 'default' })) expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 1)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 1)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 1)) @@ -156,14 +156,14 @@ describe Gitlab::HealthChecks::FsShardsCheck do describe '#readiness' do subject { described_class.readiness } - it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: :default)) } + it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: 'default')) } end describe '#metrics' do it 'provides metrics' do metrics = described_class.metrics - expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to all(have_attributes(labels: { shard: 'default' })) expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index c7930378240..be11647415e 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -48,14 +48,35 @@ describe Gitlab::Shell do end end - describe '#add_key' do - it 'removes trailing garbage' do - allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path) - expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with( - [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar'] - ) - - gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') + describe 'projects commands' do + let(:gitlab_shell_path) { File.expand_path('tmp/tests/gitlab-shell') } + let(:projects_path) { File.join(gitlab_shell_path, 'bin/gitlab-projects') } + let(:gitlab_shell_hooks_path) { File.join(gitlab_shell_path, 'hooks') } + + before do + allow(Gitlab.config.gitlab_shell).to receive(:path).and_return(gitlab_shell_path) + allow(Gitlab.config.gitlab_shell).to receive(:hooks_path).and_return(gitlab_shell_hooks_path) + allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800) + end + + describe '#mv_repository' do + it 'executes the command' do + expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with( + [projects_path, 'mv-project', 'storage/path', 'project/path.git', 'new/path.git'] + ) + gitlab_shell.mv_repository('storage/path', 'project/path', 'new/path') + end + end + + describe '#add_key' do + it 'removes trailing garbage' do + allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path) + expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with( + [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar'] + ) + + gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') + end end end @@ -105,30 +126,42 @@ describe Gitlab::Shell do end describe '#add_repository' do - it 'creates a repository' do - created_path = File.join(TestEnv.repos_path, 'project', 'path.git') - hooks_path = File.join(created_path, 'hooks') + shared_examples '#add_repository' do + let(:repository_storage) { 'default' } + let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] } + let(:repo_name) { 'project/path' } + let(:created_path) { File.join(repository_storage_path, repo_name + '.git') } - begin - result = gitlab_shell.add_repository(TestEnv.repos_path, 'project/path') - - repo_stat = File.stat(created_path) rescue nil - hooks_stat = File.lstat(hooks_path) rescue nil - hooks_dir = File.realpath(hooks_path) - ensure + after do FileUtils.rm_rf(created_path) end - expect(result).to be_truthy - expect(repo_stat.mode & 0o777).to eq(0o770) - expect(hooks_stat.symlink?).to be_truthy - expect(hooks_dir).to eq(gitlab_shell_hooks_path) + it 'creates a repository' do + expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_truthy + + expect(File.stat(created_path).mode & 0o777).to eq(0o770) + + hooks_path = File.join(created_path, 'hooks') + expect(File.lstat(hooks_path)).to be_symlink + expect(File.realpath(hooks_path)).to eq(gitlab_shell_hooks_path) + end + + it 'returns false when the command fails' do + FileUtils.mkdir_p(File.dirname(created_path)) + # This file will block the creation of the repo's .git directory. That + # should cause #add_repository to fail. + FileUtils.touch(created_path) + + expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_falsy + end end - it 'returns false when the command fails' do - expect(FileUtils).to receive(:mkdir_p).and_raise(Errno::EEXIST) + context 'with gitlay' do + it_behaves_like '#add_repository' + end - expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be_falsy + context 'without gitaly', skip_gitaly_mock: true do + it_behaves_like '#add_repository' end end @@ -136,7 +169,7 @@ describe Gitlab::Shell do it 'returns true when the command succeeds' do expect(Gitlab::Popen).to receive(:popen) .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'], - nil, popen_vars).and_return([nil, 0]) + nil, popen_vars).and_return([nil, 0]) expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be true end @@ -144,7 +177,7 @@ describe Gitlab::Shell do it 'returns false when the command fails' do expect(Gitlab::Popen).to receive(:popen) .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'], - nil, popen_vars).and_return(["error", 1]) + nil, popen_vars).and_return(["error", 1]) expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be false end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index c7d9f105f04..ee152872acc 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -26,6 +26,16 @@ describe Gitlab::UsageData do version uuid hostname + signup + ldap + gravatar + omniauth + reply_by_email + container_registry + gitlab_pages + gitlab_shared_runners + git + database )) end @@ -86,6 +96,32 @@ describe Gitlab::UsageData do end end + describe '#features_usage_data_ce' do + subject { described_class.features_usage_data_ce } + + it 'gathers feature usage data' do + expect(subject[:signup]).to eq(current_application_settings.signup_enabled?) + expect(subject[:ldap]).to eq(Gitlab.config.ldap.enabled) + expect(subject[:gravatar]).to eq(current_application_settings.gravatar_enabled?) + expect(subject[:omniauth]).to eq(Gitlab.config.omniauth.enabled) + expect(subject[:reply_by_email]).to eq(Gitlab::IncomingEmail.enabled?) + expect(subject[:container_registry]).to eq(Gitlab.config.registry.enabled) + expect(subject[:gitlab_shared_runners]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) + end + end + + describe '#components_usage_data' do + subject { described_class.components_usage_data } + + it 'gathers components usage data' do + expect(subject[:gitlab_pages][:enabled]).to eq(Gitlab.config.pages.enabled) + expect(subject[:gitlab_pages][:version]).to eq(Gitlab::Pages::VERSION) + expect(subject[:git][:version]).to eq(Gitlab::Git.version) + expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name) + expect(subject[:database][:version]).to eq(Gitlab::Database.version) + end + end + describe '#license_usage_data' do subject { described_class.license_usage_data } diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 699184ad9fe..5708aa6754f 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -214,14 +214,12 @@ describe Gitlab::Workhorse do end it 'includes a Repository param' do - repo_param = { Repository: { + repo_param = { storage_name: 'default', - relative_path: project.full_path + '.git', - git_object_directory: '', - git_alternate_object_directories: [] - } } + relative_path: project.full_path + '.git' + } - expect(subject).to include(repo_param) + expect(subject[:Repository]).to include(repo_param) end context "when git_upload_pack action is passed" do |