summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab')
-rw-r--r--spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb122
-rw-r--r--spec/lib/gitlab/backup/manager_spec.rb52
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb30
-rw-r--r--spec/lib/gitlab/ci/build/policy/refs_spec.rb87
-rw-r--r--spec/lib/gitlab/ci/build/policy_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_spec.rb66
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb55
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb85
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb142
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb126
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb60
-rw-r--r--spec/lib/gitlab/ci/pipeline/duration_spec.rb (renamed from spec/lib/gitlab/ci/pipeline_duration_spec.rb)6
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb251
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb4
-rw-r--r--spec/lib/gitlab/diff/diff_refs_spec.rb55
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb38
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb61
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb3
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb10
-rw-r--r--spec/lib/gitlab/git/hook_spec.rb3
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb114
-rw-r--r--spec/lib/gitlab/git/rev_list_spec.rb4
-rw-r--r--spec/lib/gitlab/git/storage/circuit_breaker_spec.rb13
-rw-r--r--spec/lib/gitlab/git/storage/null_circuit_breaker_spec.rb77
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb124
-rw-r--r--spec/lib/gitlab/health_checks/fs_shards_check_spec.rb18
-rw-r--r--spec/lib/gitlab/shell_spec.rb87
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb36
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb10
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