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>2020-11-19 11:27:35 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 11:27:35 +0300
commit7e9c479f7de77702622631cff2628a9c8dcbc627 (patch)
treec8f718a08e110ad7e1894510980d2155a6549197 /spec/lib/gitlab/ci
parente852b0ae16db4052c1c567d9efa4facc81146e88 (diff)
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/charts_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb128
-rw-r--r--spec/lib/gitlab/ci/config/entry/product/variables_spec.rb71
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb56
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb77
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb78
-rw-r--r--spec/lib/gitlab/ci/jwt_spec.rb63
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb123
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb19
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb78
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb66
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb63
-rw-r--r--spec/lib/gitlab/ci/reports/test_case_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/reports/test_failure_history_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb146
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/runner_instructions_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb59
-rw-r--r--spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/variables/collection/item_spec.rb4
22 files changed, 940 insertions, 251 deletions
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 cf52f601006..d20ea6c9202 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
@@ -13,5 +13,47 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
subject { described_class.new(globs).satisfied_by?(pipeline, nil) }
end
+
+ 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') }
+
+ subject { described_class.new(globs).satisfied_by?(pipeline, context) }
+
+ before do
+ allow(pipeline).to receive(:modified_paths).and_return(modified_paths)
+ end
+
+ context 'when context is nil' do
+ let(:context) {}
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when context has the specified variables' do
+ let(:variables) do
+ [{ key: "HELM_DIR", value: "helm", public: true }]
+ end
+
+ before do
+ allow(context).to receive(:variables).and_return(variables)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when variable expansion does not match' do
+ let(:globs) { ['path/with/$in/it/*'] }
+ let(:modified_paths) { ['path/with/$in/it/file.txt'] }
+
+ before do
+ allow(context).to receive(:variables).and_return([])
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb
index e00e5ed3920..cfc2019a89b 100644
--- a/spec/lib/gitlab/ci/charts_spec.rb
+++ b/spec/lib/gitlab/ci/charts_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Charts do
- context "yearchart" do
+ context 'yearchart' do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::YearChart.new(project) }
@@ -16,9 +16,13 @@ RSpec.describe Gitlab::Ci::Charts do
it 'starts at the beginning of the current year' do
expect(chart.from).to eq(chart.to.years_ago(1).beginning_of_month.beginning_of_day)
end
+
+ it 'uses %B %Y as labels format' do
+ expect(chart.labels).to include(chart.from.strftime('%B %Y'))
+ end
end
- context "monthchart" do
+ context 'monthchart' do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::MonthChart.new(project) }
@@ -31,9 +35,13 @@ RSpec.describe Gitlab::Ci::Charts do
it 'starts one month ago' do
expect(chart.from).to eq(1.month.ago.beginning_of_day)
end
+
+ it 'uses %d %B as labels format' do
+ expect(chart.labels).to include(chart.from.strftime('%d %B'))
+ end
end
- context "weekchart" do
+ context 'weekchart' do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::WeekChart.new(project) }
@@ -46,9 +54,13 @@ RSpec.describe Gitlab::Ci::Charts do
it 'starts one week ago' do
expect(chart.from).to eq(1.week.ago.beginning_of_day)
end
+
+ it 'uses %d %B as labels format' do
+ expect(chart.labels).to include(chart.from.strftime('%d %B'))
+ end
end
- context "pipeline_times" do
+ context 'pipeline_times' do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::PipelineTime.new(project) }
diff --git a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
index 3388ae0af2f..ff44a235ea5 100644
--- a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
@@ -46,98 +46,53 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
end
end
- context 'with one_dimensional_matrix feature flag enabled' do
- before do
- stub_feature_flags(one_dimensional_matrix: true)
- matrix.compose!
+ context 'when entry config has only one variable with multiple values' do
+ let(:config) do
+ [
+ {
+ 'VAR_1' => %w[build test]
+ }
+ ]
end
- context 'when entry config has only one variable with multiple values' do
- let(:config) do
- [
- {
- 'VAR_1' => %w[build test]
- }
- ]
- end
-
- describe '#valid?' do
- it { is_expected.to be_valid }
- end
+ describe '#valid?' do
+ it { is_expected.to be_valid }
+ end
- describe '#errors' do
- it 'returns no errors' do
- expect(matrix.errors)
- .to be_empty
- end
+ describe '#errors' do
+ it 'returns no errors' do
+ expect(matrix.errors)
+ .to be_empty
end
+ end
- describe '#value' do
- before do
- matrix.compose!
- end
-
- it 'returns the value without raising an error' do
- expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
- end
+ describe '#value' do
+ before do
+ matrix.compose!
end
- context 'when entry config has only one variable with one value' do
- let(:config) do
- [
- {
- 'VAR_1' => %w[test]
- }
- ]
- end
-
- describe '#valid?' do
- it { is_expected.to be_valid }
- end
-
- describe '#errors' do
- it 'returns no errors' do
- expect(matrix.errors)
- .to be_empty
- end
- end
-
- describe '#value' do
- before do
- matrix.compose!
- end
-
- it 'returns the value without raising an error' do
- expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
- end
- end
+ it 'returns the value without raising an error' do
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
end
end
- end
- context 'with one_dimensional_matrix feature flag disabled' do
- before do
- stub_feature_flags(one_dimensional_matrix: false)
- matrix.compose!
- end
-
- context 'when entry config has only one variable with multiple values' do
+ context 'when entry config has only one variable with one value' do
let(:config) do
[
{
- 'VAR_1' => %w[build test]
+ 'VAR_1' => %w[test]
}
]
end
describe '#valid?' do
- it { is_expected.not_to be_valid }
+ it { is_expected.to be_valid }
end
describe '#errors' do
- it 'returns error about too many jobs' do
+ it 'returns no errors' do
expect(matrix.errors)
- .to include('variables config requires at least 2 items')
+ .to be_empty
end
end
@@ -147,38 +102,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
end
it 'returns the value without raising an error' do
- expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
- end
- end
-
- context 'when entry config has only one variable with one value' do
- let(:config) do
- [
- {
- 'VAR_1' => %w[test]
- }
- ]
- end
-
- describe '#valid?' do
- it { is_expected.not_to be_valid }
- end
-
- describe '#errors' do
- it 'returns no errors' do
- expect(matrix.errors)
- .to include('variables config requires at least 2 items')
- end
- end
-
- describe '#value' do
- before do
- matrix.compose!
- end
-
- it 'returns the value without raising an error' do
- expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
- end
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
index 407efb438b5..5e920ce34e0 100644
--- a/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-# After Feature one_dimensional_matrix is removed, this can be changed back to fast_spec_helper
-require 'spec_helper'
+require 'fast_spec_helper'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
@@ -46,70 +45,18 @@ RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
end
end
- context 'with one_dimensional_matrix feature flag enabled' do
- context 'with only one variable' do
- before do
- stub_feature_flags(one_dimensional_matrix: true)
- end
- let(:config) { { VAR: 'test' } }
-
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
- end
+ context 'with only one variable' do
+ let(:config) { { VAR: 'test' } }
- describe '#errors' do
- it 'does not append errors' do
- expect(entry.errors).to be_empty
- end
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
end
end
- end
-
- context 'with one_dimensional_matrix feature flag disabled' do
- context 'when entry value is not correct' do
- before do
- stub_feature_flags(one_dimensional_matrix: false)
- end
- shared_examples 'invalid variables' do |message|
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors).to include(message)
- end
- end
-
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
- end
- end
-
- context 'with array' do
- let(:config) { [:VAR, 'test'] }
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
-
- context 'with empty array' do
- let(:config) { { VAR: 'test', VAR2: [] } }
-
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
-
- context 'with nested array' do
- let(:config) { { VAR: 'test', VAR2: [1, [2]] } }
-
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
-
- context 'with one_dimensional_matrix feature flag disabled' do
- context 'with only one variable' do
- let(:config) { { VAR: 'test' } }
-
- it_behaves_like 'invalid variables', /variables config requires at least 2 items/
- end
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index bf14d8d6b34..7ad57827e30 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -100,6 +100,42 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
expect { subject }.to raise_error(described_class::AmbigiousSpecificationError)
end
end
+
+ context "when the key is a project's file" do
+ let(:values) do
+ { include: { project: project.full_path, file: local_file },
+ image: 'ruby:2.7' }
+ end
+
+ it 'returns File instances' do
+ expect(subject).to contain_exactly(
+ an_instance_of(Gitlab::Ci::Config::External::File::Project))
+ end
+ end
+
+ context "when the key is project's files" do
+ let(:values) do
+ { include: { project: project.full_path, file: [local_file, 'another_file_path.yml'] },
+ image: 'ruby:2.7' }
+ end
+
+ it 'returns two File instances' do
+ expect(subject).to contain_exactly(
+ an_instance_of(Gitlab::Ci::Config::External::File::Project),
+ an_instance_of(Gitlab::Ci::Config::External::File::Project))
+ end
+
+ context 'when FF ci_include_multiple_files_from_project is disabled' do
+ before do
+ stub_feature_flags(ci_include_multiple_files_from_project: false)
+ end
+
+ it 'returns a File instance' do
+ expect(subject).to contain_exactly(
+ an_instance_of(Gitlab::Ci::Config::External::File::Project))
+ end
+ end
+ end
end
context "when 'include' is defined as an array" do
@@ -161,6 +197,16 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
it 'raises an exception' do
expect { subject }.to raise_error(described_class::DuplicateIncludesError)
end
+
+ context 'when including multiple files from a project' do
+ let(:values) do
+ { include: { project: project.full_path, file: [local_file, local_file] } }
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(described_class::DuplicateIncludesError)
+ end
+ end
end
context "when too many 'includes' are defined" do
@@ -179,6 +225,16 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
it 'raises an exception' do
expect { subject }.to raise_error(described_class::TooManyIncludesError)
end
+
+ context 'when including multiple files from a project' do
+ let(:values) do
+ { include: { project: project.full_path, file: [local_file, 'another_file_path.yml'] } }
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(described_class::TooManyIncludesError)
+ end
+ end
end
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 9786e050399..150a2ec2929 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -302,5 +302,82 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
end
end
end
+
+ context 'when a valid project file is defined' do
+ let(:values) do
+ {
+ include: { project: another_project.full_path, file: '/templates/my-build.yml' },
+ image: 'ruby:2.7'
+ }
+ end
+
+ before do
+ another_project.add_developer(user)
+
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:blob_data_at).with(another_project.commit.id, '/templates/my-build.yml') do
+ <<~HEREDOC
+ my_build:
+ script: echo Hello World
+ HEREDOC
+ end
+ end
+ end
+
+ it 'appends the file to the values' do
+ output = processor.perform
+ expect(output.keys).to match_array([:image, :my_build])
+ end
+ end
+
+ context 'when valid project files are defined in a single include' do
+ let(:values) do
+ {
+ include: {
+ project: another_project.full_path,
+ file: ['/templates/my-build.yml', '/templates/my-test.yml']
+ },
+ image: 'ruby:2.7'
+ }
+ end
+
+ before do
+ another_project.add_developer(user)
+
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:blob_data_at).with(another_project.commit.id, '/templates/my-build.yml') do
+ <<~HEREDOC
+ my_build:
+ script: echo Hello World
+ HEREDOC
+ end
+
+ allow(repository).to receive(:blob_data_at).with(another_project.commit.id, '/templates/my-test.yml') do
+ <<~HEREDOC
+ my_test:
+ script: echo Hello World
+ HEREDOC
+ end
+ end
+ end
+
+ it 'appends the file to the values' do
+ output = processor.perform
+ expect(output.keys).to match_array([:image, :my_build, :my_test])
+ end
+
+ context 'when FF ci_include_multiple_files_from_project is disabled' do
+ before do
+ stub_feature_flags(ci_include_multiple_files_from_project: false)
+ end
+
+ it 'raises an error' do
+ expect { processor.perform }.to raise_error(
+ described_class::IncludeError,
+ 'Included file `["/templates/my-build.yml", "/templates/my-test.yml"]` needs to be a string'
+ )
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 41a45fe4ab7..b5a0f0e3fd7 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -246,6 +246,14 @@ RSpec.describe Gitlab::Ci::Config do
let(:remote_location) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' }
let(:local_location) { 'spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml' }
+ let(:local_file_content) do
+ File.read(Rails.root.join(local_location))
+ end
+
+ let(:local_location_hash) do
+ YAML.safe_load(local_file_content).deep_symbolize_keys
+ end
+
let(:remote_file_content) do
<<~HEREDOC
variables:
@@ -256,8 +264,8 @@ RSpec.describe Gitlab::Ci::Config do
HEREDOC
end
- let(:local_file_content) do
- File.read(Rails.root.join(local_location))
+ let(:remote_file_hash) do
+ YAML.safe_load(remote_file_content).deep_symbolize_keys
end
let(:gitlab_ci_yml) do
@@ -283,22 +291,11 @@ RSpec.describe Gitlab::Ci::Config do
context "when gitlab_ci_yml has valid 'include' defined" do
it 'returns a composed hash' do
- before_script_values = [
- "apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs", "ruby -v",
- "which ruby",
- "bundle install --jobs $(nproc) \"${FLAGS[@]}\""
- ]
- variables = {
- POSTGRES_USER: "user",
- POSTGRES_PASSWORD: "testing-password",
- POSTGRES_ENABLED: "true",
- POSTGRES_DB: "$CI_ENVIRONMENT_SLUG"
- }
composed_hash = {
- before_script: before_script_values,
+ before_script: local_location_hash[:before_script],
image: "ruby:2.7",
rspec: { script: ["bundle exec rspec"] },
- variables: variables
+ variables: remote_file_hash[:variables]
}
expect(config.to_hash).to eq(composed_hash)
@@ -575,5 +572,56 @@ RSpec.describe Gitlab::Ci::Config do
)
end
end
+
+ context "when including multiple files from a project" do
+ let(:other_file_location) { 'my_builds.yml' }
+
+ let(:other_file_content) do
+ <<~HEREDOC
+ build:
+ stage: build
+ script: echo hello
+
+ rspec:
+ stage: test
+ script: bundle exec rspec
+ HEREDOC
+ end
+
+ let(:gitlab_ci_yml) do
+ <<~HEREDOC
+ include:
+ - project: #{project.full_path}
+ file:
+ - #{local_location}
+ - #{other_file_location}
+
+ image: ruby:2.7
+ HEREDOC
+ end
+
+ before do
+ project.add_developer(user)
+
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:blob_data_at).with(an_instance_of(String), local_location)
+ .and_return(local_file_content)
+
+ allow(repository).to receive(:blob_data_at).with(an_instance_of(String), other_file_location)
+ .and_return(other_file_content)
+ end
+ end
+
+ it 'returns a composed hash' do
+ composed_hash = {
+ before_script: local_location_hash[:before_script],
+ image: "ruby:2.7",
+ build: { stage: "build", script: "echo hello" },
+ rspec: { stage: "test", script: "bundle exec rspec" }
+ }
+
+ expect(config.to_hash).to eq(composed_hash)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb
index 9b133efad9c..3130c0c0c41 100644
--- a/spec/lib/gitlab/ci/jwt_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_spec.rb
@@ -93,32 +93,65 @@ RSpec.describe Gitlab::Ci::Jwt do
end
describe '.for_build' do
- let(:rsa_key) { OpenSSL::PKey::RSA.new(Rails.application.secrets.openid_connect_signing_key) }
+ 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 }
- subject(:jwt) { described_class.for_build(build) }
+ it 'generates JWT with key id' do
+ _payload, headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
+
+ expect(headers['kid']).to eq(rsa_key.public_key.to_jwk['kid'])
+ end
+
+ it 'generates JWT for the given job with ttl equal to build timeout' do
+ expect(build).to receive(:metadata_timeout).and_return(3_600)
+
+ payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
+ ttl = payload["exp"] - payload["iat"]
+
+ expect(ttl).to eq(3_600)
+ end
+
+ it 'generates JWT for the given job with default ttl if build timeout is not set' do
+ expect(build).to receive(:metadata_timeout).and_return(nil)
+
+ payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
+ ttl = payload["exp"] - payload["iat"]
- it 'generates JWT with key id' do
- _payload, headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
+ expect(ttl).to eq(5.minutes.to_i)
+ end
+ end
+
+ context 'when signing key is missing' do
+ let(:rsa_key_data) { nil }
- expect(headers['kid']).to eq(rsa_key.public_key.to_jwk['kid'])
+ it 'raises NoSigningKeyError' do
+ expect { jwt }.to raise_error described_class::NoSigningKeyError
+ end
+ end
end
- it 'generates JWT for the given job with ttl equal to build timeout' do
- expect(build).to receive(:metadata_timeout).and_return(3_600)
+ subject(:jwt) { described_class.for_build(build) }
+
+ context 'when ci_jwt_signing_key feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_jwt_signing_key: false)
- payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
- ttl = payload["exp"] - payload["iat"]
+ allow(Rails.application.secrets).to receive(:openid_connect_signing_key).and_return(rsa_key_data)
+ end
- expect(ttl).to eq(3_600)
+ it_behaves_like 'generating JWT for build'
end
- it 'generates JWT for the given job with default ttl if build timeout is not set' do
- expect(build).to receive(:metadata_timeout).and_return(nil)
+ context 'when ci_jwt_signing_key feature flag is enabled' do
+ before do
+ stub_feature_flags(ci_jwt_signing_key: true)
- payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
- ttl = payload["exp"] - payload["iat"]
+ stub_application_setting(ci_jwt_signing_key: rsa_key_data)
+ end
- expect(ttl).to eq(5.minutes.to_i)
+ it_behaves_like 'generating JWT for build'
end
end
end
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
new file mode 100644
index 00000000000..3eaecb11ae0
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let(:prev_pipeline) { create(:ci_pipeline, project: project) }
+ let(:new_commit) { create(:commit, project: project) }
+ let(:pipeline) { create(:ci_pipeline, project: project, sha: new_commit.sha) }
+
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(project: project, current_user: user)
+ end
+
+ let(:step) { described_class.new(pipeline, command) }
+
+ before do
+ create(:ci_build, :interruptible, :running, pipeline: prev_pipeline)
+ create(:ci_build, :interruptible, :success, pipeline: prev_pipeline)
+ create(:ci_build, :created, pipeline: prev_pipeline)
+
+ create(:ci_build, :interruptible, pipeline: pipeline)
+ end
+
+ describe '#perform!' do
+ subject(:perform) { step.perform! }
+
+ before do
+ expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ end
+
+ context 'when auto-cancel is enabled' do
+ before do
+ project.update!(auto_cancel_pending_pipelines: 'enabled')
+ end
+
+ it 'cancels only previous interruptible builds' do
+ perform
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ end
+
+ context 'when the previous pipeline has a child pipeline' do
+ let(:child_pipeline) { create(:ci_pipeline, child_of: prev_pipeline) }
+
+ context 'when the child pipeline has an interruptible job' do
+ before do
+ create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
+ end
+
+ it 'cancels interruptible builds of child pipeline' do
+ expect(build_statuses(child_pipeline)).to contain_exactly('running')
+
+ perform
+
+ 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
+ before do
+ create(:ci_build, :running, pipeline: child_pipeline)
+ end
+
+ it 'does not cancel the build 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 prev pipeline source is webide' do
+ let(:prev_pipeline) { create(:ci_pipeline, :webide, project: project) }
+
+ it 'does not cancel builds of the previous pipeline' do
+ perform
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('created', 'running', 'success')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ end
+ end
+ end
+
+ context 'when auto-cancel is disabled' do
+ before do
+ project.update!(auto_cancel_pending_pipelines: 'disabled')
+ end
+
+ it 'does not cancel any build' do
+ subject
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ end
+ end
+ end
+
+ private
+
+ def build_statuses(pipeline)
+ pipeline.builds.pluck(:status)
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 8c02121857a..5506b079d0f 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
[
Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::SeedBlock.new(pipeline, command),
Gitlab::Ci::Pipeline::Chain::Seed.new(pipeline, command)
]
end
@@ -180,23 +181,21 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
->(pipeline) { pipeline.variables.create!(key: 'VAR', value: '123') }
end
- it 'wastes pipeline iid' do
- expect { run_chain }.to raise_error(ActiveRecord::RecordNotSaved)
-
- last_iid = InternalId.ci_pipelines
- .where(project_id: project.id)
- .last.last_value
-
- expect(last_iid).to be > 0
+ it 'raises error' do
+ expect { run_chain }.to raise_error(ActiveRecord::RecordNotSaved,
+ 'You cannot call create unless the parent is saved')
end
end
end
context 'when pipeline gets persisted during the process' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
+ before do
+ dependencies.each(&:perform!)
+ pipeline.save!
+ end
it 'raises error' do
- expect { run_chain }.to raise_error(described_class::PopulateError)
+ expect { step.perform! }.to raise_error(described_class::PopulateError)
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb
new file mode 100644
index 00000000000..85c8e20767f
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Pipeline::Chain::SeedBlock do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user, developer_projects: [project]) }
+ let(:seeds_block) { }
+
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project,
+ current_user: user,
+ origin_ref: 'master',
+ seeds_block: seeds_block)
+ end
+
+ let(:pipeline) { build(:ci_pipeline, project: project) }
+
+ describe '#perform!' do
+ before do
+ stub_ci_pipeline_yaml_file(YAML.dump(config))
+ end
+
+ subject(:run_chain) do
+ [
+ Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command)
+ ].map(&:perform!)
+
+ described_class.new(pipeline, command).perform!
+ end
+
+ let(:config) do
+ { rspec: { script: 'rake' } }
+ end
+
+ context 'when there is not seeds_block' do
+ it 'does nothing' do
+ expect { run_chain }.not_to raise_error
+ end
+ end
+
+ context 'when there is seeds_block' do
+ let(:seeds_block) do
+ ->(pipeline) { pipeline.variables.build(key: 'VAR', value: '123') }
+ end
+
+ it 'executes the block' do
+ run_chain
+
+ expect(pipeline.variables.size).to eq(1)
+ end
+
+ context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do
+ before do
+ stub_feature_flags(ci_seed_block_run_before_workflow_rules: false)
+ end
+
+ it 'does not execute the block' do
+ run_chain
+
+ expect(pipeline.variables.size).to eq(0)
+ end
+ end
+ end
+
+ context 'when the seeds_block tries to save the pipelie' do
+ let(:seeds_block) do
+ ->(pipeline) { pipeline.save! }
+ end
+
+ it 'raises error' do
+ expect { run_chain }.to raise_error('Pipeline cannot be persisted by `seeds_block`')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
index f83cd49d780..d849c768a3c 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
@@ -5,22 +5,14 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
let(:project) { create(:project, :repository) }
let(:user) { create(:user, developer_projects: [project]) }
+ let(:seeds_block) { }
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
current_user: user,
origin_ref: 'master',
- seeds_block: nil)
- end
-
- def run_chain(pipeline, command)
- [
- Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
- Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command)
- ].map(&:perform!)
-
- described_class.new(pipeline, command).perform!
+ seeds_block: seeds_block)
end
let(:pipeline) { build(:ci_pipeline, project: project) }
@@ -28,22 +20,36 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
describe '#perform!' do
before do
stub_ci_pipeline_yaml_file(YAML.dump(config))
- run_chain(pipeline, command)
end
let(:config) do
{ rspec: { script: 'rake' } }
end
+ subject(:run_chain) do
+ [
+ Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command)
+ ].map(&:perform!)
+
+ described_class.new(pipeline, command).perform!
+ end
+
it 'allocates next IID' do
+ run_chain
+
expect(pipeline.iid).to be_present
end
it 'ensures ci_ref' do
+ run_chain
+
expect(pipeline.ci_ref).to be_present
end
it 'sets the seeds in the command object' do
+ run_chain
+
expect(command.stage_seeds).to all(be_a Gitlab::Ci::Pipeline::Seed::Base)
expect(command.stage_seeds.count).to eq 1
end
@@ -58,6 +64,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'correctly fabricates a stage seeds object' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 2
expect(seeds.first.attributes[:name]).to eq 'test'
@@ -81,6 +89,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns stage seeds only assigned to master' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 1
@@ -100,6 +110,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns stage seeds only assigned to schedules' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 1
@@ -127,6 +139,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
let(:pipeline) { build(:ci_pipeline, project: project) }
it 'returns seeds for kubernetes dependent job' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 2
@@ -138,6 +152,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
context 'when kubernetes is not active' do
it 'does not return seeds for kubernetes dependent job' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 1
@@ -155,11 +171,39 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns stage seeds only when variables expression is truthy' do
+ run_chain
+
seeds = command.stage_seeds
expect(seeds.size).to eq 1
expect(seeds.dig(0, 0, :name)).to eq 'unit'
end
end
+
+ context 'when there is seeds_block' do
+ let(:seeds_block) do
+ ->(pipeline) { pipeline.variables.build(key: 'VAR', value: '123') }
+ end
+
+ context 'when FF ci_seed_block_run_before_workflow_rules is enabled' do
+ it 'does not execute the block' do
+ run_chain
+
+ expect(pipeline.variables.size).to eq(0)
+ end
+ end
+
+ context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do
+ before do
+ stub_feature_flags(ci_seed_block_run_before_workflow_rules: false)
+ end
+
+ it 'executes the block' do
+ run_chain
+
+ expect(pipeline.variables.size).to eq(1)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
index 0c8a0de2f34..e62bf042fba 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
@@ -16,20 +16,37 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
subject { seed.to_resource }
shared_examples_for 'returning a correct environment' do
+ let(:expected_auto_stop_in_seconds) do
+ if expected_auto_stop_in
+ ChronicDuration.parse(expected_auto_stop_in).seconds
+ end
+ end
+
it 'returns a persisted environment object' do
- expect { subject }.to change { Environment.count }.by(1)
+ freeze_time do
+ expect { subject }.to change { Environment.count }.by(1)
- expect(subject).to be_a(Environment)
- expect(subject).to be_persisted
- expect(subject.project).to eq(project)
- expect(subject.name).to eq(expected_environment_name)
+ expect(subject).to be_a(Environment)
+ expect(subject).to be_persisted
+ expect(subject.project).to eq(project)
+ expect(subject.name).to eq(expected_environment_name)
+ expect(subject.auto_stop_in).to eq(expected_auto_stop_in_seconds)
+ end
end
context 'when environment has already existed' do
- let!(:environment) { create(:environment, project: project, name: expected_environment_name) }
+ let!(:environment) do
+ create(:environment,
+ project: project,
+ name: expected_environment_name
+ ).tap do |env|
+ env.auto_stop_in = expected_auto_stop_in
+ end
+ end
it 'returns the existing environment object' do
expect { subject }.not_to change { Environment.count }
+ expect { subject }.not_to change { environment.auto_stop_at }
expect(subject).to be_persisted
expect(subject).to eq(environment)
@@ -37,9 +54,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
end
end
- context 'when job has environment attribute' do
+ context 'when job has environment name attribute' do
let(:environment_name) { 'production' }
let(:expected_environment_name) { 'production' }
+ let(:expected_auto_stop_in) { nil }
let(:attributes) do
{
@@ -49,11 +67,41 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
end
it_behaves_like 'returning a correct environment'
+
+ context 'and job environment also has an auto_stop_in attribute' do
+ let(:environment_auto_stop_in) { '5 minutes' }
+ let(:expected_auto_stop_in) { '5 minutes' }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: {
+ environment: {
+ name: environment_name,
+ auto_stop_in: environment_auto_stop_in
+ }
+ }
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+
+ context 'but the environment auto_stop_in on create flag is disabled' do
+ let(:expected_auto_stop_in) { nil }
+
+ before do
+ stub_feature_flags(environment_auto_stop_start_on_create: false)
+ end
+
+ it_behaves_like 'returning a correct environment'
+ end
+ end
end
context 'when job starts a review app' do
let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
let(:expected_environment_name) { "review/#{job.ref}" }
+ let(:expected_auto_stop_in) { nil }
let(:attributes) do
{
@@ -68,6 +116,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
context 'when job stops a review app' do
let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
let(:expected_environment_name) { "review/#{job.ref}" }
+ let(:expected_auto_stop_in) { nil }
let(:attributes) do
{
diff --git a/spec/lib/gitlab/ci/reports/test_case_spec.rb b/spec/lib/gitlab/ci/reports/test_case_spec.rb
index a142846fc18..668a475514e 100644
--- a/spec/lib/gitlab/ci/reports/test_case_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_case_spec.rb
@@ -2,13 +2,13 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Reports::TestCase do
+RSpec.describe Gitlab::Ci::Reports::TestCase, :aggregate_failures do
describe '#initialize' do
let(:test_case) { described_class.new(params) }
context 'when required params are given' do
let(:job) { build(:ci_build) }
- let(:params) { attributes_for(:test_case).merge!(job: job) }
+ let(:params) { attributes_for(:report_test_case).merge!(job: job) }
it 'initializes an instance', :aggregate_failures do
expect { test_case }.not_to raise_error
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
shared_examples 'param is missing' do |param|
let(:job) { build(:ci_build) }
- let(:params) { attributes_for(:test_case).merge!(job: job) }
+ let(:params) { attributes_for(:report_test_case).merge!(job: job) }
it 'raises an error' do
params.delete(param)
@@ -55,7 +55,7 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
context 'when attachment is present' do
let_it_be(:job) { create(:ci_build) }
- let(:attachment_test_case) { build(:test_case, :failed_with_attachment, job: job) }
+ let(:attachment_test_case) { build(:report_test_case, :failed_with_attachment, job: job) }
it "initializes the attachment if present" do
expect(attachment_test_case.attachment).to eq("some/path.png")
@@ -71,7 +71,7 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
end
context 'when attachment is missing' do
- let(:test_case) { build(:test_case) }
+ let(:test_case) { build(:report_test_case) }
it '#has_attachment?' do
expect(test_case.has_attachment?).to be_falsy
@@ -82,4 +82,17 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
end
end
end
+
+ describe '#set_recent_failures' do
+ it 'sets the recent_failures information' do
+ test_case = build(:report_test_case)
+
+ test_case.set_recent_failures(1, 'master')
+
+ expect(test_case.recent_failures).to eq(
+ count: 1,
+ base_branch: 'master'
+ )
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb b/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb
new file mode 100644
index 00000000000..8df34eddffd
--- /dev/null
+++ b/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Reports::TestFailureHistory, :aggregate_failures do
+ include TestReportsHelper
+
+ describe '#load!' do
+ let_it_be(:project) { create(:project) }
+ let(:failed_rspec) { create_test_case_rspec_failed }
+ let(:failed_java) { create_test_case_java_failed }
+
+ subject(:load_history) { described_class.new([failed_rspec, failed_java], project).load! }
+
+ before do
+ allow(Ci::TestCaseFailure)
+ .to receive(:recent_failures_count)
+ .with(project: project, test_case_keys: [failed_rspec.key, failed_java.key])
+ .and_return(
+ failed_rspec.key => 2,
+ failed_java.key => 1
+ )
+ end
+
+ it 'sets the recent failures for each matching failed test case in all test suites' do
+ load_history
+
+ expect(failed_rspec.recent_failures).to eq(count: 2, base_branch: 'master')
+ expect(failed_java.recent_failures).to eq(count: 1, base_branch: 'master')
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(test_failure_history: false)
+ end
+
+ it 'does not set recent failures' do
+ load_history
+
+ expect(failed_rspec.recent_failures).to be_nil
+ expect(failed_java.recent_failures).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/reports/test_reports_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_spec.rb
index 502859852f2..24c00de3731 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe Gitlab::Ci::Reports::TestReports do
end
describe '#with_attachment' do
- let(:test_case) { build(:test_case, :failed) }
+ let(:test_case) { build(:report_test_case, :failed) }
subject { test_reports.with_attachment! }
@@ -126,8 +126,8 @@ RSpec.describe Gitlab::Ci::Reports::TestReports do
end
context 'when test suites contain an attachment' do
- let(:test_case_succes) { build(:test_case) }
- let(:test_case_with_attachment) { build(:test_case, :failed_with_attachment) }
+ let(:test_case_succes) { build(:report_test_case) }
+ let(:test_case_with_attachment) { build(:report_test_case, :failed_with_attachment) }
before do
test_reports.get_suite('rspec').add_test_case(test_case_succes)
diff --git a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
index 6bb6771678a..c44d32ddb7d 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
@@ -2,11 +2,11 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
+RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer, :aggregate_failures do
include TestReportsHelper
let(:comparer) { described_class.new(name, base_suite, head_suite) }
- let(:name) { 'rpsec' }
+ let(:name) { 'rspec' }
let(:base_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:head_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:test_case_success) { create_test_case_java_success }
@@ -16,7 +16,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
describe '#new_failures' do
subject { comparer.new_failures }
- context 'when head sutie has a newly failed test case which does not exist in base' do
+ context 'when head suite has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie still has a failed test case which failed in base' do
+ context 'when head suite still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie has a success test case which failed in base' do
+ context 'when head suite has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_success)
@@ -53,7 +53,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
describe '#existing_failures' do
subject { comparer.existing_failures }
- context 'when head sutie has a newly failed test case which does not exist in base' do
+ context 'when head suite has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie still has a failed test case which failed in base' do
+ context 'when head suite still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
@@ -75,7 +75,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie has a success test case which failed in base' do
+ context 'when head suite has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_success)
@@ -90,7 +90,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
describe '#resolved_failures' do
subject { comparer.resolved_failures }
- context 'when head sutie has a newly failed test case which does not exist in base' do
+ context 'when head suite has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
@@ -105,7 +105,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie still has a failed test case which failed in base' do
+ context 'when head suite still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
@@ -120,7 +120,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
- context 'when head sutie has a success test case which failed in base' do
+ context 'when head suite has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_success)
@@ -347,4 +347,128 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
end
+
+ describe '#limited_tests' do
+ subject(:limited_tests) { comparer.limited_tests }
+
+ context 'limits amount of tests returned' do
+ before do
+ stub_const("#{described_class}::DEFAULT_MAX_TESTS", 2)
+ stub_const("#{described_class}::DEFAULT_MIN_TESTS", 1)
+ end
+
+ context 'prefers new over existing and resolved' do
+ before do
+ 3.times { add_new_failure }
+ 3.times { add_new_error }
+ 3.times { add_existing_failure }
+ 3.times { add_existing_error }
+ 3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
+ end
+
+ it 'returns 2 of each new category, and 1 of each resolved and existing' do
+ expect(limited_tests.new_failures.count).to eq(2)
+ expect(limited_tests.new_errors.count).to eq(2)
+ expect(limited_tests.existing_failures.count).to eq(1)
+ expect(limited_tests.existing_errors.count).to eq(1)
+ expect(limited_tests.resolved_failures.count).to eq(1)
+ expect(limited_tests.resolved_errors.count).to eq(1)
+ end
+
+ it 'does not affect the overall count' do
+ expect(summary).to include(total: 18, resolved: 6, failed: 6, errored: 6)
+ end
+ end
+
+ context 'prefers existing over resolved' do
+ before do
+ 3.times { add_existing_failure }
+ 3.times { add_existing_error }
+ 3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
+ end
+
+ it 'returns 2 of each existing category, and 1 of each resolved' do
+ expect(limited_tests.new_failures.count).to eq(0)
+ expect(limited_tests.new_errors.count).to eq(0)
+ expect(limited_tests.existing_failures.count).to eq(2)
+ expect(limited_tests.existing_errors.count).to eq(2)
+ expect(limited_tests.resolved_failures.count).to eq(1)
+ expect(limited_tests.resolved_errors.count).to eq(1)
+ end
+
+ it 'does not affect the overall count' do
+ expect(summary).to include(total: 12, resolved: 6, failed: 3, errored: 3)
+ end
+ end
+
+ context 'limits amount of resolved' do
+ before do
+ 3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
+ end
+
+ it 'returns 2 of each resolved category' do
+ expect(limited_tests.new_failures.count).to eq(0)
+ expect(limited_tests.new_errors.count).to eq(0)
+ expect(limited_tests.existing_failures.count).to eq(0)
+ expect(limited_tests.existing_errors.count).to eq(0)
+ expect(limited_tests.resolved_failures.count).to eq(2)
+ expect(limited_tests.resolved_errors.count).to eq(2)
+ end
+
+ it 'does not affect the overall count' do
+ expect(summary).to include(total: 6, resolved: 6, failed: 0, errored: 0)
+ end
+ end
+ end
+
+ def summary
+ {
+ total: comparer.total_count,
+ resolved: comparer.resolved_count,
+ failed: comparer.failed_count,
+ errored: comparer.error_count
+ }
+ end
+
+ def add_new_failure
+ failed_case = create_test_case_rspec_failed(SecureRandom.hex)
+ head_suite.add_test_case(failed_case)
+ end
+
+ def add_new_error
+ error_case = create_test_case_rspec_error(SecureRandom.hex)
+ head_suite.add_test_case(error_case)
+ end
+
+ def add_existing_failure
+ failed_case = create_test_case_rspec_failed(SecureRandom.hex)
+ base_suite.add_test_case(failed_case)
+ head_suite.add_test_case(failed_case)
+ end
+
+ def add_existing_error
+ error_case = create_test_case_rspec_error(SecureRandom.hex)
+ base_suite.add_test_case(error_case)
+ head_suite.add_test_case(error_case)
+ end
+
+ def add_resolved_failure
+ case_name = SecureRandom.hex
+ failed_case = create_test_case_java_failed(case_name)
+ success_case = create_test_case_java_success(case_name)
+ base_suite.add_test_case(failed_case)
+ head_suite.add_test_case(success_case)
+ end
+
+ def add_resolved_error
+ case_name = SecureRandom.hex
+ error_case = create_test_case_java_error(case_name)
+ success_case = create_test_case_java_success(case_name)
+ base_suite.add_test_case(error_case)
+ head_suite.add_test_case(success_case)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index 50d1595da73..1d6b39a7831 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -91,7 +91,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
subject { test_suite.with_attachment! }
context 'when test cases do not contain an attachment' do
- let(:test_case) { build(:test_case, :failed)}
+ let(:test_case) { build(:report_test_case, :failed)}
before do
test_suite.add_test_case(test_case)
@@ -103,7 +103,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
end
context 'when test cases contain an attachment' do
- let(:test_case_with_attachment) { build(:test_case, :failed_with_attachment)}
+ let(:test_case_with_attachment) { build(:report_test_case, :failed_with_attachment)}
before do
test_suite.add_test_case(test_case_with_attachment)
diff --git a/spec/lib/gitlab/ci/runner_instructions_spec.rb b/spec/lib/gitlab/ci/runner_instructions_spec.rb
index 32ee2ceb040..d1020026fe6 100644
--- a/spec/lib/gitlab/ci/runner_instructions_spec.rb
+++ b/spec/lib/gitlab/ci/runner_instructions_spec.rb
@@ -75,6 +75,13 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
with_them do
let(:params) { { os: os, arch: arch } }
+ around do |example|
+ # puma in production does not run from Rails.root, ensure file loading does not assume this
+ Dir.chdir(Rails.root.join('tmp').to_s) do
+ example.run
+ end
+ end
+
it 'returns string containing correct params' do
result = subject.install_script
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
new file mode 100644
index 00000000000..4be92e8608e
--- /dev/null
+++ b/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Deploy-ECS.gitlab-ci.yml' do
+ subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('AWS/Deploy-ECS') }
+
+ describe 'the created pipeline' do
+ let_it_be(:user) { create(:admin) }
+ let(:default_branch) { 'master' }
+ let(:pipeline_branch) { default_branch }
+ let(:project) { create(:project, :auto_devops, :custom_repo, files: { 'README.md' => '' }) }
+ let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
+ let(:pipeline) { service.execute!(:push) }
+ let(:build_names) { pipeline.builds.pluck(:name) }
+ let(:platform_target) { 'ECS' }
+
+ before do
+ create(:ci_variable, project: project, key: 'AUTO_DEVOPS_PLATFORM_TARGET', value: platform_target)
+ stub_ci_pipeline_yaml_file(template.content)
+ allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true)
+ allow(project).to receive(:default_branch).and_return(default_branch)
+ end
+
+ shared_examples 'no pipeline yaml error' do
+ it 'does not have any error' do
+ expect(pipeline.has_yaml_errors?).to be_falsey
+ end
+ end
+
+ it_behaves_like 'no pipeline yaml error'
+
+ it 'creates the expected jobs' do
+ expect(build_names).to include('production_ecs')
+ end
+
+ context 'when running a pipeline for a branch' do
+ let(:pipeline_branch) { 'test_branch' }
+
+ before do
+ project.repository.create_branch(pipeline_branch)
+ end
+
+ it_behaves_like 'no pipeline yaml error'
+
+ it 'creates the expected jobs' do
+ expect(build_names).to include('review_ecs', 'stop_review_ecs')
+ end
+
+ context 'when deploying to ECS Fargate' do
+ let(:platform_target) { 'FARGATE' }
+
+ it 'creates the expected jobs' do
+ expect(build_names).to include('review_fargate', 'stop_review_fargate')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
index 4d90e7ca9e6..793df55f45d 100644
--- a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
@@ -94,14 +94,14 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml' do
end
it 'creates an ECS deployment job for review only' do
- expect(review_prod_build_names).to contain_exactly('review_ecs')
+ expect(review_prod_build_names).to contain_exactly('review_ecs', 'stop_review_ecs')
end
context 'with FARGATE as a launch type' do
let(:platform_value) { 'FARGATE' }
it 'creates an FARGATE deployment job for review only' do
- expect(review_prod_build_names).to contain_exactly('review_fargate')
+ expect(review_prod_build_names).to contain_exactly('review_fargate', 'stop_review_fargate')
end
end
end
@@ -122,6 +122,15 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml' do
end
end
end
+
+ context 'when the platform target is EC2' do
+ let(:platform_value) { 'EC2' }
+
+ it 'contains the build_artifact job, not the build job' do
+ expect(build_names).to include('build_artifact')
+ expect(build_names).not_to include('build')
+ end
+ end
end
context 'when the project has no active cluster' do
diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
index eba2f29836d..2e43f22830a 100644
--- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
@@ -15,14 +15,14 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
context 'when unknown keyword is specified' do
it 'raises error' do
expect { described_class.new(key: variable_key, value: 'abc', files: true) }
- .to raise_error ArgumentError, 'unknown keyword: files'
+ .to raise_error ArgumentError, 'unknown keyword: :files'
end
end
context 'when required keywords are not specified' do
it 'raises error' do
expect { described_class.new(key: variable_key) }
- .to raise_error ArgumentError, 'missing keyword: value'
+ .to raise_error ArgumentError, 'missing keyword: :value'
end
end