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>2022-07-20 18:40:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 18:40:28 +0300
commitb595cb0c1dec83de5bdee18284abe86614bed33b (patch)
tree8c3d4540f193c5ff98019352f554e921b3a41a72 /spec/lib/gitlab/ci
parent2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff)
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/build/duration_parser_spec.rb (renamed from spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb64
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/config/external/context_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/jwt_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb48
-rw-r--r--spec/lib/gitlab/ci/reports/coverage_report_generator_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/reports/test_report_spec.rb (renamed from spec/lib/gitlab/ci/reports/test_reports_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/runner/metrics_spec.rb41
-rw-r--r--spec/lib/gitlab/ci/runner_releases_spec.rb196
-rw-r--r--spec/lib/gitlab/ci/runner_upgrade_check_spec.rb170
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/status/stage/play_manual_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/tags/bulk_insert_spec.rb70
-rw-r--r--spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/variables/builder_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/feature_flags_spec.rb80
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb94
33 files changed, 859 insertions, 207 deletions
diff --git a/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb b/spec/lib/gitlab/ci/build/duration_parser_spec.rb
index 889878cf3ef..7f5ff1eb0ee 100644
--- a/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb
+++ b/spec/lib/gitlab/ci/build/duration_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::Artifacts::ExpireInParser do
+RSpec.describe Gitlab::Ci::Build::DurationParser do
describe '.validate_duration', :request_store do
subject { described_class.validate_duration(value) }
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index 8f77a1f60ad..4895077a731 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -98,9 +98,11 @@ RSpec.describe Gitlab::Ci::Build::Image do
let(:service_entrypoint) { '/bin/sh' }
let(:service_alias) { 'db' }
let(:service_command) { 'sleep 30' }
+ let(:pull_policy) { %w[always if-not-present] }
let(:job) do
create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint,
- alias: service_alias, command: service_command, ports: [80] }] })
+ alias: service_alias, command: service_command, ports: [80],
+ pull_policy: pull_policy }] })
end
it 'fabricates an non-empty array of objects' do
@@ -114,6 +116,7 @@ RSpec.describe Gitlab::Ci::Build::Image do
expect(subject.first.entrypoint).to eq(service_entrypoint)
expect(subject.first.alias).to eq(service_alias)
expect(subject.first.command).to eq(service_command)
+ expect(subject.first.pull_policy).to eq(pull_policy)
port = subject.first.ports.first
expect(port.number).to eq 80
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
index 4ac8bf61738..3892b88598a 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
@@ -6,19 +6,43 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
describe '#satisfied_by?' do
subject { described_class.new(globs).satisfied_by?(pipeline, context) }
- it_behaves_like 'a glob matching rule' do
+ context 'a glob matching rule' do
+ using RSpec::Parameterized::TableSyntax
+
let(:pipeline) { build(:ci_pipeline) }
let(:context) {}
before do
allow(pipeline).to receive(:modified_paths).and_return(files.keys)
end
+
+ # rubocop:disable Layout/LineLength
+ where(:case_name, :globs, :files, :satisfied) do
+ 'exact top-level match' | ['Dockerfile'] | { 'Dockerfile' => '', 'Gemfile' => '' } | true
+ 'exact top-level match' | { paths: ['Dockerfile'] } | { 'Dockerfile' => '', 'Gemfile' => '' } | true
+ 'exact top-level no match' | { paths: ['Dockerfile'] } | { 'Gemfile' => '' } | false
+ 'pattern top-level match' | { paths: ['Docker*'] } | { 'Dockerfile' => '', 'Gemfile' => '' } | true
+ 'pattern top-level no match' | ['Docker*'] | { 'Gemfile' => '' } | false
+ 'pattern top-level no match' | { paths: ['Docker*'] } | { 'Gemfile' => '' } | false
+ 'exact nested match' | { paths: ['project/build.properties'] } | { 'project/build.properties' => '' } | true
+ 'exact nested no match' | { paths: ['project/build.properties'] } | { 'project/README.md' => '' } | false
+ 'pattern nested match' | { paths: ['src/**/*.go'] } | { 'src/gitlab.com/goproject/goproject.go' => '' } | true
+ 'pattern nested no match' | { paths: ['src/**/*.go'] } | { 'src/gitlab.com/goproject/README.md' => '' } | false
+ 'ext top-level match' | { paths: ['*.go'] } | { 'main.go' => '', 'cmd/goproject/main.go' => '' } | true
+ 'ext nested no match' | { paths: ['*.go'] } | { 'cmd/goproject/main.go' => '' } | false
+ 'ext slash no match' | { paths: ['/*.go'] } | { 'main.go' => '', 'cmd/goproject/main.go' => '' } | false
+ end
+ # rubocop:enable Layout/LineLength
+
+ with_them do
+ it { is_expected.to eq(satisfied) }
+ end
end
context 'when pipeline is nil' do
let(:pipeline) {}
let(:context) {}
- let(:globs) { [] }
+ let(:globs) { { paths: [] } }
it { is_expected.to be_truthy }
end
@@ -26,8 +50,8 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
context 'when using variable expansion' do
let(:pipeline) { build(:ci_pipeline) }
let(:modified_paths) { ['helm/test.txt'] }
- let(:globs) { ['$HELM_DIR/**/*'] }
- let(:context) { double('context') }
+ let(:globs) { { paths: ['$HELM_DIR/**/*'] } }
+ let(:context) { instance_double(Gitlab::Ci::Build::Context::Base) }
before do
allow(pipeline).to receive(:modified_paths).and_return(modified_paths)
@@ -58,7 +82,7 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
end
context 'when variable expansion does not match' do
- let(:globs) { ['path/with/$in/it/*'] }
+ let(:globs) { { paths: ['path/with/$in/it/*'] } }
let(:modified_paths) { ['path/with/$in/it/file.txt'] }
before do
diff --git a/spec/lib/gitlab/ci/build/rules/rule_spec.rb b/spec/lib/gitlab/ci/build/rules/rule_spec.rb
index f905e229415..ac73b665f3a 100644
--- a/spec/lib/gitlab/ci/build/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule_spec.rb
@@ -14,10 +14,14 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule do
let(:ci_build) { build(:ci_build, pipeline: pipeline) }
let(:rule) { described_class.new(rule_hash) }
+ before do
+ allow(pipeline).to receive(:modified_paths).and_return(['file.rb'])
+ end
+
describe '#matches?' do
subject { rule.matches?(pipeline, seed) }
- context 'with one matching clause' do
+ context 'with one matching clause if' do
let(:rule_hash) do
{ if: '$VAR == null', when: 'always' }
end
@@ -25,9 +29,17 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule do
it { is_expected.to eq(true) }
end
+ context 'with one matching clause changes' do
+ let(:rule_hash) do
+ { changes: { paths: ['**/*'] }, when: 'always' }
+ end
+
+ it { is_expected.to eq(true) }
+ end
+
context 'with two matching clauses' do
let(:rule_hash) do
- { if: '$VAR == null', changes: '**/*', when: 'always' }
+ { if: '$VAR == null', changes: { paths: ['**/*'] }, when: 'always' }
end
it { is_expected.to eq(true) }
@@ -35,7 +47,7 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule do
context 'with a matching and non-matching clause' do
let(:rule_hash) do
- { if: '$VAR != null', changes: '$VAR == null', when: 'always' }
+ { if: '$VAR != null', changes: { paths: ['invalid.xyz'] }, when: 'always' }
end
it { is_expected.to eq(false) }
@@ -43,7 +55,7 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule do
context 'with two non-matching clauses' do
let(:rule_hash) do
- { if: '$VAR != null', changes: 'README', when: 'always' }
+ { if: '$VAR != null', changes: { paths: ['README'] }, when: 'always' }
end
it { is_expected.to eq(false) }
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index bd1ab5d8c41..0fa6d4f8804 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -9,6 +9,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
before do
stub_feature_flags(ci_docker_image_pull_policy: true)
+
+ entry.compose!
end
let(:entry) { described_class.new(config) }
@@ -129,19 +131,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
describe '#valid?' do
it 'is valid' do
- entry.compose!
-
expect(entry).to be_valid
end
context 'when the feature flag ci_docker_image_pull_policy is disabled' do
before do
stub_feature_flags(ci_docker_image_pull_policy: false)
+ entry.compose!
end
it 'is not valid' do
- entry.compose!
-
expect(entry).not_to be_valid
expect(entry.errors).to include('image config contains unknown keys: pull_policy')
end
@@ -150,8 +149,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
describe '#value' do
it "returns value" do
- entry.compose!
-
expect(entry.value).to eq(
name: 'image:1.0',
pull_policy: ['if-not-present']
@@ -161,11 +158,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
context 'when the feature flag ci_docker_image_pull_policy is disabled' do
before do
stub_feature_flags(ci_docker_image_pull_policy: false)
+ entry.compose!
end
it 'is not valid' do
- entry.compose!
-
expect(entry.value).to eq(
name: 'image:1.0'
)
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb
index 3ed4a9f263f..295561b3c4d 100644
--- a/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule::Changes do
it { is_expected.not_to be_valid }
it 'reports an error about invalid policy' do
- expect(entry.errors).to include(/should be an array of strings/)
+ expect(entry.errors).to include(/should be an array or a hash/)
end
end
@@ -64,7 +64,59 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule::Changes do
it 'returns information about errors' do
expect(entry.errors)
- .to include(/should be an array of strings/)
+ .to include(/should be an array or a hash/)
+ end
+ end
+
+ context 'with paths' do
+ context 'when paths is an array of strings' do
+ let(:config) { { paths: %w[app/ lib/] } }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when paths is not an array' do
+ let(:config) { { paths: 'string' } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns information about errors' do
+ expect(entry.errors)
+ .to include(/should be an array of strings/)
+ end
+ end
+
+ context 'when paths is an array of integers' do
+ let(:config) { { paths: [1, 2] } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns information about errors' do
+ expect(entry.errors)
+ .to include(/should be an array of strings/)
+ end
+ end
+
+ context 'when paths is an array of long strings' do
+ let(:config) { { paths: ['a'] * 51 } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns information about errors' do
+ expect(entry.errors)
+ .to include(/has too many entries \(maximum 50\)/)
+ end
+ end
+
+ context 'when paths is nil' do
+ let(:config) { { paths: nil } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns information about errors' do
+ expect(entry.errors)
+ .to include(/should be an array of strings/)
+ end
end
end
end
@@ -75,6 +127,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule::Changes do
context 'when using a string array' do
let(:config) { %w[app/ lib/ spec/ other/* paths/**/*.rb] }
+ it { is_expected.to eq(paths: config) }
+ end
+
+ context 'with paths' do
+ let(:config) do
+ { paths: ['app/', 'lib/'] }
+ end
+
it { is_expected.to eq(config) }
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
index 89d349efe8f..93f4a66bfb6 100644
--- a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
@@ -115,7 +115,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.not_to be_valid }
it 'reports an error about invalid policy' do
- expect(subject.errors).to include(/should be an array of strings/)
+ expect(subject.errors).to include(/should be an array or a hash/)
end
end
@@ -411,7 +411,13 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
context 'when using a changes: clause' do
let(:config) { { changes: %w[app/ lib/ spec/ other/* paths/**/*.rb] } }
- it { is_expected.to eq(config) }
+ it { is_expected.to eq(changes: { paths: %w[app/ lib/ spec/ other/* paths/**/*.rb] }) }
+
+ context 'when using changes with paths' do
+ let(:config) { { changes: { paths: %w[app/ lib/ spec/ other/* paths/**/*.rb] } } }
+
+ it { is_expected.to eq(config) }
+ end
end
context 'when default value has been provided' do
@@ -426,7 +432,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
end
it 'does not add to provided configuration' do
- expect(entry.value).to eq(config)
+ expect(entry.value).to eq(changes: { paths: %w[app/**/*.rb] })
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/rules_spec.rb b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
index cfec33003e4..b0871f2345e 100644
--- a/spec/lib/gitlab/ci/config/entry/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
-require 'support/helpers/stub_feature_flags'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Rules do
@@ -12,13 +11,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
end
let(:metadata) { { allowed_when: %w[always never] } }
- let(:entry) { factory.create! }
- describe '.new' do
- subject { entry }
+ subject(:entry) { factory.create! }
+ describe '.new' do
before do
- subject.compose!
+ entry.compose!
end
context 'with a list of rule rule' do
@@ -73,7 +71,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
end
describe '#value' do
- subject { entry.value }
+ subject(:value) { entry.value }
+
+ before do
+ entry.compose!
+ end
context 'with a list of rule rule' do
let(:config) do
@@ -99,7 +101,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
{ if: '$SKIP', when: 'never' }
end
- it { is_expected.to eq([config]) }
+ it { is_expected.to eq([]) }
end
context 'with nested rules' do
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index 2795cc9dddf..3c000fd09ed 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -1,14 +1,19 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'fast_spec_helper'
+require 'support/helpers/stubbed_feature'
+require 'support/helpers/stub_feature_flags'
RSpec.describe Gitlab::Ci::Config::Entry::Service do
- let(:entry) { described_class.new(config) }
+ include StubFeatureFlags
before do
+ stub_feature_flags(ci_docker_image_pull_policy: true)
entry.compose!
end
+ subject(:entry) { described_class.new(config) }
+
context 'when configuration is a string' do
let(:config) { 'postgresql:9.5' }
@@ -90,6 +95,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
end
end
+ describe '#pull_policy' do
+ it "returns nil" do
+ expect(entry.pull_policy).to be_nil
+ end
+ end
+
context 'when configuration has ports' do
let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] }
let(:config) do
@@ -134,6 +145,49 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
end
end
end
+
+ context 'when configuration has pull_policy' do
+ let(:config) { { name: 'postgresql:9.5', pull_policy: 'if-not-present' } }
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+
+ context 'when the feature flag ci_docker_image_pull_policy is disabled' do
+ before do
+ stub_feature_flags(ci_docker_image_pull_policy: false)
+ entry.compose!
+ end
+
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include('service config contains unknown keys: pull_policy')
+ end
+ end
+ end
+
+ describe '#value' do
+ it "returns value" do
+ expect(entry.value).to eq(
+ name: 'postgresql:9.5',
+ pull_policy: ['if-not-present']
+ )
+ end
+
+ context 'when the feature flag ci_docker_image_pull_policy is disabled' do
+ before do
+ stub_feature_flags(ci_docker_image_pull_policy: false)
+ end
+
+ it 'is not valid' do
+ expect(entry.value).to eq(
+ name: 'postgresql:9.5'
+ )
+ end
+ end
+ end
+ end
end
context 'when entry value is not correct' do
diff --git a/spec/lib/gitlab/ci/config/external/context_spec.rb b/spec/lib/gitlab/ci/config/external/context_spec.rb
index 800c563cd0b..40702e75404 100644
--- a/spec/lib/gitlab/ci/config/external/context_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/context_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::External::Context do
- let(:project) { double('Project') }
+ let(:project) { build(:project) }
let(:user) { double('User') }
let(:sha) { '12345' }
let(:variables) { Gitlab::Ci::Variables::Collection.new([{ 'key' => 'a', 'value' => 'b' }]) }
@@ -126,7 +126,7 @@ RSpec.describe Gitlab::Ci::Config::External::Context do
end
context 'with attributes' do
- let(:new_attributes) { { project: double, user: double, sha: '56789' } }
+ let(:new_attributes) { { project: build(:project), user: double, sha: '56789' } }
it_behaves_like 'a mutated context'
end
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index 77e542cf933..72a85c9b03d 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -177,6 +177,22 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
expect(project_file.error_message).to include("Project `xxxxxxxxxxxxxxxxxxxxxxx` not found or access denied!")
end
end
+
+ context 'when a project contained in an array is used with a masked variable' do
+ let(:variables) do
+ Gitlab::Ci::Variables::Collection.new([
+ { key: 'VAR1', value: 'a_secret_variable_value', masked: true }
+ ])
+ end
+
+ let(:params) do
+ { project: ['a_secret_variable_value'], file: '/file.yml' }
+ end
+
+ it 'does not raise an error' do
+ expect { valid? }.not_to raise_error
+ end
+ end
end
describe '#expand_context' do
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index 7e1b31fea6a..e74fdc2071b 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -232,11 +232,9 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
image: 'image:1.0' }
end
- before do
- stub_const("#{described_class}::MAX_INCLUDES", 2)
- end
-
it 'does not raise an exception' do
+ allow(context).to receive(:max_includes).and_return(2)
+
expect { subject }.not_to raise_error
end
end
@@ -250,11 +248,9 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
image: 'image:1.0' }
end
- before do
- stub_const("#{described_class}::MAX_INCLUDES", 1)
- end
-
it 'raises an exception' do
+ allow(context).to receive(:max_includes).and_return(1)
+
expect { subject }.to raise_error(described_class::TooManyIncludesError)
end
@@ -264,6 +260,8 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
end
it 'raises an exception' do
+ allow(context).to receive(:max_includes).and_return(1)
+
expect { subject }.to raise_error(described_class::TooManyIncludesError)
end
end
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 15a0ff40aa4..841a46e197d 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -323,11 +323,9 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
end
context 'when too many includes is included' do
- before do
- stub_const('Gitlab::Ci::Config::External::Mapper::MAX_INCLUDES', 1)
- end
-
it 'raises an error' do
+ allow(context).to receive(:max_includes).and_return(1)
+
expect { subject }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError, /Maximum of 1 nested/)
end
end
diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb
index 179e2efc0c7..147801b6217 100644
--- a/spec/lib/gitlab/ci/jwt_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_spec.rb
@@ -48,6 +48,7 @@ RSpec.describe Gitlab::Ci::Jwt do
expect(payload[:ref_protected]).to eq(build.protected.to_s)
expect(payload[:environment]).to be_nil
expect(payload[:environment_protected]).to be_nil
+ expect(payload[:deployment_tier]).to be_nil
end
end
@@ -96,7 +97,7 @@ RSpec.describe Gitlab::Ci::Jwt do
end
describe 'environment' do
- let(:environment) { build_stubbed(:environment, project: project, name: 'production') }
+ let(:environment) { build_stubbed(:environment, project: project, name: 'production', tier: 'production') }
let(:build) do
build_stubbed(
:ci_build,
@@ -114,6 +115,19 @@ RSpec.describe Gitlab::Ci::Jwt do
it 'has correct values for environment attributes' do
expect(payload[:environment]).to eq('production')
expect(payload[:environment_protected]).to eq('false')
+ expect(payload[:deployment_tier]).to eq('production')
+ end
+
+ describe 'deployment_tier' do
+ context 'when build options specifies a different deployment_tier' do
+ before do
+ build.options[:environment] = { name: environment.name, deployment_tier: 'development' }
+ end
+
+ it 'uses deployment_tier from build options' do
+ expect(payload[:deployment_tier]).to eq('development')
+ end
+ end
end
end
end
@@ -121,8 +135,8 @@ RSpec.describe Gitlab::Ci::Jwt do
describe '.for_build' do
shared_examples 'generating JWT for build' do
context 'when signing key is present' do
- let(:rsa_key) { OpenSSL::PKey::RSA.generate(1024) }
- let(:rsa_key_data) { rsa_key.to_s }
+ let_it_be(:rsa_key) { OpenSSL::PKey::RSA.generate(3072) }
+ let_it_be(:rsa_key_data) { rsa_key.to_s }
it 'generates JWT with key id' do
_payload, headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
index 375841ce236..cbf92f8fa83 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CreateDeployments do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- let(:stage) { build(:ci_stage_entity, project: project, statuses: [job]) }
+ let(:stage) { build(:ci_stage, project: project, statuses: [job]) }
let(:pipeline) { create(:ci_pipeline, project: project, stages: [stage]) }
let(:command) do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
index 9057c4e99df..eba0db0adfb 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Create do
context 'tags persistence' do
let(:stage) do
- build(:ci_stage_entity, pipeline: pipeline, project: project)
+ build(:ci_stage, pipeline: pipeline, project: project)
end
let(:job) do
@@ -77,7 +77,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Create do
context 'without tags' do
it 'extracts an empty tag list' do
- expect(CommitStatus)
+ expect(Gitlab::Ci::Tags::BulkInsert)
.to receive(:bulk_insert_tags!)
.with([job])
.and_call_original
@@ -95,7 +95,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Create do
end
it 'bulk inserts tags' do
- expect(CommitStatus)
+ expect(Gitlab::Ci::Tags::BulkInsert)
.to receive(:bulk_insert_tags!)
.with([job])
.and_call_original
diff --git a/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
index 6a7d9b58a05..e07a3ca9033 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::EnsureEnvironments do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:stage) { build(:ci_stage_entity, project: project, statuses: [job]) }
+ let(:stage) { build(:ci_stage, project: project, statuses: [job]) }
let(:pipeline) { build(:ci_pipeline, project: project, stages: [stage]) }
let(:command) do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
index 571455d6279..f14dd70a753 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::EnsureResourceGroups do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:stage) { build(:ci_stage_entity, project: project, statuses: [job]) }
+ let(:stage) { build(:ci_stage, project: project, statuses: [job]) }
let(:pipeline) { build(:ci_pipeline, project: project, stages: [stage]) }
let!(:environment) { create(:environment, name: 'production', project: project) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index cebc4c02d11..eeac0c85a77 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
end
- it 'respects the defined payload schema', :saas do
+ it 'respects the defined payload schema' do
expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
expect(params[:body]).to match_schema('/external_validation')
expect(params[:timeout]).to eq(described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT)
@@ -235,6 +235,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
it 'logs the authorization' do
+ allow(Gitlab::AppLogger).to receive(:info)
+
expect(Gitlab::AppLogger).to receive(:info).with(message: 'Pipeline not authorized', project_id: project.id, user_id: user.id)
perform!
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 49505d397c2..040f3ab5830 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -858,14 +858,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'with an explicit `when: never`' do
where(:rule_set) do
[
- [[{ changes: %w[*/**/*.rb], when: 'never' }, { changes: %w[*/**/*.rb], when: 'always' }]],
- [[{ changes: %w[app/models/ci/pipeline.rb], when: 'never' }, { changes: %w[app/models/ci/pipeline.rb], when: 'always' }]],
- [[{ changes: %w[spec/**/*.rb], when: 'never' }, { changes: %w[spec/**/*.rb], when: 'always' }]],
- [[{ changes: %w[*.yml], when: 'never' }, { changes: %w[*.yml], when: 'always' }]],
- [[{ changes: %w[.*.yml], when: 'never' }, { changes: %w[.*.yml], when: 'always' }]],
- [[{ changes: %w[**/*], when: 'never' }, { changes: %w[**/*], when: 'always' }]],
- [[{ changes: %w[*/**/*.rb *.yml], when: 'never' }, { changes: %w[*/**/*.rb *.yml], when: 'always' }]],
- [[{ changes: %w[.*.yml **/*], when: 'never' }, { changes: %w[.*.yml **/*], when: 'always' }]]
+ [[{ changes: { paths: %w[*/**/*.rb] }, when: 'never' }, { changes: { paths: %w[*/**/*.rb] }, when: 'always' }]],
+ [[{ changes: { paths: %w[app/models/ci/pipeline.rb] }, when: 'never' }, { changes: { paths: %w[app/models/ci/pipeline.rb] }, when: 'always' }]],
+ [[{ changes: { paths: %w[spec/**/*.rb] }, when: 'never' }, { changes: { paths: %w[spec/**/*.rb] }, when: 'always' }]],
+ [[{ changes: { paths: %w[*.yml] }, when: 'never' }, { changes: { paths: %w[*.yml] }, when: 'always' }]],
+ [[{ changes: { paths: %w[.*.yml] }, when: 'never' }, { changes: { paths: %w[.*.yml] }, when: 'always' }]],
+ [[{ changes: { paths: %w[**/*] }, when: 'never' }, { changes: { paths: %w[**/*] }, when: 'always' }]],
+ [[{ changes: { paths: %w[*/**/*.rb *.yml] }, when: 'never' }, { changes: { paths: %w[*/**/*.rb *.yml] }, when: 'always' }]],
+ [[{ changes: { paths: %w[.*.yml **/*] }, when: 'never' }, { changes: { paths: %w[.*.yml **/*] }, when: 'always' }]]
]
end
@@ -881,14 +881,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'with an explicit `when: always`' do
where(:rule_set) do
[
- [[{ changes: %w[*/**/*.rb], when: 'always' }, { changes: %w[*/**/*.rb], when: 'never' }]],
- [[{ changes: %w[app/models/ci/pipeline.rb], when: 'always' }, { changes: %w[app/models/ci/pipeline.rb], when: 'never' }]],
- [[{ changes: %w[spec/**/*.rb], when: 'always' }, { changes: %w[spec/**/*.rb], when: 'never' }]],
- [[{ changes: %w[*.yml], when: 'always' }, { changes: %w[*.yml], when: 'never' }]],
- [[{ changes: %w[.*.yml], when: 'always' }, { changes: %w[.*.yml], when: 'never' }]],
- [[{ changes: %w[**/*], when: 'always' }, { changes: %w[**/*], when: 'never' }]],
- [[{ changes: %w[*/**/*.rb *.yml], when: 'always' }, { changes: %w[*/**/*.rb *.yml], when: 'never' }]],
- [[{ changes: %w[.*.yml **/*], when: 'always' }, { changes: %w[.*.yml **/*], when: 'never' }]]
+ [[{ changes: { paths: %w[*/**/*.rb] }, when: 'always' }, { changes: { paths: %w[*/**/*.rb] }, when: 'never' }]],
+ [[{ changes: { paths: %w[app/models/ci/pipeline.rb] }, when: 'always' }, { changes: { paths: %w[app/models/ci/pipeline.rb] }, when: 'never' }]],
+ [[{ changes: { paths: %w[spec/**/*.rb] }, when: 'always' }, { changes: { paths: %w[spec/**/*.rb] }, when: 'never' }]],
+ [[{ changes: { paths: %w[*.yml] }, when: 'always' }, { changes: { paths: %w[*.yml] }, when: 'never' }]],
+ [[{ changes: { paths: %w[.*.yml] }, when: 'always' }, { changes: { paths: %w[.*.yml] }, when: 'never' }]],
+ [[{ changes: { paths: %w[**/*] }, when: 'always' }, { changes: { paths: %w[**/*] }, when: 'never' }]],
+ [[{ changes: { paths: %w[*/**/*.rb *.yml] }, when: 'always' }, { changes: { paths: %w[*/**/*.rb *.yml] }, when: 'never' }]],
+ [[{ changes: { paths: %w[.*.yml **/*] }, when: 'always' }, { changes: { paths: %w[.*.yml **/*] }, when: 'never' }]]
]
end
@@ -904,14 +904,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'without an explicit when: value' do
where(:rule_set) do
[
- [[{ changes: %w[*/**/*.rb] }]],
- [[{ changes: %w[app/models/ci/pipeline.rb] }]],
- [[{ changes: %w[spec/**/*.rb] }]],
- [[{ changes: %w[*.yml] }]],
- [[{ changes: %w[.*.yml] }]],
- [[{ changes: %w[**/*] }]],
- [[{ changes: %w[*/**/*.rb *.yml] }]],
- [[{ changes: %w[.*.yml **/*] }]]
+ [[{ changes: { paths: %w[*/**/*.rb] } }]],
+ [[{ changes: { paths: %w[app/models/ci/pipeline.rb] } }]],
+ [[{ changes: { paths: %w[spec/**/*.rb] } }]],
+ [[{ changes: { paths: %w[*.yml] } }]],
+ [[{ changes: { paths: %w[.*.yml] } }]],
+ [[{ changes: { paths: %w[**/*] } }]],
+ [[{ changes: { paths: %w[*/**/*.rb *.yml] } }]],
+ [[{ changes: { paths: %w[.*.yml **/*] } }]]
]
end
diff --git a/spec/lib/gitlab/ci/reports/coverage_report_generator_spec.rb b/spec/lib/gitlab/ci/reports/coverage_report_generator_spec.rb
index eec218346c2..f116b175fc7 100644
--- a/spec/lib/gitlab/ci/reports/coverage_report_generator_spec.rb
+++ b/spec/lib/gitlab/ci/reports/coverage_report_generator_spec.rb
@@ -75,16 +75,6 @@ RSpec.describe Gitlab::Ci::Reports::CoverageReportGenerator, factory_default: :k
end
it_behaves_like 'having a coverage report'
-
- context 'when feature flag ci_child_pipeline_coverage_reports is disabled' do
- before do
- stub_feature_flags(ci_child_pipeline_coverage_reports: false)
- end
-
- it 'returns empty coverage reports' do
- expect(subject).to be_empty
- end
- end
end
context 'when both parent and child pipeline have builds with coverage reports' do
diff --git a/spec/lib/gitlab/ci/reports/test_reports_spec.rb b/spec/lib/gitlab/ci/reports/test_report_spec.rb
index 24c00de3731..539510bca9e 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_report_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Reports::TestReports do
+RSpec.describe Gitlab::Ci::Reports::TestReport do
include TestReportsHelper
let(:test_reports) { described_class.new }
diff --git a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
index 3483dddca3a..ac64e4699fe 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe Gitlab::Ci::Reports::TestReportsComparer do
include TestReportsHelper
let(:comparer) { described_class.new(base_reports, head_reports) }
- let(:base_reports) { Gitlab::Ci::Reports::TestReports.new }
- let(:head_reports) { Gitlab::Ci::Reports::TestReports.new }
+ let(:base_reports) { Gitlab::Ci::Reports::TestReport.new }
+ let(:head_reports) { Gitlab::Ci::Reports::TestReport.new }
describe '#suite_comparers' do
subject { comparer.suite_comparers }
diff --git a/spec/lib/gitlab/ci/runner/metrics_spec.rb b/spec/lib/gitlab/ci/runner/metrics_spec.rb
new file mode 100644
index 00000000000..3c459271092
--- /dev/null
+++ b/spec/lib/gitlab/ci/runner/metrics_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Runner::Metrics, :prometheus do
+ subject { described_class.new }
+
+ describe '#increment_runner_authentication_success_counter' do
+ it 'increments count for same type' do
+ expect { subject.increment_runner_authentication_success_counter(runner_type: 'instance_type') }
+ .to change { described_class.runner_authentication_success_counter.get(runner_type: 'instance_type') }.by(1)
+ end
+
+ it 'does not increment count for different type' do
+ expect { subject.increment_runner_authentication_success_counter(runner_type: 'group_type') }
+ .to not_change { described_class.runner_authentication_success_counter.get(runner_type: 'project_type') }
+ end
+
+ it 'does not increment failure count' do
+ expect { subject.increment_runner_authentication_success_counter(runner_type: 'project_type') }
+ .to not_change { described_class.runner_authentication_failure_counter.get }
+ end
+
+ it 'throws ArgumentError for invalid runner type' do
+ expect { subject.increment_runner_authentication_success_counter(runner_type: 'unknown_type') }
+ .to raise_error(ArgumentError, 'unknown runner type: unknown_type')
+ end
+ end
+
+ describe '#increment_runner_authentication_failure_counter' do
+ it 'increments count' do
+ expect { subject.increment_runner_authentication_failure_counter }
+ .to change { described_class.runner_authentication_failure_counter.get }.by(1)
+ end
+
+ it 'does not increment success count' do
+ expect { subject.increment_runner_authentication_failure_counter }
+ .to not_change { described_class.runner_authentication_success_counter.get(runner_type: 'instance_type') }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/runner_releases_spec.rb b/spec/lib/gitlab/ci/runner_releases_spec.rb
index 9e4a8739c0f..576eb02ad83 100644
--- a/spec/lib/gitlab/ci/runner_releases_spec.rb
+++ b/spec/lib/gitlab/ci/runner_releases_spec.rb
@@ -5,16 +5,25 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::RunnerReleases do
subject { described_class.instance }
- describe '#releases' do
- before do
- subject.reset!
+ let(:runner_releases_url) { 'the release API URL' }
- stub_application_setting(public_runner_releases_url: 'the release API URL')
- allow(Gitlab::HTTP).to receive(:try_get).with('the release API URL').once { mock_http_response(response) }
- end
+ def releases
+ subject.releases
+ end
+
+ def releases_by_minor
+ subject.releases_by_minor
+ end
+
+ before do
+ subject.reset_backoff!
- def releases
- subject.releases
+ stub_application_setting(public_runner_releases_url: runner_releases_url)
+ end
+
+ describe 'caching behavior', :use_clean_rails_memory_store_caching do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(runner_releases_url, anything).once { mock_http_response(response) }
end
shared_examples 'requests that follow cache status' do |validity_period|
@@ -25,9 +34,14 @@ RSpec.describe Gitlab::Ci::RunnerReleases do
releases
travel followup_request_interval do
- expect(Gitlab::HTTP).not_to receive(:try_get)
+ expect(Gitlab::HTTP).not_to receive(:get)
- expect(releases).to eq(expected_result)
+ if expected_releases
+ expected_result_by_minor = expected_releases.group_by(&:without_patch).transform_values(&:max)
+ end
+
+ expect(releases).to eq(expected_releases)
+ expect(releases_by_minor).to eq(expected_result_by_minor)
end
end
end
@@ -40,75 +54,189 @@ RSpec.describe Gitlab::Ci::RunnerReleases do
releases
travel followup_request_interval do
- expect(Gitlab::HTTP).to receive(:try_get).with('the release API URL').once { mock_http_response(followup_response) }
-
- expect(releases).to eq((expected_result || []) + [Gitlab::VersionInfo.new(14, 9, 2)])
+ expect(Gitlab::HTTP).to receive(:get)
+ .with(runner_releases_url, anything)
+ .once { mock_http_response(followup_response) }
+
+ new_releases = (expected_releases || []) + [Gitlab::VersionInfo.new(14, 9, 2)]
+ new_releases_by_minor_version = (expected_releases_by_minor || {}).merge(
+ Gitlab::VersionInfo.new(14, 9, 0) => Gitlab::VersionInfo.new(14, 9, 2)
+ )
+ expect(releases).to eq(new_releases)
+ expect(releases_by_minor).to eq(new_releases_by_minor_version)
end
end
end
end
- context 'when response is nil' do
- let(:response) { nil }
- let(:expected_result) { nil }
-
- it 'returns nil' do
- expect(releases).to be_nil
- end
-
- it_behaves_like 'requests that follow cache status', 5.seconds
-
+ shared_examples 'a service implementing exponential backoff' do |opts|
it 'performs exponential backoff on requests', :aggregate_failures do
start_time = Time.now.utc.change(usec: 0)
http_call_timestamp_offsets = []
- allow(Gitlab::HTTP).to receive(:try_get).with('the release API URL') do
+ allow(Gitlab::HTTP).to receive(:get).with(runner_releases_url, anything) do
http_call_timestamp_offsets << Time.now.utc - start_time
+
+ raise Net::OpenTimeout if opts&.dig(:raise_timeout)
+
mock_http_response(response)
end
# An initial HTTP request fails
travel_to(start_time)
- subject.reset!
+ subject.reset_backoff!
expect(releases).to be_nil
+ expect(releases_by_minor).to be_nil
# Successive failed requests result in HTTP requests only after specific backoff periods
backoff_periods = [5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 3600].map(&:seconds)
backoff_periods.each do |period|
travel(period - 1.second)
expect(releases).to be_nil
+ expect(releases_by_minor).to be_nil
travel 1.second
expect(releases).to be_nil
+ expect(releases_by_minor).to be_nil
end
expect(http_call_timestamp_offsets).to eq([0, 5, 15, 35, 75, 155, 315, 635, 1275, 2555, 5115, 8715])
# Finally a successful HTTP request results in releases being returned
- allow(Gitlab::HTTP).to receive(:try_get).with('the release API URL').once { mock_http_response([{ 'name' => 'v14.9.1' }]) }
+ allow(Gitlab::HTTP).to receive(:get)
+ .with(runner_releases_url, anything)
+ .once { mock_http_response([{ 'name' => 'v14.9.1-beta1-ee' }]) }
travel 1.hour
expect(releases).not_to be_nil
+ expect(releases_by_minor).not_to be_nil
end
end
+ context 'when request results in timeout' do
+ let(:response) { }
+ let(:expected_releases) { nil }
+ let(:expected_releases_by_minor) { nil }
+
+ it_behaves_like 'requests that follow cache status', 5.seconds
+ it_behaves_like 'a service implementing exponential backoff', raise_timeout: true
+ end
+
+ context 'when response is nil' do
+ let(:response) { nil }
+ let(:expected_releases) { nil }
+ let(:expected_releases_by_minor) { nil }
+
+ it_behaves_like 'requests that follow cache status', 5.seconds
+ it_behaves_like 'a service implementing exponential backoff'
+ end
+
context 'when response is not nil' do
- let(:response) { [{ 'name' => 'v14.9.1' }, { 'name' => 'v14.9.0' }] }
- let(:expected_result) { [Gitlab::VersionInfo.new(14, 9, 0), Gitlab::VersionInfo.new(14, 9, 1)] }
+ let(:response) { [{ 'name' => 'v14.9.1-beta1-ee' }, { 'name' => 'v14.9.0' }] }
+ let(:expected_releases) do
+ [
+ Gitlab::VersionInfo.new(14, 9, 0),
+ Gitlab::VersionInfo.new(14, 9, 1, '-beta1-ee')
+ ]
+ end
+
+ let(:expected_releases_by_minor) do
+ {
+ Gitlab::VersionInfo.new(14, 9, 0) => Gitlab::VersionInfo.new(14, 9, 1, '-beta1-ee')
+ }
+ end
+
+ it_behaves_like 'requests that follow cache status', 1.day
+ end
+ end
+
+ describe '#releases', :use_clean_rails_memory_store_caching do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(runner_releases_url, anything).once { mock_http_response(response) }
+ end
+
+ context 'when response is nil' do
+ let(:response) { nil }
+ let(:expected_result) { nil }
+
+ it 'returns nil' do
+ expect(releases).to be_nil
+ end
+ end
+
+ context 'when response is not nil' do
+ let(:response) { [{ 'name' => 'v14.9.1-beta1-ee' }, { 'name' => 'v14.9.0' }] }
+ let(:expected_result) do
+ [
+ Gitlab::VersionInfo.new(14, 9, 0),
+ Gitlab::VersionInfo.new(14, 9, 1, '-beta1-ee')
+ ]
+ end
it 'returns parsed and sorted Gitlab::VersionInfo objects' do
expect(releases).to eq(expected_result)
end
+ end
- it_behaves_like 'requests that follow cache status', 1.day
+ context 'when response contains unexpected input type' do
+ let(:response) { 'error' }
+
+ it { expect(releases).to be_nil }
+ end
+
+ context 'when response contains unexpected input array' do
+ let(:response) { ['error'] }
+
+ it { expect(releases).to be_nil }
+ end
+ end
+
+ describe '#releases_by_minor', :use_clean_rails_memory_store_caching do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(runner_releases_url, anything).once { mock_http_response(response) }
end
- def mock_http_response(response)
- http_response = instance_double(HTTParty::Response)
+ context 'when response is nil' do
+ let(:response) { nil }
+ let(:expected_result) { nil }
- allow(http_response).to receive(:success?).and_return(response.present?)
- allow(http_response).to receive(:parsed_response).and_return(response)
+ it 'returns nil' do
+ expect(releases_by_minor).to be_nil
+ end
+ end
- http_response
+ context 'when response is not nil' do
+ let(:response) { [{ 'name' => 'v14.9.1-beta1-ee' }, { 'name' => 'v14.9.0' }, { 'name' => 'v14.8.1' }] }
+ let(:expected_result) do
+ {
+ Gitlab::VersionInfo.new(14, 8, 0) => Gitlab::VersionInfo.new(14, 8, 1),
+ Gitlab::VersionInfo.new(14, 9, 0) => Gitlab::VersionInfo.new(14, 9, 1, '-beta1-ee')
+ }
+ end
+
+ it 'returns parsed and grouped Gitlab::VersionInfo objects' do
+ expect(releases_by_minor).to eq(expected_result)
+ end
end
+
+ context 'when response contains unexpected input type' do
+ let(:response) { 'error' }
+
+ it { expect(releases_by_minor).to be_nil }
+ end
+
+ context 'when response contains unexpected input array' do
+ let(:response) { ['error'] }
+
+ it { expect(releases_by_minor).to be_nil }
+ end
+ end
+
+ def mock_http_response(response)
+ http_response = instance_double(HTTParty::Response)
+
+ allow(http_response).to receive(:success?).and_return(!response.nil?)
+ allow(http_response).to receive(:parsed_response).and_return(response)
+
+ http_response
end
end
diff --git a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb
index 0353432741b..f2507a24b10 100644
--- a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb
+++ b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb
@@ -3,84 +3,156 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
- include StubVersion
using RSpec::Parameterized::TableSyntax
describe '#check_runner_upgrade_status' do
subject(:result) { described_class.instance.check_runner_upgrade_status(runner_version) }
+ let(:gitlab_version) { '14.1.1' }
+ let(:parsed_runner_version) { ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true) }
+
before do
- runner_releases_double = instance_double(Gitlab::Ci::RunnerReleases)
+ allow(described_class.instance).to receive(:gitlab_version)
+ .and_return(::Gitlab::VersionInfo.parse(gitlab_version))
+ end
+
+ context 'with failing Gitlab::Ci::RunnerReleases request' do
+ let(:runner_version) { '14.1.123' }
+ let(:runner_releases_double) { instance_double(Gitlab::Ci::RunnerReleases) }
+
+ before do
+ allow(Gitlab::Ci::RunnerReleases).to receive(:instance).and_return(runner_releases_double)
+ allow(runner_releases_double).to receive(:releases).and_return(nil)
+ end
- allow(Gitlab::Ci::RunnerReleases).to receive(:instance).and_return(runner_releases_double)
- allow(runner_releases_double).to receive(:releases).and_return(available_runner_releases.map { |v| ::Gitlab::VersionInfo.parse(v) })
+ it 'returns :error' do
+ is_expected.to eq({ error: parsed_runner_version })
+ end
end
- context 'with available_runner_releases configured up to 14.1.1' do
- let(:available_runner_releases) { %w[13.9.0 13.9.1 13.9.2 13.10.0 13.10.1 14.0.0 14.0.1 14.0.2 14.1.0 14.1.1 14.1.1-rc3] }
+ context 'with available_runner_releases configured' do
+ before do
+ url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url
- context 'with nil runner_version' do
- let(:runner_version) { nil }
+ WebMock.stub_request(:get, url).to_return(
+ body: available_runner_releases.map { |v| { name: v } }.to_json,
+ status: 200,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
- it 'returns :invalid' do
- is_expected.to eq(:invalid)
+ context 'with no available runner releases' do
+ let(:available_runner_releases) do
+ %w[]
end
- end
- context 'with invalid runner_version' do
- let(:runner_version) { 'junk' }
+ context 'with Gitlab::VERSION set to 14.1.1' do
+ let(:gitlab_version) { '14.1.1' }
- it 'raises ArgumentError' do
- expect { subject }.to raise_error(ArgumentError)
+ context 'with runner_version from last minor release' do
+ let(:runner_version) { 'v14.0.1' }
+
+ it 'returns :not_available' do
+ is_expected.to eq({ not_available: parsed_runner_version })
+ end
+ end
end
end
- context 'with Gitlab::VERSION set to 14.1.123' do
- before do
- stub_version('14.1.123', 'deadbeef')
+ context 'up to 14.1.1' do
+ let(:available_runner_releases) do
+ %w[13.9.0 13.9.1 13.9.2 13.10.0 13.10.1 14.0.0 14.0.1 14.0.2-rc1 14.0.2 14.1.0 14.1.1]
+ end
+
+ context 'with nil runner_version' do
+ let(:runner_version) { nil }
- described_class.instance.reset!
+ it 'returns :invalid_version' do
+ is_expected.to match({ invalid_version: anything })
+ end
end
- context 'with a runner_version that is too recent' do
- let(:runner_version) { 'v14.2.0' }
+ context 'with invalid runner_version' do
+ let(:runner_version) { 'junk' }
- it 'returns :not_available' do
- is_expected.to eq(:not_available)
+ it 'returns :invalid_version' do
+ is_expected.to match({ invalid_version: anything })
end
end
- end
- context 'with Gitlab::VERSION set to 14.0.1' do
- before do
- stub_version('14.0.1', 'deadbeef')
+ context 'with Gitlab::VERSION set to 14.1.123' do
+ let(:gitlab_version) { '14.1.123' }
+
+ context 'with a runner_version that is too recent' do
+ let(:runner_version) { 'v14.2.0' }
- described_class.instance.reset!
+ it 'returns :not_available' do
+ is_expected.to eq({ not_available: parsed_runner_version })
+ end
+ end
+ end
+
+ context 'with Gitlab::VERSION set to 14.0.1' do
+ let(:gitlab_version) { '14.0.1' }
+
+ context 'with valid params' do
+ where(:runner_version, :expected_result, :expected_suggested_version) do
+ 'v15.0.0' | :not_available | '15.0.0' # not available since the GitLab instance is still on 14.x, a major version might be incompatible, and a patch upgrade is not available
+ 'v14.1.0-rc3' | :recommended | '14.1.1' # recommended since even though the GitLab instance is still on 14.0.x, there is a patch release (14.1.1) available which might contain security fixes
+ 'v14.1.0~beta.1574.gf6ea9389' | :recommended | '14.1.1' # suffixes are correctly handled
+ 'v14.1.0/1.1.0' | :recommended | '14.1.1' # suffixes are correctly handled
+ 'v14.1.0' | :recommended | '14.1.1' # recommended since even though the GitLab instance is still on 14.0.x, there is a patch release (14.1.1) available which might contain security fixes
+ 'v14.0.1' | :recommended | '14.0.2' # recommended upgrade since 14.0.2 is available
+ 'v14.0.2-rc1' | :recommended | '14.0.2' # recommended upgrade since 14.0.2 is available and we'll move out of a release candidate
+ 'v14.0.2' | :not_available | '14.0.2' # not available since 14.0.2 is the latest 14.0.x release available within the instance's major.minor version
+ 'v13.10.1' | :available | '14.0.2' # available upgrade: 14.0.2
+ 'v13.10.1~beta.1574.gf6ea9389' | :recommended | '13.10.1' # suffixes are correctly handled, official 13.10.1 is available
+ 'v13.10.1/1.1.0' | :recommended | '13.10.1' # suffixes are correctly handled, official 13.10.1 is available
+ 'v13.10.0' | :recommended | '13.10.1' # recommended upgrade since 13.10.1 is available
+ 'v13.9.2' | :recommended | '14.0.2' # recommended upgrade since backports are no longer released for this version
+ 'v13.9.0' | :recommended | '14.0.2' # recommended upgrade since backports are no longer released for this version
+ 'v13.8.1' | :recommended | '14.0.2' # recommended upgrade since build is too old (missing in records)
+ 'v11.4.1' | :recommended | '14.0.2' # recommended upgrade since build is too old (missing in records)
+ end
+
+ with_them do
+ it { is_expected.to eq({ expected_result => Gitlab::VersionInfo.parse(expected_suggested_version) }) }
+ end
+ end
end
- context 'with valid params' do
- where(:runner_version, :expected_result) do
- 'v15.0.0' | :not_available # not available since the GitLab instance is still on 14.x and a major version might be incompatible
- 'v14.1.0-rc3' | :recommended # recommended since even though the GitLab instance is still on 14.0.x, there is a patch release (14.1.1) available which might contain security fixes
- 'v14.1.0~beta.1574.gf6ea9389' | :recommended # suffixes are correctly handled
- 'v14.1.0/1.1.0' | :recommended # suffixes are correctly handled
- 'v14.1.0' | :recommended # recommended since even though the GitLab instance is still on 14.0.x, there is a patch release (14.1.1) available which might contain security fixes
- 'v14.0.1' | :recommended # recommended upgrade since 14.0.2 is available
- 'v14.0.2' | :not_available # not available since 14.0.2 is the latest 14.0.x release available within the instance's major.minor version
- 'v13.10.1' | :available # available upgrade: 14.1.1
- 'v13.10.1~beta.1574.gf6ea9389' | :available # suffixes are correctly handled
- 'v13.10.1/1.1.0' | :available # suffixes are correctly handled
- 'v13.10.0' | :recommended # recommended upgrade since 13.10.1 is available
- 'v13.9.2' | :recommended # recommended upgrade since backports are no longer released for this version
- 'v13.9.0' | :recommended # recommended upgrade since backports are no longer released for this version
- 'v13.8.1' | :recommended # recommended upgrade since build is too old (missing in records)
- 'v11.4.1' | :recommended # recommended upgrade since build is too old (missing in records)
+ context 'with Gitlab::VERSION set to 13.9.0' do
+ let(:gitlab_version) { '13.9.0' }
+
+ context 'with valid params' do
+ where(:runner_version, :expected_result, :expected_suggested_version) do
+ 'v14.0.0' | :recommended | '14.0.2' # recommended upgrade since 14.0.2 is available, even though the GitLab instance is still on 13.x and a major version might be incompatible
+ 'v13.10.1' | :not_available | '13.10.1' # not available since 13.10.1 is already ahead of GitLab instance version and is the latest patch update for 13.10.x
+ 'v13.10.0' | :recommended | '13.10.1' # recommended upgrade since 13.10.1 is available
+ 'v13.9.2' | :not_available | '13.9.2' # not_available even though backports are no longer released for this version because the runner is already on the same version as the GitLab version
+ 'v13.9.0' | :recommended | '13.9.2' # recommended upgrade since backports are no longer released for this version
+ 'v13.8.1' | :recommended | '13.9.2' # recommended upgrade since build is too old (missing in records)
+ 'v11.4.1' | :recommended | '13.9.2' # recommended upgrade since build is too old (missing in records)
+ end
+
+ with_them do
+ it { is_expected.to eq({ expected_result => Gitlab::VersionInfo.parse(expected_suggested_version) }) }
+ end
end
+ end
+ end
+
+ context 'up to 15.1.0' do
+ let(:available_runner_releases) { %w[14.9.1 14.9.2 14.10.0 14.10.1 15.0.0 15.1.0] }
+
+ context 'with Gitlab::VERSION set to 15.2.0-pre' do
+ let(:gitlab_version) { '15.2.0-pre' }
+
+ context 'with unknown runner version' do
+ let(:runner_version) { '14.11.0~beta.29.gd0c550e3' }
- with_them do
- it 'returns symbol representing expected upgrade status' do
- is_expected.to be_a(Symbol)
- is_expected.to eq(expected_result)
+ it 'recommends 15.1.0 since 14.11 is an unknown release and 15.1.0 is available' do
+ is_expected.to eq({ recommended: Gitlab::VersionInfo.new(15, 1, 0) })
end
end
end
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index e0f5531f370..35d44281072 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -7,9 +7,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
- let(:stage) do
- build(:ci_stage, pipeline: pipeline, name: 'test')
- end
+ let(:stage) { create(:ci_stage, pipeline: pipeline) }
subject do
described_class.new(stage, user)
@@ -26,11 +24,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory do
context 'when stage has a core status' do
(Ci::HasStatus::AVAILABLE_STATUSES - %w(manual skipped scheduled)).each do |core_status|
context "when core status is #{core_status}" do
- before do
- create(:ci_build, pipeline: pipeline, stage: 'test', status: core_status)
- create(:commit_status, pipeline: pipeline, stage: 'test', status: core_status)
- create(:ci_build, pipeline: pipeline, stage: 'build', status: :failed)
- end
+ let(:stage) { create(:ci_stage, pipeline: pipeline, status: core_status) }
it "fabricates a core status #{core_status}" do
expect(status).to be_a(
@@ -48,12 +42,12 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory do
context 'when stage has warnings' do
let(:stage) do
- build(:ci_stage, name: 'test', status: :success, pipeline: pipeline)
+ create(:ci_stage, status: :success, pipeline: pipeline)
end
before do
create(:ci_build, :allowed_to_fail, :failed,
- stage: 'test', pipeline: stage.pipeline)
+ stage_id: stage.id, pipeline: stage.pipeline)
end
it 'fabricates extended "success with warnings" status' do
@@ -70,11 +64,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory do
context 'when stage has manual builds' do
(Ci::HasStatus::BLOCKED_STATUS + ['skipped']).each do |core_status|
context "when status is #{core_status}" do
- before do
- create(:ci_build, pipeline: pipeline, stage: 'test', status: core_status)
- create(:commit_status, pipeline: pipeline, stage: 'test', status: core_status)
- create(:ci_build, pipeline: pipeline, stage: 'build', status: :manual)
- end
+ let(:stage) { create(:ci_stage, pipeline: pipeline, status: core_status) }
it 'fabricates a play manual status' do
expect(status).to be_a(Gitlab::Ci::Status::Stage::PlayManual)
diff --git a/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb b/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
index 25b79ff2099..9fdaddc083e 100644
--- a/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::PlayManual do
end
describe '#action_path' do
- let(:stage) { create(:ci_stage_entity, status: 'manual') }
+ let(:stage) { create(:ci_stage, status: 'manual') }
let(:pipeline) { stage.pipeline }
let(:play_manual) { stage.detailed_status(create(:user)) }
@@ -46,25 +46,25 @@ RSpec.describe Gitlab::Ci::Status::Stage::PlayManual do
subject { described_class.matches?(stage, user) }
context 'when stage is skipped' do
- let(:stage) { create(:ci_stage_entity, status: :skipped) }
+ let(:stage) { create(:ci_stage, status: :skipped) }
it { is_expected.to be_truthy }
end
context 'when stage is manual' do
- let(:stage) { create(:ci_stage_entity, status: :manual) }
+ let(:stage) { create(:ci_stage, status: :manual) }
it { is_expected.to be_truthy }
end
context 'when stage is scheduled' do
- let(:stage) { create(:ci_stage_entity, status: :scheduled) }
+ let(:stage) { create(:ci_stage, status: :scheduled) }
it { is_expected.to be_truthy }
end
context 'when stage is success' do
- let(:stage) { create(:ci_stage_entity, status: :success) }
+ let(:stage) { create(:ci_stage, status: :success) }
context 'and does not have manual builds' do
it { is_expected.to be_falsy }
diff --git a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
index 6c4f69fb036..5ab859241c6 100644
--- a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
+++ b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do
let(:error_message) do
<<~MESSAGE
A mechanism depending on internals of 'act-as-taggable-on` has been designed
- to bulk insert tags for Ci::Build records.
+ to bulk insert tags for Ci::Build/Ci::Runner records.
Please review the code carefully before updating the gem version
https://gitlab.com/gitlab-org/gitlab/-/issues/350053
MESSAGE
@@ -27,6 +27,21 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do
it { expect(ActsAsTaggableOn::VERSION).to eq(acceptable_version), error_message }
end
+ describe '.bulk_insert_tags!' do
+ let(:inserter) { instance_double(described_class) }
+
+ it 'delegates to bulk insert class' do
+ expect(Gitlab::Ci::Tags::BulkInsert)
+ .to receive(:new)
+ .with(statuses)
+ .and_return(inserter)
+
+ expect(inserter).to receive(:insert!)
+
+ described_class.bulk_insert_tags!(statuses)
+ end
+ end
+
describe '#insert!' do
context 'without tags' do
it { expect(service.insert!).to be_falsey }
@@ -44,6 +59,50 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do
expect(job.reload.tag_list).to match_array(%w[tag1 tag2])
expect(other_job.reload.tag_list).to match_array(%w[tag2 tag3 tag4])
end
+
+ it 'persists taggings' do
+ service.insert!
+
+ expect(job.taggings.size).to eq(2)
+ expect(other_job.taggings.size).to eq(3)
+
+ expect(Ci::Build.tagged_with('tag1')).to include(job)
+ expect(Ci::Build.tagged_with('tag2')).to include(job, other_job)
+ expect(Ci::Build.tagged_with('tag3')).to include(other_job)
+ end
+
+ it 'strips tags' do
+ job.tag_list = [' taga', 'tagb ', ' tagc ']
+
+ service.insert!
+ expect(job.tags.map(&:name)).to match_array(%w[taga tagb tagc])
+ end
+
+ context 'when batching inserts for tags' do
+ before do
+ stub_const("#{described_class}::TAGS_BATCH_SIZE", 2)
+ end
+
+ it 'inserts tags in batches' do
+ recorder = ActiveRecord::QueryRecorder.new { service.insert! }
+ count = recorder.log.count { |query| query.include?('INSERT INTO "tags"') }
+
+ expect(count).to eq(2)
+ end
+ end
+
+ context 'when batching inserts for taggings' do
+ before do
+ stub_const("#{described_class}::TAGGINGS_BATCH_SIZE", 2)
+ end
+
+ it 'inserts taggings in batches' do
+ recorder = ActiveRecord::QueryRecorder.new { service.insert! }
+ count = recorder.log.count { |query| query.include?('INSERT INTO "taggings"') }
+
+ expect(count).to eq(3)
+ end
+ end
end
context 'with tags for only one job' do
@@ -57,6 +116,15 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do
expect(job.reload.tag_list).to match_array(%w[tag1 tag2])
expect(other_job.reload.tag_list).to be_empty
end
+
+ it 'persists taggings' do
+ service.insert!
+
+ expect(job.taggings.size).to eq(2)
+
+ expect(Ci::Build.tagged_with('tag1')).to include(job)
+ expect(Ci::Build.tagged_with('tag2')).to include(job)
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
index 27de8324206..65fd2b016ac 100644
--- a/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
@@ -34,6 +34,16 @@ RSpec.describe 'Deploy-ECS.gitlab-ci.yml' do
expect(build_names).to include('production_ecs')
end
+ context 'when the DAST template is also included' do
+ let(:dast_template) { Gitlab::Template::GitlabCiYmlTemplate.find('Security/DAST') }
+
+ before do
+ stub_ci_pipeline_yaml_file(template.content + dast_template.content)
+ end
+
+ include_examples 'no pipeline yaml error'
+ end
+
context 'when running a pipeline for a branch' do
let(:pipeline_branch) { 'test_branch' }
diff --git a/spec/lib/gitlab/ci/variables/builder_spec.rb b/spec/lib/gitlab/ci/variables/builder_spec.rb
index b0704ad7f50..8ec0846bdca 100644
--- a/spec/lib/gitlab/ci/variables/builder_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder_spec.rb
@@ -166,9 +166,8 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
allow(builder).to receive(:secret_instance_variables) { [var('J', 10), var('K', 10)] }
allow(builder).to receive(:secret_group_variables) { [var('K', 11), var('L', 11)] }
allow(builder).to receive(:secret_project_variables) { [var('L', 12), var('M', 12)] }
- allow(job).to receive(:trigger_request) { double(user_variables: [var('M', 13), var('N', 13)]) }
- allow(pipeline).to receive(:variables) { [var('N', 14), var('O', 14)] }
- allow(pipeline).to receive(:pipeline_schedule) { double(job_variables: [var('O', 15), var('P', 15)]) }
+ allow(pipeline).to receive(:variables) { [var('M', 13), var('N', 13)] }
+ allow(pipeline).to receive(:pipeline_schedule) { double(job_variables: [var('N', 14), var('O', 14)]) }
end
it 'returns variables in order depending on resource hierarchy' do
@@ -185,8 +184,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
var('K', 11), var('L', 11),
var('L', 12), var('M', 12),
var('M', 13), var('N', 13),
- var('N', 14), var('O', 14),
- var('O', 15), var('P', 15)])
+ var('N', 14), var('O', 14)])
end
it 'overrides duplicate keys depending on resource hierarchy' do
@@ -198,7 +196,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
'I' => '9', 'J' => '10',
'K' => '11', 'L' => '12',
'M' => '13', 'N' => '14',
- 'O' => '15', 'P' => '15')
+ 'O' => '14')
end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor/feature_flags_spec.rb b/spec/lib/gitlab/ci/yaml_processor/feature_flags_spec.rb
new file mode 100644
index 00000000000..0bd9563d191
--- /dev/null
+++ b/spec/lib/gitlab/ci/yaml_processor/feature_flags_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::YamlProcessor::FeatureFlags do
+ let(:feature_flag) { :my_feature_flag }
+
+ context 'when the actor is set' do
+ let(:actor) { double }
+ let(:another_actor) { double }
+
+ it 'checks the feature flag using the given actor' do
+ described_class.with_actor(actor) do
+ expect(Feature).to receive(:enabled?).with(feature_flag, actor)
+
+ described_class.enabled?(feature_flag)
+ end
+ end
+
+ it 'returns the value of the block' do
+ result = described_class.with_actor(actor) do
+ :test
+ end
+
+ expect(result).to eq(:test)
+ end
+
+ it 'restores the existing actor if any' do
+ described_class.with_actor(actor) do
+ described_class.with_actor(another_actor) do
+ expect(Feature).to receive(:enabled?).with(feature_flag, another_actor)
+
+ described_class.enabled?(feature_flag)
+ end
+
+ expect(Feature).to receive(:enabled?).with(feature_flag, actor)
+ described_class.enabled?(feature_flag)
+ end
+ end
+
+ it 'restores the actor to nil after the block' do
+ described_class.with_actor(actor) do
+ expect(Thread.current[described_class::ACTOR_KEY]).to eq(actor)
+ end
+
+ expect(Thread.current[described_class::ACTOR_KEY]).to be nil
+ end
+ end
+
+ context 'when feature flag is checked outside the "with_actor" block' do
+ it 'raises an error on dev/test environment' do
+ expect { described_class.enabled?(feature_flag) }.to raise_error(described_class::NoActorError)
+ end
+
+ context 'when on production' do
+ before do
+ allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false)
+ end
+
+ it 'checks the feature flag without actor' do
+ expect(Feature).to receive(:enabled?).with(feature_flag, nil)
+ expect(Gitlab::ErrorTracking)
+ .to receive(:track_and_raise_for_dev_exception)
+ .and_call_original
+
+ described_class.enabled?(feature_flag)
+ end
+ end
+ end
+
+ context 'when actor is explicitly nil' do
+ it 'checks the feature flag without actor' do
+ described_class.with_actor(nil) do
+ expect(Feature).to receive(:enabled?).with(feature_flag, nil)
+
+ described_class.enabled?(feature_flag)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 3dd9ca35881..22bc6b0db59 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -70,7 +70,7 @@ module Gitlab
options: { script: ['rspec'] },
rules: [
{ if: '$CI_COMMIT_REF_NAME == "master"' },
- { changes: %w[README.md] }
+ { changes: { paths: %w[README.md] } }
],
allow_failure: false,
when: 'on_success',
@@ -980,7 +980,7 @@ module Gitlab
it { is_expected.to be_valid }
- it "returns image and service when defined" do
+ it "returns with image" do
expect(processor.stage_builds_attributes("test")).to contain_exactly({
stage: "test",
stage_idx: 2,
@@ -1010,6 +1010,51 @@ module Gitlab
end
end
end
+
+ context 'when a service has pull_policy' do
+ let(:config) do
+ <<~YAML
+ services:
+ - name: postgres:11.9
+ pull_policy: if-not-present
+
+ test:
+ script: exit 0
+ YAML
+ end
+
+ it { is_expected.to be_valid }
+
+ it "returns with service" do
+ expect(processor.stage_builds_attributes("test")).to contain_exactly({
+ stage: "test",
+ stage_idx: 2,
+ name: "test",
+ only: { refs: %w[branches tags] },
+ options: {
+ script: ["exit 0"],
+ services: [{ name: "postgres:11.9", pull_policy: ["if-not-present"] }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ job_variables: [],
+ root_variables_inheritance: true,
+ scheduling_type: :stage
+ })
+ end
+
+ context 'when the feature flag ci_docker_image_pull_policy is disabled' do
+ before do
+ stub_feature_flags(ci_docker_image_pull_policy: false)
+ end
+
+ it { is_expected.not_to be_valid }
+
+ it "returns no job" do
+ expect(processor.jobs).to eq({})
+ end
+ end
+ end
end
describe 'Variables' do
@@ -2848,6 +2893,51 @@ module Gitlab
end
end
+ describe 'Rules' do
+ context 'changes' do
+ let(:config) do
+ <<~YAML
+ rspec:
+ script: exit 0
+ rules:
+ - changes: [README.md]
+ YAML
+ end
+
+ it 'returns builds with correct rules' do
+ expect(processor.builds.size).to eq(1)
+ expect(processor.builds[0]).to match(
+ hash_including(
+ name: "rspec",
+ rules: [{ changes: { paths: ["README.md"] } }]
+ )
+ )
+ end
+
+ context 'with paths' do
+ let(:config) do
+ <<~YAML
+ rspec:
+ script: exit 0
+ rules:
+ - changes:
+ paths: [README.md]
+ YAML
+ end
+
+ it 'returns builds with correct rules' do
+ expect(processor.builds.size).to eq(1)
+ expect(processor.builds[0]).to match(
+ hash_including(
+ name: "rspec",
+ rules: [{ changes: { paths: ["README.md"] } }]
+ )
+ )
+ end
+ end
+ end
+ end
+
describe '#execute' do
subject { Gitlab::Ci::YamlProcessor.new(content).execute }