Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /spec/lib/gitlab/ci
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/badge/coverage/metadata_spec.rb32
-rw-r--r--spec/lib/gitlab/ci/badge/coverage/report_spec.rb99
-rw-r--r--spec/lib/gitlab/ci/badge/coverage/template_spec.rb182
-rw-r--r--spec/lib/gitlab/ci/badge/pipeline/metadata_spec.rb29
-rw-r--r--spec/lib/gitlab/ci/badge/pipeline/status_spec.rb127
-rw-r--r--spec/lib/gitlab/ci/badge/pipeline/template_spec.rb140
-rw-r--r--spec/lib/gitlab/ci/badge/shared/metadata.rb33
-rw-r--r--spec/lib/gitlab/ci/build/credentials/registry/dependency_proxy_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/build/credentials/registry/gitlab_registry_spec.rb (renamed from spec/lib/gitlab/ci/build/credentials/registry_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/build/rules_spec.rb29
-rw-r--r--spec/lib/gitlab/ci/charts_spec.rb82
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/config/entry/commands_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb29
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb121
-rw-r--r--spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb123
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/cron_parser_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/jwt_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/parsers/instrumentation_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/parsers_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/processable/resource_group_spec.rb (renamed from spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/reports/codequality_mr_diff_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/reports/codequality_reports_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/status/bridge/factory_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/bridge/waiting_for_resource_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/status/build/waiting_for_resource_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/status/processable/waiting_for_resource_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/trace/chunked_io_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/collection/sorted_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/variables/helpers_spec.rb103
38 files changed, 1415 insertions, 203 deletions
diff --git a/spec/lib/gitlab/ci/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/ci/badge/coverage/metadata_spec.rb
new file mode 100644
index 00000000000..6d272f060ab
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/coverage/metadata_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'lib/gitlab/ci/badge/shared/metadata'
+
+RSpec.describe Gitlab::Ci::Badge::Coverage::Metadata do
+ let(:badge) do
+ double(project: create(:project), ref: 'feature', job: 'test')
+ end
+
+ let(:metadata) { described_class.new(badge) }
+
+ it_behaves_like 'badge metadata'
+
+ describe '#title' do
+ it 'returns coverage report title' do
+ expect(metadata.title).to eq 'coverage report'
+ end
+ end
+
+ describe '#image_url' do
+ it 'returns valid url' do
+ expect(metadata.image_url).to include 'badges/feature/coverage.svg'
+ end
+ end
+
+ describe '#link_url' do
+ it 'returns valid link' do
+ expect(metadata.link_url).to include 'commits/feature'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/coverage/report_spec.rb b/spec/lib/gitlab/ci/badge/coverage/report_spec.rb
new file mode 100644
index 00000000000..13696d815aa
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/coverage/report_spec.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Badge::Coverage::Report do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:success_pipeline) { create(:ci_pipeline, :success, project: project) }
+ let_it_be(:running_pipeline) { create(:ci_pipeline, :running, project: project) }
+ let_it_be(:failure_pipeline) { create(:ci_pipeline, :failed, project: project) }
+
+ let_it_be(:builds) do
+ [
+ create(:ci_build, :success, pipeline: success_pipeline, coverage: 40, created_at: 9.seconds.ago, name: 'coverage'),
+ create(:ci_build, :success, pipeline: success_pipeline, coverage: 60, created_at: 8.seconds.ago)
+ ]
+ end
+
+ let(:badge) do
+ described_class.new(project, 'master', opts: { job: job_name })
+ end
+
+ let(:job_name) { nil }
+
+ describe '#entity' do
+ it 'describes a coverage' do
+ expect(badge.entity).to eq 'coverage'
+ end
+ end
+
+ describe '#metadata' do
+ it 'returns correct metadata' do
+ expect(badge.metadata.image_url).to include 'coverage.svg'
+ end
+ end
+
+ describe '#template' do
+ it 'returns correct template' do
+ expect(badge.template.key_text).to eq 'coverage'
+ end
+ end
+
+ describe '#status' do
+ context 'with no job specified' do
+ it 'returns the most recent successful pipeline coverage value' do
+ expect(badge.status).to eq(50.00)
+ end
+
+ context 'and no successful pipelines' do
+ before do
+ allow(badge).to receive(:successful_pipeline).and_return(nil)
+ end
+
+ it 'returns nil' do
+ expect(badge.status).to eq(nil)
+ end
+ end
+ end
+
+ context 'with a blank job name' do
+ let(:job_name) { ' ' }
+
+ it 'returns the latest successful pipeline coverage value' do
+ expect(badge.status).to eq(50.00)
+ end
+ end
+
+ context 'with an unmatching job name specified' do
+ let(:job_name) { 'incorrect name' }
+
+ it 'returns nil' do
+ expect(badge.status).to be_nil
+ end
+ end
+
+ context 'with a matching job name specified' do
+ let(:job_name) { 'coverage' }
+
+ it 'returns the pipeline coverage value' do
+ expect(badge.status).to eq(40.00)
+ end
+
+ context 'with a more recent running pipeline' do
+ let!(:another_build) { create(:ci_build, :success, pipeline: running_pipeline, coverage: 20, created_at: 7.seconds.ago, name: 'coverage') }
+
+ it 'returns the running pipeline coverage value' do
+ expect(badge.status).to eq(20.00)
+ end
+ end
+
+ context 'with a more recent failed pipeline' do
+ let!(:another_build) { create(:ci_build, :success, pipeline: failure_pipeline, coverage: 10, created_at: 6.seconds.ago, name: 'coverage') }
+
+ it 'returns the failed pipeline coverage value' do
+ expect(badge.status).to eq(10.00)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/coverage/template_spec.rb b/spec/lib/gitlab/ci/badge/coverage/template_spec.rb
new file mode 100644
index 00000000000..f010d1bce50
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/coverage/template_spec.rb
@@ -0,0 +1,182 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Badge::Coverage::Template do
+ let(:badge) { double(entity: 'coverage', status: 90.00, customization: {}) }
+ let(:template) { described_class.new(badge) }
+
+ describe '#key_text' do
+ it 'says coverage by default' do
+ expect(template.key_text).to eq 'coverage'
+ end
+
+ context 'when custom key_text is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: "custom text" })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_text).to eq "custom text"
+ end
+
+ context 'when its size is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: 't' * 65 })
+ end
+
+ it 'returns default value' do
+ expect(template.key_text).to eq 'coverage'
+ end
+ end
+ end
+ end
+
+ describe '#value_text' do
+ context 'when coverage is known' do
+ it 'returns coverage percentage' do
+ expect(template.value_text).to eq '90.00%'
+ end
+ end
+
+ context 'when coverage is known to many digits' do
+ before do
+ allow(badge).to receive(:status).and_return(92.349)
+ end
+
+ it 'returns rounded coverage percentage' do
+ expect(template.value_text).to eq '92.35%'
+ end
+ end
+
+ context 'when coverage is unknown' do
+ before do
+ allow(badge).to receive(:status).and_return(nil)
+ end
+
+ it 'returns string that says coverage is unknown' do
+ expect(template.value_text).to eq 'unknown'
+ end
+ end
+ end
+
+ describe '#key_width' do
+ it 'is fixed by default' do
+ expect(template.key_width).to eq 62
+ end
+
+ context 'when custom key_width is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: 101 })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_width).to eq 101
+ end
+
+ context 'when it is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: 513 })
+ end
+
+ it 'returns default value' do
+ expect(template.key_width).to eq 62
+ end
+ end
+ end
+ end
+
+ describe '#value_width' do
+ context 'when coverage is known' do
+ it 'is narrower when coverage is known' do
+ expect(template.value_width).to eq 54
+ end
+ end
+
+ context 'when coverage is unknown' do
+ before do
+ allow(badge).to receive(:status).and_return(nil)
+ end
+
+ it 'is wider when coverage is unknown to fit text' do
+ expect(template.value_width).to eq 58
+ end
+ end
+ end
+
+ describe '#key_color' do
+ it 'always has the same color' do
+ expect(template.key_color).to eq '#555'
+ end
+ end
+
+ describe '#value_color' do
+ context 'when coverage is good' do
+ before do
+ allow(badge).to receive(:status).and_return(98)
+ end
+
+ it 'is green' do
+ expect(template.value_color).to eq '#4c1'
+ end
+ end
+
+ context 'when coverage is acceptable' do
+ before do
+ allow(badge).to receive(:status).and_return(90)
+ end
+
+ it 'is green-orange' do
+ expect(template.value_color).to eq '#a3c51c'
+ end
+ end
+
+ context 'when coverage is medium' do
+ before do
+ allow(badge).to receive(:status).and_return(75)
+ end
+
+ it 'is orange-yellow' do
+ expect(template.value_color).to eq '#dfb317'
+ end
+ end
+
+ context 'when coverage is low' do
+ before do
+ allow(badge).to receive(:status).and_return(50)
+ end
+
+ it 'is red' do
+ expect(template.value_color).to eq '#e05d44'
+ end
+ end
+
+ context 'when coverage is unknown' do
+ before do
+ allow(badge).to receive(:status).and_return(nil)
+ end
+
+ it 'is grey' do
+ expect(template.value_color).to eq '#9f9f9f'
+ end
+ end
+ end
+
+ describe '#width' do
+ context 'when coverage is known' do
+ it 'returns the key width plus value width' do
+ expect(template.width).to eq 116
+ end
+ end
+
+ context 'when coverage is unknown' do
+ before do
+ allow(badge).to receive(:status).and_return(nil)
+ end
+
+ it 'returns key width plus wider value width' do
+ expect(template.width).to eq 120
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/pipeline/metadata_spec.rb b/spec/lib/gitlab/ci/badge/pipeline/metadata_spec.rb
new file mode 100644
index 00000000000..2f677237fad
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/pipeline/metadata_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'lib/gitlab/ci/badge/shared/metadata'
+
+RSpec.describe Gitlab::Ci::Badge::Pipeline::Metadata do
+ let(:badge) { double(project: create(:project), ref: 'feature') }
+ let(:metadata) { described_class.new(badge) }
+
+ it_behaves_like 'badge metadata'
+
+ describe '#title' do
+ it 'returns build status title' do
+ expect(metadata.title).to eq 'pipeline status'
+ end
+ end
+
+ describe '#image_url' do
+ it 'returns valid url' do
+ expect(metadata.image_url).to include 'badges/feature/pipeline.svg'
+ end
+ end
+
+ describe '#link_url' do
+ it 'returns valid link' do
+ expect(metadata.link_url).to include 'commits/feature'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb b/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb
new file mode 100644
index 00000000000..45d0d781090
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Badge::Pipeline::Status do
+ let(:project) { create(:project, :repository) }
+ let(:sha) { project.commit.sha }
+ let(:branch) { 'master' }
+ let(:badge) { described_class.new(project, branch) }
+
+ describe '#entity' do
+ it 'always says pipeline' do
+ expect(badge.entity).to eq 'pipeline'
+ end
+ end
+
+ describe '#template' do
+ it 'returns badge template' do
+ expect(badge.template.key_text).to eq 'pipeline'
+ end
+ end
+
+ describe '#metadata' do
+ it 'returns badge metadata' do
+ expect(badge.metadata.image_url).to include 'badges/master/pipeline.svg'
+ end
+ end
+
+ context 'pipeline exists', :sidekiq_might_not_need_inline do
+ let!(:pipeline) { create_pipeline(project, sha, branch) }
+
+ context 'pipeline success' do
+ before do
+ pipeline.success!
+ end
+
+ describe '#status' do
+ it 'is successful' do
+ expect(badge.status).to eq 'success'
+ end
+ end
+ end
+
+ context 'pipeline failed' do
+ before do
+ pipeline.drop!
+ end
+
+ describe '#status' do
+ it 'failed' do
+ expect(badge.status).to eq 'failed'
+ end
+ end
+ end
+
+ context 'when outdated pipeline for given ref exists' do
+ before do
+ pipeline.success!
+
+ old_pipeline = create_pipeline(project, '11eeffdd', branch)
+ old_pipeline.drop!
+ end
+
+ it 'does not take outdated pipeline into account' do
+ expect(badge.status).to eq 'success'
+ end
+ end
+
+ context 'when multiple pipelines exist for given sha' do
+ before do
+ pipeline.drop!
+
+ new_pipeline = create_pipeline(project, sha, branch)
+ new_pipeline.success!
+ end
+
+ it 'does not take outdated pipeline into account' do
+ expect(badge.status).to eq 'success'
+ end
+ end
+
+ context 'when ignored_skipped is set to true' do
+ let(:new_badge) { described_class.new(project, branch, opts: { ignore_skipped: true }) }
+
+ before do
+ pipeline.skip!
+ end
+
+ describe '#status' do
+ it 'uses latest non-skipped status' do
+ expect(new_badge.status).not_to eq 'skipped'
+ end
+ end
+ end
+
+ context 'when ignored_skipped is set to false' do
+ let(:new_badge) { described_class.new(project, branch, opts: { ignore_skipped: false }) }
+
+ before do
+ pipeline.skip!
+ end
+
+ describe '#status' do
+ it 'uses latest status' do
+ expect(new_badge.status).to eq 'skipped'
+ end
+ end
+ end
+ end
+
+ context 'build does not exist' do
+ describe '#status' do
+ it 'is unknown' do
+ expect(badge.status).to eq 'unknown'
+ end
+ end
+ end
+
+ def create_pipeline(project, sha, branch)
+ pipeline = create(:ci_empty_pipeline,
+ project: project,
+ sha: sha,
+ ref: branch)
+
+ create(:ci_build, pipeline: pipeline, stage: 'notify')
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb b/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb
new file mode 100644
index 00000000000..696bb62b4d6
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb
@@ -0,0 +1,140 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Badge::Pipeline::Template do
+ let(:badge) { double(entity: 'pipeline', status: 'success', customization: {}) }
+ let(:template) { described_class.new(badge) }
+
+ describe '#key_text' do
+ it 'says pipeline by default' do
+ expect(template.key_text).to eq 'pipeline'
+ end
+
+ context 'when custom key_text is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: 'custom text' })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_text).to eq 'custom text'
+ end
+
+ context 'when its size is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: 't' * 65 })
+ end
+
+ it 'returns default value' do
+ expect(template.key_text).to eq 'pipeline'
+ end
+ end
+ end
+ end
+
+ describe '#value_text' do
+ it 'is status value' do
+ expect(template.value_text).to eq 'passed'
+ end
+ end
+
+ describe '#key_width' do
+ it 'is fixed by default' do
+ expect(template.key_width).to eq 62
+ end
+
+ context 'when custom key_width is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: 101 })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_width).to eq 101
+ end
+
+ context 'when it is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: 513 })
+ end
+
+ it 'returns default value' do
+ expect(template.key_width).to eq 62
+ end
+ end
+ end
+ end
+
+ describe 'widths and text anchors' do
+ it 'has fixed width and text anchors' do
+ expect(template.width).to eq 116
+ expect(template.key_width).to eq 62
+ expect(template.value_width).to eq 54
+ expect(template.key_text_anchor).to eq 31
+ expect(template.value_text_anchor).to eq 89
+ end
+ end
+
+ describe '#key_color' do
+ it 'is always the same' do
+ expect(template.key_color).to eq '#555'
+ end
+ end
+
+ describe '#value_color' do
+ context 'when status is success' do
+ it 'has expected color' do
+ expect(template.value_color).to eq '#4c1'
+ end
+ end
+
+ context 'when status is failed' do
+ before do
+ allow(badge).to receive(:status).and_return('failed')
+ end
+
+ it 'has expected color' do
+ expect(template.value_color).to eq '#e05d44'
+ end
+ end
+
+ context 'when status is running' do
+ before do
+ allow(badge).to receive(:status).and_return('running')
+ end
+
+ it 'has expected color' do
+ expect(template.value_color).to eq '#dfb317'
+ end
+ end
+
+ context 'when status is preparing' do
+ before do
+ allow(badge).to receive(:status).and_return('preparing')
+ end
+
+ it 'has expected color' do
+ expect(template.value_color).to eq '#a7a7a7'
+ end
+ end
+
+ context 'when status is unknown' do
+ before do
+ allow(badge).to receive(:status).and_return('unknown')
+ end
+
+ it 'has expected color' do
+ expect(template.value_color).to eq '#9f9f9f'
+ end
+ end
+
+ context 'when status does not match any known statuses' do
+ before do
+ allow(badge).to receive(:status).and_return('invalid')
+ end
+
+ it 'has expected color' do
+ expect(template.value_color).to eq '#9f9f9f'
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/badge/shared/metadata.rb b/spec/lib/gitlab/ci/badge/shared/metadata.rb
new file mode 100644
index 00000000000..c99a65bb2f4
--- /dev/null
+++ b/spec/lib/gitlab/ci/badge/shared/metadata.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'badge metadata' do
+ describe '#to_html' do
+ let(:html) { Nokogiri::HTML.parse(metadata.to_html) }
+ let(:a_href) { html.at('a') }
+
+ it 'points to link' do
+ expect(a_href[:href]).to eq metadata.link_url
+ end
+
+ it 'contains clickable image' do
+ expect(a_href.children.first.name).to eq 'img'
+ end
+ end
+
+ describe '#to_markdown' do
+ subject { metadata.to_markdown }
+
+ it { is_expected.to include metadata.image_url }
+ it { is_expected.to include metadata.link_url }
+ end
+
+ describe '#to_asciidoc' do
+ subject { metadata.to_asciidoc }
+
+ it { is_expected.to include metadata.image_url }
+ it { is_expected.to include metadata.link_url }
+ it { is_expected.to include 'image:' }
+ it { is_expected.to include 'link=' }
+ it { is_expected.to include 'title=' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/credentials/registry/dependency_proxy_spec.rb b/spec/lib/gitlab/ci/build/credentials/registry/dependency_proxy_spec.rb
new file mode 100644
index 00000000000..f50c6e99e99
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/credentials/registry/dependency_proxy_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Build::Credentials::Registry::DependencyProxy do
+ let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
+ let(:gitlab_url) { 'gitlab.example.com:443' }
+
+ subject { described_class.new(build) }
+
+ before do
+ stub_config_setting(host: 'gitlab.example.com', port: 443)
+ end
+
+ it 'contains valid dependency proxy credentials' do
+ expect(subject).to be_kind_of(described_class)
+
+ expect(subject.username).to eq 'gitlab-ci-token'
+ expect(subject.password).to eq build.token
+ expect(subject.url).to eq gitlab_url
+ expect(subject.type).to eq 'registry'
+ end
+
+ describe '.valid?' do
+ subject { described_class.new(build).valid? }
+
+ context 'when dependency proxy is enabled' do
+ before do
+ stub_config(dependency_proxy: { enabled: true })
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when dependency proxy is disabled' do
+ before do
+ stub_config(dependency_proxy: { enabled: false })
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb b/spec/lib/gitlab/ci/build/credentials/registry/gitlab_registry_spec.rb
index c0a76973f60..43913e91085 100644
--- a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
+++ b/spec/lib/gitlab/ci/build/credentials/registry/gitlab_registry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::Credentials::Registry do
+RSpec.describe Gitlab::Ci::Build::Credentials::Registry::GitlabRegistry do
let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
let(:registry_url) { 'registry.example.com:5005' }
diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb
index a1af5b75f87..0b50def05d4 100644
--- a/spec/lib/gitlab/ci/build/rules_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules_spec.rb
@@ -201,40 +201,13 @@ RSpec.describe Gitlab::Ci::Build::Rules do
end
describe '#build_attributes' do
- let(:seed_attributes) { {} }
-
subject(:build_attributes) do
- result.build_attributes(seed_attributes)
+ result.build_attributes
end
it 'compacts nil values' do
is_expected.to eq(options: {}, when: 'on_success')
end
-
- context 'when there are variables in rules' do
- let(:variables) { { VAR1: 'new var 1', VAR3: 'var 3' } }
-
- context 'when there are seed variables' do
- let(:seed_attributes) do
- { yaml_variables: [{ key: 'VAR1', value: 'var 1', public: true },
- { key: 'VAR2', value: 'var 2', public: true }] }
- end
-
- it 'returns yaml_variables with override' do
- is_expected.to include(
- yaml_variables: [{ key: 'VAR1', value: 'new var 1', public: true },
- { key: 'VAR2', value: 'var 2', public: true },
- { key: 'VAR3', value: 'var 3', public: true }]
- )
- end
- end
-
- context 'when there is not seed variables' do
- it 'does not return yaml_variables' do
- is_expected.not_to have_key(:yaml_variables)
- end
- end
- end
end
describe '#pass?' do
diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb
index cfc2019a89b..46d7d4a58f0 100644
--- a/spec/lib/gitlab/ci/charts_spec.rb
+++ b/spec/lib/gitlab/ci/charts_spec.rb
@@ -9,6 +9,10 @@ RSpec.describe Gitlab::Ci::Charts do
subject { chart.to }
+ before do
+ create(:ci_empty_pipeline, project: project, duration: 120)
+ end
+
it 'goes until the end of the current month (including the whole last day of the month)' do
is_expected.to eq(Date.today.end_of_month.end_of_day)
end
@@ -20,6 +24,10 @@ RSpec.describe Gitlab::Ci::Charts do
it 'uses %B %Y as labels format' do
expect(chart.labels).to include(chart.from.strftime('%B %Y'))
end
+
+ it 'returns count of pipelines run each day in the current year' do
+ expect(chart.total.sum).to eq(1)
+ end
end
context 'monthchart' do
@@ -28,6 +36,10 @@ RSpec.describe Gitlab::Ci::Charts do
subject { chart.to }
+ before do
+ create(:ci_empty_pipeline, project: project, duration: 120)
+ end
+
it 'includes the whole current day' do
is_expected.to eq(Date.today.end_of_day)
end
@@ -39,6 +51,10 @@ RSpec.describe Gitlab::Ci::Charts do
it 'uses %d %B as labels format' do
expect(chart.labels).to include(chart.from.strftime('%d %B'))
end
+
+ it 'returns count of pipelines run each day in the current month' do
+ expect(chart.total.sum).to eq(1)
+ end
end
context 'weekchart' do
@@ -47,6 +63,10 @@ RSpec.describe Gitlab::Ci::Charts do
subject { chart.to }
+ before do
+ create(:ci_empty_pipeline, project: project, duration: 120)
+ end
+
it 'includes the whole current day' do
is_expected.to eq(Date.today.end_of_day)
end
@@ -58,6 +78,68 @@ RSpec.describe Gitlab::Ci::Charts do
it 'uses %d %B as labels format' do
expect(chart.labels).to include(chart.from.strftime('%d %B'))
end
+
+ it 'returns count of pipelines run each day in the current week' do
+ expect(chart.total.sum).to eq(1)
+ end
+ end
+
+ context 'weekchart_utc' do
+ today = Date.today
+ end_of_today = Time.use_zone(Time.find_zone('UTC')) { today.end_of_day }
+
+ let(:project) { create(:project) }
+ let(:chart) do
+ allow(Date).to receive(:today).and_return(today)
+ allow(today).to receive(:end_of_day).and_return(end_of_today)
+ Gitlab::Ci::Charts::WeekChart.new(project)
+ end
+
+ subject { chart.total }
+
+ before do
+ create(:ci_empty_pipeline, project: project, duration: 120)
+ end
+
+ it 'uses a utc time zone for range times' do
+ expect(chart.to.zone).to eq(end_of_today.zone)
+ expect(chart.from.zone).to eq(end_of_today.zone)
+ end
+
+ it 'returns count of pipelines run each day in the current week' do
+ expect(chart.total.sum).to eq(1)
+ end
+ end
+
+ context 'weekchart_non_utc' do
+ today = Date.today
+ end_of_today = Time.use_zone(Time.find_zone('Asia/Dubai')) { today.end_of_day }
+
+ let(:project) { create(:project) }
+ let(:chart) do
+ allow(Date).to receive(:today).and_return(today)
+ allow(today).to receive(:end_of_day).and_return(end_of_today)
+ Gitlab::Ci::Charts::WeekChart.new(project)
+ end
+
+ subject { chart.total }
+
+ before do
+ # The DB uses UTC always, so our use of a Time Zone in the application
+ # can cause the creation date of the pipeline to go unmatched depending
+ # on the offset. We can work around this by requesting the pipeline be
+ # created a with the `created_at` field set to a day ago in the same week.
+ create(:ci_empty_pipeline, project: project, duration: 120, created_at: today - 1.day)
+ end
+
+ it 'uses a non-utc time zone for range times' do
+ expect(chart.to.zone).to eq(end_of_today.zone)
+ expect(chart.from.zone).to eq(end_of_today.zone)
+ end
+
+ it 'returns count of pipelines run each day in the current week' do
+ expect(chart.total.sum).to eq(1)
+ end
end
context 'pipeline_times' do
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 80427eaa6ee..247f4b63910 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Cache do
+ using RSpec::Parameterized::TableSyntax
+
subject(:entry) { described_class.new(config) }
describe 'validations' do
@@ -56,8 +58,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
context 'with `policy`' do
- using RSpec::Parameterized::TableSyntax
-
where(:policy, :result) do
'pull-push' | 'pull-push'
'push' | 'push'
@@ -77,8 +77,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
context 'with `when`' do
- using RSpec::Parameterized::TableSyntax
-
where(:when_config, :result) do
'on_success' | 'on_success'
'on_failure' | 'on_failure'
@@ -109,8 +107,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
context 'with `policy`' do
- using RSpec::Parameterized::TableSyntax
-
where(:policy, :valid) do
'pull-push' | true
'push' | true
@@ -126,8 +122,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
context 'with `when`' do
- using RSpec::Parameterized::TableSyntax
-
where(:when_config, :valid) do
'on_success' | true
'on_failure' | true
diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
index 439799fe973..1b8dfae692a 100644
--- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
@@ -87,18 +87,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Commands do
describe '#errors' do
it 'saves errors' do
expect(entry.errors)
- .to include 'commands config should be a string or an array containing strings and arrays of strings'
+ .to include 'commands config should be a string or a nested array of strings up to 10 levels deep'
end
end
end
context 'when entry value is multi-level nested array' do
- let(:config) { [['ls', ['echo 1']], 'pwd'] }
+ let(:config) do
+ ['ls 0', ['ls 1', ['ls 2', ['ls 3', ['ls 4', ['ls 5', ['ls 6', ['ls 7', ['ls 8', ['ls 9', ['ls 10']]]]]]]]]]]
+ end
describe '#errors' do
it 'saves errors' do
expect(entry.errors)
- .to include 'commands config should be a string or an array containing strings and arrays of strings'
+ .to include 'commands config should be a string or a nested array of strings up to 10 levels deep'
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 7834a1a94f2..a3b5f32b9f9 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -763,16 +763,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
it 'returns allow_failure_criteria' do
expect(entry.value[:allow_failure_criteria]).to match(exit_codes: [42])
end
-
- context 'with ci_allow_failure_with_exit_codes disabled' do
- before do
- stub_feature_flags(ci_allow_failure_with_exit_codes: false)
- end
-
- it 'does not return allow_failure_criteria' do
- expect(entry.value.key?(:allow_failure_criteria)).to be_falsey
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index aadf94365c6..04e80450263 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -73,6 +73,15 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
end
end
+ context 'when resource_group key is not a string' do
+ let(:config) { { resource_group: 123 } }
+
+ it 'returns error about wrong value type' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include "job resource group should be a string"
+ end
+ end
+
context 'when it uses both "when:" and "rules:"' do
let(:config) do
{
@@ -340,6 +349,26 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
end
end
+ context 'with resource group' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:resource_group, :result) do
+ 'iOS' | 'iOS'
+ 'review/$CI_COMMIT_REF_NAME' | 'review/$CI_COMMIT_REF_NAME'
+ nil | nil
+ end
+
+ with_them do
+ let(:config) { { script: 'ls', resource_group: resource_group }.compact }
+
+ it do
+ entry.compose!(deps)
+
+ expect(entry.resource_group).to eq(result)
+ end
+ end
+ end
+
context 'with inheritance' do
context 'of variables' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index 4fdaaca8316..99f546ceb37 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -323,20 +323,6 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
expect { subject }.to raise_error(described_class::AmbigiousSpecificationError)
end
end
-
- context 'when feature flag is turned off' do
- let(:values) do
- { include: full_local_file_path }
- end
-
- before do
- stub_feature_flags(variables_in_include_section_ci: false)
- end
-
- it 'does not expand the variables' do
- expect(subject[0].location).to eq('$CI_PROJECT_PATH' + local_file)
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb b/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb
new file mode 100644
index 00000000000..c68dccd3455
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Reference do
+ let(:config) do
+ Gitlab::Ci::Config::Yaml.load!(yaml)
+ end
+
+ describe '.tag' do
+ it 'implements the tag method' do
+ expect(described_class.tag).to eq('!reference')
+ end
+ end
+
+ describe '#resolve' do
+ subject { Gitlab::Ci::Config::Yaml::Tags::Resolver.new(config).to_hash }
+
+ context 'with circular references' do
+ let(:yaml) do
+ <<~YML
+ a: !reference [b]
+ b: !reference [a]
+ YML
+ end
+
+ it 'raises CircularReferenceError' do
+ expect { subject }.to raise_error Gitlab::Ci::Config::Yaml::Tags::TagError, '!reference ["b"] is part of a circular chain'
+ end
+ end
+
+ context 'with nested circular references' do
+ let(:yaml) do
+ <<~YML
+ a: !reference [b, c]
+ b: { c: !reference [d, e, f] }
+ d: { e: { f: !reference [a] } }
+ YML
+ end
+
+ it 'raises CircularReferenceError' do
+ expect { subject }.to raise_error Gitlab::Ci::Config::Yaml::Tags::TagError, '!reference ["b", "c"] is part of a circular chain'
+ end
+ end
+
+ context 'with missing references' do
+ let(:yaml) { 'a: !reference [b]' }
+
+ it 'raises MissingReferenceError' do
+ expect { subject }.to raise_error Gitlab::Ci::Config::Yaml::Tags::TagError, '!reference ["b"] could not be found'
+ end
+ end
+
+ context 'with invalid references' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:yaml, :error_message) do
+ 'a: !reference' | '!reference [] is not valid'
+ 'a: !reference str' | '!reference "str" is not valid'
+ 'a: !reference 1' | '!reference "1" is not valid'
+ 'a: !reference [1]' | '!reference [1] is not valid'
+ 'a: !reference { b: c }' | '!reference {"b"=>"c"} is not valid'
+ end
+
+ with_them do
+ it 'raises an error' do
+ expect { subject }.to raise_error Gitlab::Ci::Config::Yaml::Tags::TagError, error_message
+ end
+ end
+ end
+
+ context 'with arrays' do
+ let(:yaml) do
+ <<~YML
+ a: { b: [1, 2] }
+ c: { d: { e: [3, 4] } }
+ f: { g: [ !reference [a, b], 5, !reference [c, d, e]] }
+ YML
+ end
+
+ it { is_expected.to match(a_hash_including({ f: { g: [[1, 2], 5, [3, 4]] } })) }
+ end
+
+ context 'with hashes' do
+ context 'when referencing an entire hash' do
+ let(:yaml) do
+ <<~YML
+ a: { b: { c: 'c', d: 'd' } }
+ e: { f: !reference [a, b] }
+ YML
+ end
+
+ it { is_expected.to match(a_hash_including({ e: { f: { c: 'c', d: 'd' } } })) }
+ end
+
+ context 'when referencing only a hash value' do
+ let(:yaml) do
+ <<~YML
+ a: { b: { c: 'c', d: 'd' } }
+ e: { f: { g: !reference [a, b, c], h: 'h' } }
+ i: !reference [e, f]
+ YML
+ end
+
+ it { is_expected.to match(a_hash_including({ i: { g: 'c', h: 'h' } })) }
+ end
+
+ context 'when referencing a value before its definition' do
+ let(:yaml) do
+ <<~YML
+ a: { b: !reference [c, d] }
+ g: { h: { i: 'i', j: 1 } }
+ c: { d: { e: !reference [g, h, j], f: 'f' } }
+ YML
+ end
+
+ it { is_expected.to match(a_hash_including({ a: { b: { e: 1, f: 'f' } } })) }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb b/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb
new file mode 100644
index 00000000000..594242c33cc
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Resolver do
+ let(:config) do
+ Gitlab::Ci::Config::Yaml.load!(yaml)
+ end
+
+ describe '#to_hash' do
+ subject { described_class.new(config).to_hash }
+
+ context 'when referencing deeply nested arrays' do
+ let(:yaml_templates) do
+ <<~YML
+ .job-1:
+ script:
+ - echo doing step 1 of job 1
+ - echo doing step 2 of job 1
+
+ .job-2:
+ script:
+ - echo doing step 1 of job 2
+ - !reference [.job-1, script]
+ - echo doing step 2 of job 2
+
+ .job-3:
+ script:
+ - echo doing step 1 of job 3
+ - !reference [.job-2, script]
+ - echo doing step 2 of job 3
+ YML
+ end
+
+ let(:job_yaml) do
+ <<~YML
+ test:
+ script:
+ - echo preparing to test
+ - !reference [.job-3, script]
+ - echo test finished
+ YML
+ end
+
+ shared_examples 'expands references' do
+ it 'expands the references' do
+ is_expected.to match({
+ '.job-1': {
+ script: [
+ 'echo doing step 1 of job 1',
+ 'echo doing step 2 of job 1'
+ ]
+ },
+ '.job-2': {
+ script: [
+ 'echo doing step 1 of job 2',
+ [
+ 'echo doing step 1 of job 1',
+ 'echo doing step 2 of job 1'
+ ],
+ 'echo doing step 2 of job 2'
+ ]
+ },
+ '.job-3': {
+ script: [
+ 'echo doing step 1 of job 3',
+ [
+ 'echo doing step 1 of job 2',
+ [
+ 'echo doing step 1 of job 1',
+ 'echo doing step 2 of job 1'
+ ],
+ 'echo doing step 2 of job 2'
+ ],
+ 'echo doing step 2 of job 3'
+ ]
+ },
+ test: {
+ script: [
+ 'echo preparing to test',
+ [
+ 'echo doing step 1 of job 3',
+ [
+ 'echo doing step 1 of job 2',
+ [
+ 'echo doing step 1 of job 1',
+ 'echo doing step 2 of job 1'
+ ],
+ 'echo doing step 2 of job 2'
+ ],
+ 'echo doing step 2 of job 3'
+ ],
+ 'echo test finished'
+ ]
+ }
+ })
+ end
+ end
+
+ context 'when templates are defined before the job' do
+ let(:yaml) do
+ <<~YML
+ #{yaml_templates}
+ #{job_yaml}
+ YML
+ end
+
+ it_behaves_like 'expands references'
+ end
+
+ context 'when templates are defined after the job' do
+ let(:yaml) do
+ <<~YML
+ #{job_yaml}
+ #{yaml_templates}
+ YML
+ end
+
+ it_behaves_like 'expands references'
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index dc03d2f80fe..45ce4cac6c4 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -263,6 +263,26 @@ RSpec.describe Gitlab::Ci::Config do
end
end
end
+
+ context 'when yaml uses circular !reference' do
+ let(:yml) do
+ <<~YAML
+ job-1:
+ script:
+ - !reference [job-2, before_script]
+
+ job-2:
+ before_script: !reference [job-1, script]
+ YAML
+ end
+
+ it 'raises error' do
+ expect { config }.to raise_error(
+ described_class::ConfigError,
+ /\!reference \["job-2", "before_script"\] is part of a circular chain/
+ )
+ end
+ end
end
context "when using 'include' directive" do
diff --git a/spec/lib/gitlab/ci/cron_parser_spec.rb b/spec/lib/gitlab/ci/cron_parser_spec.rb
index dd27b4045c9..15293429354 100644
--- a/spec/lib/gitlab/ci/cron_parser_spec.rb
+++ b/spec/lib/gitlab/ci/cron_parser_spec.rb
@@ -63,6 +63,17 @@ RSpec.describe Gitlab::Ci::CronParser do
end
end
+ context 'when range and slash used' do
+ let(:cron) { '3-59/10 * * * *' }
+ let(:cron_timezone) { 'UTC' }
+
+ it_behaves_like returns_time_for_epoch
+
+ it 'returns specific time' do
+ expect(subject.min).to be_in([3, 13, 23, 33, 43, 53])
+ end
+ end
+
context 'when cron_timezone is TZInfo format' do
before do
allow(Time).to receive(:zone)
diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb
index 3130c0c0c41..342ca6b8b75 100644
--- a/spec/lib/gitlab/ci/jwt_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_spec.rb
@@ -44,6 +44,9 @@ RSpec.describe Gitlab::Ci::Jwt do
expect(payload[:pipeline_id]).to eq(pipeline.id.to_s)
expect(payload[:job_id]).to eq(build.id.to_s)
expect(payload[:ref]).to eq(pipeline.source_ref)
+ expect(payload[:ref_protected]).to eq(build.protected.to_s)
+ expect(payload[:environment]).to be_nil
+ expect(payload[:environment_protected]).to be_nil
end
end
@@ -90,6 +93,39 @@ RSpec.describe Gitlab::Ci::Jwt do
expect(payload[:ref_protected]).to eq('true')
end
end
+
+ describe 'environment' do
+ let(:environment) { build_stubbed(:environment, project: project, name: 'production') }
+ let(:build) do
+ build_stubbed(
+ :ci_build,
+ project: project,
+ user: user,
+ pipeline: pipeline,
+ environment: environment.name
+ )
+ end
+
+ before do
+ allow(build).to receive(:persisted_environment).and_return(environment)
+ end
+
+ it 'has correct values for environment attributes' do
+ expect(payload[:environment]).to eq('production')
+ expect(payload[:environment_protected]).to eq('false')
+ end
+
+ context ':ci_jwt_include_environment feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_jwt_include_environment: false)
+ end
+
+ it 'does not include environment attributes' do
+ expect(payload).not_to have_key(:environment)
+ expect(payload).not_to have_key(:environment_protected)
+ end
+ end
+ end
end
describe '.for_build' do
diff --git a/spec/lib/gitlab/ci/parsers/instrumentation_spec.rb b/spec/lib/gitlab/ci/parsers/instrumentation_spec.rb
new file mode 100644
index 00000000000..30bcce21be2
--- /dev/null
+++ b/spec/lib/gitlab/ci/parsers/instrumentation_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Parsers::Instrumentation do
+ describe '#parse!' do
+ let(:parser_class) do
+ Class.new do
+ prepend Gitlab::Ci::Parsers::Instrumentation
+
+ def parse!(arg1, arg2)
+ "parse #{arg1} #{arg2}"
+ end
+ end
+ end
+
+ it 'sets metrics for duration of parsing' do
+ result = parser_class.new.parse!('hello', 'world')
+
+ expect(result).to eq('parse hello world')
+
+ metrics = Gitlab::Metrics.registry.get(:ci_report_parser_duration_seconds).get({ parser: parser_class.name })
+
+ expect(metrics.keys).to match_array(described_class::BUCKETS)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/parsers_spec.rb b/spec/lib/gitlab/ci/parsers_spec.rb
index b932cd81272..c9891c06507 100644
--- a/spec/lib/gitlab/ci/parsers_spec.rb
+++ b/spec/lib/gitlab/ci/parsers_spec.rb
@@ -54,4 +54,12 @@ RSpec.describe Gitlab::Ci::Parsers do
end
end
end
+
+ describe '.instrument!' do
+ it 'prepends the Instrumentation module into each parser' do
+ expect(described_class.parsers.values).to all( receive(:prepend).with(Gitlab::Ci::Parsers::Instrumentation) )
+
+ described_class.instrument!
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
index 20406acb658..53dea1d0d19 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
@@ -235,7 +235,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
with_them do
before do
- project.update!(ci_keep_latest_artifact: keep_latest_artifact)
+ project.update!(keep_latest_artifact: keep_latest_artifact)
end
it 'builds a pipeline with appropriate locked value' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
index 3eaecb11ae0..1d17244e519 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
@@ -58,20 +58,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
expect(build_statuses(child_pipeline)).to contain_exactly('canceled')
end
-
- context 'when FF ci_auto_cancel_all_pipelines is disabled' do
- before do
- stub_feature_flags(ci_auto_cancel_all_pipelines: false)
- end
-
- it 'does not cancel interruptible builds of child pipeline' do
- expect(build_statuses(child_pipeline)).to contain_exactly('running')
-
- perform
-
- expect(build_statuses(child_pipeline)).to contain_exactly('running')
- end
- end
end
context 'when the child pipeline has not an interruptible job' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
index 3616461d94f..cd868a57bbc 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::TemplateUsage do
%w(Template-1 Template-2).each do |expected_template|
expect(Gitlab::UsageDataCounters::CiTemplateUniqueCounter).to(
receive(:track_unique_project_event)
- .with(project_id: project.id, template: expected_template)
+ .with(project_id: project.id, template: expected_template, config_source: pipeline.config_source)
)
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index cf020fc343c..0efc7484699 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -383,14 +383,25 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
end
context 'when job is a bridge' do
- let(:attributes) do
+ let(:base_attributes) do
{
name: 'rspec', ref: 'master', options: { trigger: 'my/project' }, scheduling_type: :stage
}
end
+ let(:attributes) { base_attributes }
+
it { is_expected.to be_a(::Ci::Bridge) }
it { is_expected.to be_valid }
+
+ context 'when job belongs to a resource group' do
+ let(:attributes) { base_attributes.merge(resource_group_key: 'iOS') }
+
+ it 'returns a job with resource group' do
+ expect(subject.resource_group).not_to be_nil
+ expect(subject.resource_group.key).to eq('iOS')
+ end
+ end
end
it 'memoizes a resource object' do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/processable/resource_group_spec.rb
index 8fcc242ba5f..b7260599de2 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/processable/resource_group_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::ResourceGroup do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Processable::ResourceGroup do
let_it_be(:project) { create(:project) }
let(:job) { build(:ci_build, project: project) }
let(:seed) { described_class.new(job, resource_group_key) }
diff --git a/spec/lib/gitlab/ci/reports/codequality_mr_diff_spec.rb b/spec/lib/gitlab/ci/reports/codequality_mr_diff_spec.rb
new file mode 100644
index 00000000000..8b177fa7fc1
--- /dev/null
+++ b/spec/lib/gitlab/ci/reports/codequality_mr_diff_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Reports::CodequalityMrDiff do
+ let(:codequality_report) { Gitlab::Ci::Reports::CodequalityReports.new }
+ let(:degradation_1) { build(:codequality_degradation_1) }
+ let(:degradation_2) { build(:codequality_degradation_2) }
+ let(:degradation_3) { build(:codequality_degradation_3) }
+
+ describe '#initialize!' do
+ subject(:report) { described_class.new(codequality_report) }
+
+ context 'when quality has degradations' do
+ context 'with several degradations on the same line' do
+ before do
+ codequality_report.add_degradation(degradation_1)
+ codequality_report.add_degradation(degradation_2)
+ end
+
+ it 'generates quality report for mr diff' do
+ expect(report.files).to match(
+ "file_a.rb" => [
+ { line: 10, description: "Avoid parameter lists longer than 5 parameters. [12/5]", severity: "major" },
+ { line: 10, description: "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.", severity: "major" }
+ ]
+ )
+ end
+ end
+
+ context 'with several degradations on several files' do
+ before do
+ codequality_report.add_degradation(degradation_1)
+ codequality_report.add_degradation(degradation_2)
+ codequality_report.add_degradation(degradation_3)
+ end
+
+ it 'returns quality report for mr diff' do
+ expect(report.files).to match(
+ "file_a.rb" => [
+ { line: 10, description: "Avoid parameter lists longer than 5 parameters. [12/5]", severity: "major" },
+ { line: 10, description: "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.", severity: "major" }
+ ],
+ "file_b.rb" => [
+ { line: 10, description: "Avoid parameter lists longer than 5 parameters. [12/5]", severity: "minor" }
+ ]
+ )
+ end
+ end
+ end
+
+ context 'when quality has no degradation' do
+ it 'returns an empty hash' do
+ expect(report.files).to match({})
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
index 7053d54381b..90188b56f5a 100644
--- a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
@@ -6,62 +6,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
let(:comparer) { described_class.new(base_report, head_report) }
let(:base_report) { Gitlab::Ci::Reports::CodequalityReports.new }
let(:head_report) { Gitlab::Ci::Reports::CodequalityReports.new }
- let(:degradation_1) do
- {
- "categories": [
- "Complexity"
- ],
- "check_name": "argument_count",
- "content": {
- "body": ""
- },
- "description": "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.",
- "fingerprint": "15cdb5c53afd42bc22f8ca366a08d547",
- "location": {
- "path": "foo.rb",
- "lines": {
- "begin": 10,
- "end": 10
- }
- },
- "other_locations": [],
- "remediation_points": 900000,
- "severity": "major",
- "type": "issue",
- "engine_name": "structure"
- }.with_indifferent_access
- end
-
- let(:degradation_2) do
- {
- "type": "Issue",
- "check_name": "Rubocop/Metrics/ParameterLists",
- "description": "Avoid parameter lists longer than 5 parameters. [12/5]",
- "categories": [
- "Complexity"
- ],
- "remediation_points": 550000,
- "location": {
- "path": "foo.rb",
- "positions": {
- "begin": {
- "column": 14,
- "line": 10
- },
- "end": {
- "column": 39,
- "line": 10
- }
- }
- },
- "content": {
- "body": "This cop checks for methods with too many parameters.\nThe maximum number of parameters is configurable.\nKeyword arguments can optionally be excluded from the total count."
- },
- "engine_name": "rubocop",
- "fingerprint": "ab5f8b935886b942d621399f5a2ca16e",
- "severity": "minor"
- }.with_indifferent_access
- end
+ let(:degradation_1) { build(:codequality_degradation_1) }
+ let(:degradation_2) { build(:codequality_degradation_2) }
describe '#status' do
subject(:report_status) { comparer.status }
diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
index 44e67259369..ae9b2f2c62b 100644
--- a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
@@ -4,62 +4,8 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::CodequalityReports do
let(:codequality_report) { described_class.new }
- let(:degradation_1) do
- {
- "categories": [
- "Complexity"
- ],
- "check_name": "argument_count",
- "content": {
- "body": ""
- },
- "description": "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.",
- "fingerprint": "15cdb5c53afd42bc22f8ca366a08d547",
- "location": {
- "path": "foo.rb",
- "lines": {
- "begin": 10,
- "end": 10
- }
- },
- "other_locations": [],
- "remediation_points": 900000,
- "severity": "major",
- "type": "issue",
- "engine_name": "structure"
- }.with_indifferent_access
- end
-
- let(:degradation_2) do
- {
- "type": "Issue",
- "check_name": "Rubocop/Metrics/ParameterLists",
- "description": "Avoid parameter lists longer than 5 parameters. [12/5]",
- "categories": [
- "Complexity"
- ],
- "remediation_points": 550000,
- "location": {
- "path": "foo.rb",
- "positions": {
- "begin": {
- "column": 14,
- "line": 10
- },
- "end": {
- "column": 39,
- "line": 10
- }
- }
- },
- "content": {
- "body": "This cop checks for methods with too many parameters.\nThe maximum number of parameters is configurable.\nKeyword arguments can optionally be excluded from the total count."
- },
- "engine_name": "rubocop",
- "fingerprint": "ab5f8b935886b942d621399f5a2ca16e",
- "severity": "minor"
- }.with_indifferent_access
- end
+ let(:degradation_1) { build(:codequality_degradation_1) }
+ let(:degradation_2) { build(:codequality_degradation_2) }
it { expect(codequality_report.degradations).to eq({}) }
diff --git a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
index d27bb98ba9a..6081f104e42 100644
--- a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
@@ -117,14 +117,31 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory do
end
end
+ context 'when bridge is waiting for resource' do
+ let(:bridge) { create_bridge(:waiting_for_resource, :resource_group) }
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::WaitingForResource
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'waiting'
+ expect(status.group).to eq 'waiting-for-resource'
+ expect(status.icon).to eq 'status_pending'
+ expect(status.favicon).to eq 'favicon_pending'
+ expect(status.illustration).to include(:image, :size, :title)
+ expect(status).not_to have_details
+ end
+ end
+
private
- def create_bridge(trait)
+ def create_bridge(*traits)
upstream_project = create(:project, :repository)
downstream_project = create(:project, :repository)
upstream_pipeline = create(:ci_pipeline, :running, project: upstream_project)
trigger = { trigger: { project: downstream_project.full_path, branch: 'feature' } }
- create(:ci_bridge, trait, options: trigger, pipeline: upstream_pipeline)
+ create(:ci_bridge, *traits, options: trigger, pipeline: upstream_pipeline)
end
end
diff --git a/spec/lib/gitlab/ci/status/bridge/waiting_for_resource_spec.rb b/spec/lib/gitlab/ci/status/bridge/waiting_for_resource_spec.rb
new file mode 100644
index 00000000000..3e19df28d83
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/bridge/waiting_for_resource_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::Bridge::WaitingForResource do
+ it { expect(described_class).to be < Gitlab::Ci::Status::Processable::WaitingForResource }
+end
diff --git a/spec/lib/gitlab/ci/status/build/waiting_for_resource_spec.rb b/spec/lib/gitlab/ci/status/build/waiting_for_resource_spec.rb
new file mode 100644
index 00000000000..44bd5a8611a
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/waiting_for_resource_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::Build::WaitingForResource do
+ it { expect(described_class).to be < Gitlab::Ci::Status::Processable::WaitingForResource }
+end
diff --git a/spec/lib/gitlab/ci/status/processable/waiting_for_resource_spec.rb b/spec/lib/gitlab/ci/status/processable/waiting_for_resource_spec.rb
new file mode 100644
index 00000000000..91a9724d043
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/processable/waiting_for_resource_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::Processable::WaitingForResource do
+ let(:user) { create(:user) }
+
+ subject do
+ processable = create(:ci_build, :waiting_for_resource, :resource_group)
+ described_class.new(Gitlab::Ci::Status::Core.new(processable, user))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(processable, user) }
+
+ context 'when processable is waiting for resource' do
+ let(:processable) { create(:ci_build, :waiting_for_resource) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when processable is not waiting for resource' do
+ let(:processable) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
index a2903391c6f..f09e03b4d55 100644
--- a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
+++ b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
let(:chunked_io) { described_class.new(build) }
before do
- stub_feature_flags(ci_enable_live_trace: true)
+ stub_feature_flags(ci_enable_live_trace: true, gitlab_ci_trace_read_consistency: true)
end
describe "#initialize" do
diff --git a/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb b/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
index d85bf29f77f..954273fd41e 100644
--- a/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
@@ -5,8 +5,11 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
describe '#errors' do
context 'when FF :variable_inside_variable is disabled' do
+ let_it_be(:project_with_flag_disabled) { create(:project) }
+ let_it_be(:project_with_flag_enabled) { create(:project) }
+
before do
- stub_feature_flags(variable_inside_variable: false)
+ stub_feature_flags(variable_inside_variable: [project_with_flag_enabled])
end
context 'table tests' do
@@ -53,7 +56,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project_with_flag_disabled) }
it 'does not report error' do
expect(subject.errors).to eq(nil)
@@ -67,8 +70,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
context 'when FF :variable_inside_variable is enabled' do
+ let_it_be(:project_with_flag_disabled) { create(:project) }
+ let_it_be(:project_with_flag_enabled) { create(:project) }
+
before do
- stub_feature_flags(variable_inside_variable: true)
+ stub_feature_flags(variable_inside_variable: [project_with_flag_enabled])
end
context 'table tests' do
@@ -100,7 +106,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project_with_flag_enabled) }
it 'errors matches expected validation result' do
expect(subject.errors).to eq(validation_result)
@@ -164,7 +170,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ let_it_be(:project) { create(:project) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project) }
it 'does not expand variables' do
expect(subject.sort).to eq(variables)
@@ -239,7 +246,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ let_it_be(:project) { create(:project) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project) }
it 'sort returns correctly sorted variables' do
expect(subject.sort.map { |var| var[:key] }).to eq(result)
diff --git a/spec/lib/gitlab/ci/variables/helpers_spec.rb b/spec/lib/gitlab/ci/variables/helpers_spec.rb
new file mode 100644
index 00000000000..b45abf8c0e1
--- /dev/null
+++ b/spec/lib/gitlab/ci/variables/helpers_spec.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Variables::Helpers do
+ describe '.merge_variables' do
+ let(:current_variables) do
+ [{ key: 'key1', value: 'value1' },
+ { key: 'key2', value: 'value2' }]
+ end
+
+ let(:new_variables) do
+ [{ key: 'key2', value: 'value22' },
+ { key: 'key3', value: 'value3' }]
+ end
+
+ let(:result) do
+ [{ key: 'key1', value: 'value1', public: true },
+ { key: 'key2', value: 'value22', public: true },
+ { key: 'key3', value: 'value3', public: true }]
+ end
+
+ subject { described_class.merge_variables(current_variables, new_variables) }
+
+ it { is_expected.to eq(result) }
+
+ context 'when new variables is a hash' do
+ let(:new_variables) do
+ { 'key2' => 'value22', 'key3' => 'value3' }
+ end
+
+ it { is_expected.to eq(result) }
+ end
+
+ context 'when new variables is a hash with symbol keys' do
+ let(:new_variables) do
+ { key2: 'value22', key3: 'value3' }
+ end
+
+ it { is_expected.to eq(result) }
+ end
+
+ context 'when new variables is nil' do
+ let(:new_variables) {}
+ let(:result) do
+ [{ key: 'key1', value: 'value1', public: true },
+ { key: 'key2', value: 'value2', public: true }]
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ describe '.transform_to_yaml_variables' do
+ let(:variables) do
+ { 'key1' => 'value1', 'key2' => 'value2' }
+ end
+
+ let(:result) do
+ [{ key: 'key1', value: 'value1', public: true },
+ { key: 'key2', value: 'value2', public: true }]
+ end
+
+ subject { described_class.transform_to_yaml_variables(variables) }
+
+ it { is_expected.to eq(result) }
+
+ context 'when variables is nil' do
+ let(:variables) {}
+
+ it { is_expected.to eq([]) }
+ end
+ end
+
+ describe '.transform_from_yaml_variables' do
+ let(:variables) do
+ [{ key: 'key1', value: 'value1', public: true },
+ { key: 'key2', value: 'value2', public: true }]
+ end
+
+ let(:result) do
+ { 'key1' => 'value1', 'key2' => 'value2' }
+ end
+
+ subject { described_class.transform_from_yaml_variables(variables) }
+
+ it { is_expected.to eq(result) }
+
+ context 'when variables is nil' do
+ let(:variables) {}
+
+ it { is_expected.to eq({}) }
+ end
+
+ context 'when variables is a hash' do
+ let(:variables) do
+ { key1: 'value1', 'key2' => 'value2' }
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
+end