summaryrefslogtreecommitdiff
path: root/spec/models/ci
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:40:28 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:40:28 +0000
commitb595cb0c1dec83de5bdee18284abe86614bed33b (patch)
tree8c3d4540f193c5ff98019352f554e921b3a41a72 /spec/models/ci
parent2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff)
downloadgitlab-ce-b595cb0c1dec83de5bdee18284abe86614bed33b.tar.gz
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'spec/models/ci')
-rw-r--r--spec/models/ci/build_report_result_spec.rb6
-rw-r--r--spec/models/ci/build_spec.rb172
-rw-r--r--spec/models/ci/group_spec.rb2
-rw-r--r--spec/models/ci/group_variable_spec.rb6
-rw-r--r--spec/models/ci/legacy_stage_spec.rb268
-rw-r--r--spec/models/ci/pending_build_spec.rb58
-rw-r--r--spec/models/ci/pipeline_artifact_spec.rb74
-rw-r--r--spec/models/ci/pipeline_spec.rb287
-rw-r--r--spec/models/ci/processable_spec.rb4
-rw-r--r--spec/models/ci/runner_spec.rb147
-rw-r--r--spec/models/ci/runner_version_spec.rb53
-rw-r--r--spec/models/ci/stage_spec.rb28
-rw-r--r--spec/models/ci/variable_spec.rb6
13 files changed, 541 insertions, 570 deletions
diff --git a/spec/models/ci/build_report_result_spec.rb b/spec/models/ci/build_report_result_spec.rb
index 3f53c6c1c0e..09ea19cf077 100644
--- a/spec/models/ci/build_report_result_spec.rb
+++ b/spec/models/ci/build_report_result_spec.rb
@@ -70,10 +70,4 @@ RSpec.describe Ci::BuildReportResult do
expect(build_report_result.tests_skipped).to eq(0)
end
end
-
- describe '#tests_total' do
- it 'returns the total count' do
- expect(build_report_result.tests_total).to eq(2)
- end
- end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 6ad6bb16eb5..e0166ba64a4 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -43,30 +43,10 @@ RSpec.describe Ci::Build do
it { is_expected.to delegate_method(:legacy_detached_merge_request_pipeline?).to(:pipeline) }
shared_examples 'calling proper BuildFinishedWorker' do
- context 'when ci_build_finished_worker_namespace_changed feature flag enabled' do
- before do
- stub_feature_flags(ci_build_finished_worker_namespace_changed: build.project)
- end
-
- it 'calls Ci::BuildFinishedWorker' do
- expect(Ci::BuildFinishedWorker).to receive(:perform_async)
- expect(::BuildFinishedWorker).not_to receive(:perform_async)
-
- subject
- end
- end
-
- context 'when ci_build_finished_worker_namespace_changed feature flag disabled' do
- before do
- stub_feature_flags(ci_build_finished_worker_namespace_changed: false)
- end
-
- it 'calls ::BuildFinishedWorker' do
- expect(::BuildFinishedWorker).to receive(:perform_async)
- expect(Ci::BuildFinishedWorker).not_to receive(:perform_async)
+ it 'calls Ci::BuildFinishedWorker' do
+ expect(Ci::BuildFinishedWorker).to receive(:perform_async)
- subject
- end
+ subject
end
end
@@ -1364,7 +1344,7 @@ RSpec.describe Ci::Build do
before do
allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
- allow(deployment).to receive(:execute_hooks)
+ allow(Deployments::HooksWorker).to receive(:perform_async)
end
it 'has deployments record with created status' do
@@ -1420,7 +1400,7 @@ RSpec.describe Ci::Build do
before do
allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
- allow(deployment).to receive(:execute_hooks)
+ allow(Deployments::HooksWorker).to receive(:perform_async)
end
it_behaves_like 'avoid deadlock'
@@ -1506,28 +1486,14 @@ RSpec.describe Ci::Build do
it 'transitions to running and calls webhook' do
freeze_time do
- expect(deployment).to receive(:execute_hooks).with(Time.current)
+ expect(Deployments::HooksWorker)
+ .to receive(:perform_async).with(deployment_id: deployment.id, status: 'running', status_changed_at: Time.current)
subject
end
expect(deployment).to be_running
end
-
- context 'when `deployment_hooks_skip_worker` flag is disabled' do
- before do
- stub_feature_flags(deployment_hooks_skip_worker: false)
- end
-
- it 'executes Deployments::HooksWorker asynchronously' do
- freeze_time do
- expect(Deployments::HooksWorker)
- .to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
-
- subject
- end
- end
- end
end
end
end
@@ -1567,48 +1533,47 @@ RSpec.describe Ci::Build do
end
end
- describe 'deployment' do
- describe '#outdated_deployment?' do
- subject { build.outdated_deployment? }
-
- context 'when build succeeded' do
- let(:build) { create(:ci_build, :success) }
- let!(:deployment) { create(:deployment, :success, deployable: build) }
+ describe 'environment' do
+ describe '#has_environment?' do
+ subject { build.has_environment? }
- context 'current deployment is latest' do
- it { is_expected.to be_falsey }
+ context 'when environment is defined' do
+ before do
+ build.update!(environment: 'review')
end
- context 'current deployment is not latest on environment' do
- let!(:deployment2) { create(:deployment, :success, environment: deployment.environment) }
-
- it { is_expected.to be_truthy }
- end
+ it { is_expected.to be_truthy }
end
- context 'when build failed' do
- let(:build) { create(:ci_build, :failed) }
+ context 'when environment is not defined' do
+ before do
+ build.update!(environment: nil)
+ end
it { is_expected.to be_falsey }
end
end
- end
- describe 'environment' do
- describe '#has_environment?' do
- subject { build.has_environment? }
+ describe '#count_user_verification?' do
+ subject { build.count_user_verification? }
- context 'when environment is defined' do
- before do
- build.update!(environment: 'review')
+ context 'when build is the verify action for the environment' do
+ let(:build) do
+ create(:ci_build,
+ ref: 'master',
+ environment: 'staging',
+ options: { environment: { action: 'verify' } })
end
it { is_expected.to be_truthy }
end
- context 'when environment is not defined' do
- before do
- build.update!(environment: nil)
+ context 'when build is not the verify action for the environment' do
+ let(:build) do
+ create(:ci_build,
+ ref: 'master',
+ environment: 'staging',
+ options: { environment: { action: 'start' } })
end
it { is_expected.to be_falsey }
@@ -1975,16 +1940,6 @@ RSpec.describe Ci::Build do
end
end
- describe '#first_pending' do
- let!(:first) { create(:ci_build, pipeline: pipeline, status: 'pending', created_at: Date.yesterday) }
- let!(:second) { create(:ci_build, pipeline: pipeline, status: 'pending') }
-
- subject { described_class.first_pending }
-
- it { is_expected.to be_a(described_class) }
- it('returns with the first pending build') { is_expected.to eq(first) }
- end
-
describe '#failed_but_allowed?' do
subject { build.failed_but_allowed? }
@@ -2134,6 +2089,34 @@ RSpec.describe Ci::Build do
end
end
+ describe '#save_tags' do
+ let(:build) { create(:ci_build, tag_list: ['tag']) }
+
+ it 'saves tags' do
+ build.save!
+
+ expect(build.tags.count).to eq(1)
+ expect(build.tags.first.name).to eq('tag')
+ end
+
+ it 'strips tags' do
+ build.tag_list = [' taga', 'tagb ', ' tagc ']
+
+ build.save!
+ expect(build.tags.map(&:name)).to match_array(%w[taga tagb tagc])
+ end
+
+ context 'with BulkInsertableTags.with_bulk_insert_tags' do
+ it 'does not save_tags' do
+ Ci::BulkInsertableTags.with_bulk_insert_tags do
+ build.save!
+ end
+
+ expect(build.tags).to be_empty
+ end
+ end
+ end
+
describe '#has_tags?' do
context 'when build has tags' do
subject { create(:ci_build, tag_list: ['tag']) }
@@ -2641,7 +2624,7 @@ RSpec.describe Ci::Build do
context 'when token is empty' do
before do
- build.update_columns(token: nil, token_encrypted: nil)
+ build.update_columns(token_encrypted: nil)
end
it { is_expected.to be_nil}
@@ -3294,10 +3277,6 @@ RSpec.describe Ci::Build do
let(:trigger) { create(:ci_trigger, project: project) }
let(:trigger_request) { create(:ci_trigger_request, pipeline: pipeline, trigger: trigger) }
- let(:user_trigger_variable) do
- { key: 'TRIGGER_KEY_1', value: 'TRIGGER_VALUE_1', public: false, masked: false }
- end
-
let(:predefined_trigger_variable) do
{ key: 'CI_PIPELINE_TRIGGERED', value: 'true', public: true, masked: false }
end
@@ -3306,26 +3285,7 @@ RSpec.describe Ci::Build do
build.trigger_request = trigger_request
end
- shared_examples 'returns variables for triggers' do
- it { is_expected.to include(user_trigger_variable) }
- it { is_expected.to include(predefined_trigger_variable) }
- end
-
- context 'when variables are stored in trigger_request' do
- before do
- trigger_request.update_attribute(:variables, { 'TRIGGER_KEY_1' => 'TRIGGER_VALUE_1' } )
- end
-
- it_behaves_like 'returns variables for triggers'
- end
-
- context 'when variables are stored in pipeline_variables' do
- before do
- create(:ci_pipeline_variable, pipeline: pipeline, key: 'TRIGGER_KEY_1', value: 'TRIGGER_VALUE_1')
- end
-
- it_behaves_like 'returns variables for triggers'
- end
+ it { is_expected.to include(predefined_trigger_variable) }
end
context 'when pipeline has a variable' do
@@ -3848,7 +3808,7 @@ RSpec.describe Ci::Build do
end
it 'queues BuildHooksWorker' do
- expect(BuildHooksWorker).to receive(:perform_async).with(build.id)
+ expect(BuildHooksWorker).to receive(:perform_async).with(build)
build.enqueue
end
@@ -4321,7 +4281,7 @@ RSpec.describe Ci::Build do
describe '#collect_test_reports!' do
subject { build.collect_test_reports!(test_reports) }
- let(:test_reports) { Gitlab::Ci::Reports::TestReports.new }
+ let(:test_reports) { Gitlab::Ci::Reports::TestReport.new }
it { expect(test_reports.get_suite(build.name).total_count).to eq(0) }
@@ -4372,7 +4332,7 @@ RSpec.describe Ci::Build do
context 'when build is part of parallel build' do
let(:build_1) { create(:ci_build, name: 'build 1/2') }
- let(:test_report) { Gitlab::Ci::Reports::TestReports.new }
+ let(:test_report) { Gitlab::Ci::Reports::TestReport.new }
before do
build_1.collect_test_reports!(test_report)
@@ -4396,7 +4356,7 @@ RSpec.describe Ci::Build do
end
context 'when build is part of matrix build' do
- let(:test_report) { Gitlab::Ci::Reports::TestReports.new }
+ let(:test_report) { Gitlab::Ci::Reports::TestReport.new }
let(:matrix_build_1) { create(:ci_build, :matrix) }
before do
diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb
index 6c96e659a34..4900bc792af 100644
--- a/spec/models/ci/group_spec.rb
+++ b/spec/models/ci/group_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe Ci::Group do
describe '.fabricate' do
let(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { create(:ci_stage_entity, pipeline: pipeline) }
+ let(:stage) { create(:ci_stage, pipeline: pipeline) }
before do
create_build(:ci_build, name: 'rspec 0 2')
diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb
index 3a4b836e453..fc5a9c879f6 100644
--- a/spec/models/ci/group_variable_spec.rb
+++ b/spec/models/ci/group_variable_spec.rb
@@ -56,4 +56,10 @@ RSpec.describe Ci::GroupVariable do
let!(:parent) { model.group }
end
+
+ describe '#audit_details' do
+ it "equals to the group variable's key" do
+ expect(subject.audit_details).to eq(subject.key)
+ end
+ end
end
diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb
deleted file mode 100644
index 2487ad85889..00000000000
--- a/spec/models/ci/legacy_stage_spec.rb
+++ /dev/null
@@ -1,268 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Ci::LegacyStage do
- let(:stage) { build(:ci_stage) }
- let(:pipeline) { stage.pipeline }
- let(:stage_name) { stage.name }
-
- describe '#expectations' do
- subject { stage }
-
- it { is_expected.to include_module(StaticModel) }
-
- it { is_expected.to respond_to(:pipeline) }
- it { is_expected.to respond_to(:name) }
-
- it { is_expected.to delegate_method(:project).to(:pipeline) }
- end
-
- describe '#statuses' do
- let!(:stage_build) { create_job(:ci_build) }
- let!(:commit_status) { create_job(:commit_status) }
- let!(:other_build) { create_job(:ci_build, stage: 'other stage') }
-
- subject { stage.statuses }
-
- it "returns only matching statuses" do
- is_expected.to contain_exactly(stage_build, commit_status)
- end
- end
-
- describe '#groups' do
- before do
- create_job(:ci_build, name: 'rspec 0 2')
- create_job(:ci_build, name: 'rspec 0 1')
- create_job(:ci_build, name: 'spinach 0 1')
- create_job(:commit_status, name: 'aaaaa')
- end
-
- it 'returns an array of three groups' do
- expect(stage.groups).to be_a Array
- expect(stage.groups).to all(be_a Ci::Group)
- expect(stage.groups.size).to eq 3
- end
-
- it 'returns groups with correctly ordered statuses' do
- expect(stage.groups.first.jobs.map(&:name))
- .to eq ['aaaaa']
- expect(stage.groups.second.jobs.map(&:name))
- .to eq ['rspec 0 1', 'rspec 0 2']
- expect(stage.groups.third.jobs.map(&:name))
- .to eq ['spinach 0 1']
- end
-
- it 'returns groups with correct names' do
- expect(stage.groups.map(&:name))
- .to eq %w[aaaaa rspec spinach]
- end
-
- context 'when a name is nil on legacy pipelines' do
- before do
- pipeline.builds.first.update_attribute(:name, nil)
- end
-
- it 'returns an array of three groups' do
- expect(stage.groups.map(&:name))
- .to eq ['', 'aaaaa', 'rspec', 'spinach']
- end
- end
- end
-
- describe '#statuses_count' do
- before do
- create_job(:ci_build)
- create_job(:ci_build, stage: 'other stage')
- end
-
- subject { stage.statuses_count }
-
- it "counts statuses only from current stage" do
- is_expected.to eq(1)
- end
- end
-
- describe '#builds' do
- let!(:stage_build) { create_job(:ci_build) }
- let!(:commit_status) { create_job(:commit_status) }
-
- subject { stage.builds }
-
- it "returns only builds" do
- is_expected.to contain_exactly(stage_build)
- end
- end
-
- describe '#status' do
- subject { stage.status }
-
- context 'if status is already defined' do
- let(:stage) { build(:ci_stage, status: 'success') }
-
- it "returns defined status" do
- is_expected.to eq('success')
- end
- end
-
- context 'if status has to be calculated' do
- let!(:stage_build) { create_job(:ci_build, status: :failed) }
-
- it "returns status of a build" do
- is_expected.to eq('failed')
- end
-
- context 'and builds are retried' do
- let!(:new_build) { create_job(:ci_build, status: :success) }
-
- before do
- stage_build.update!(retried: true)
- end
-
- it "returns status of latest build" do
- is_expected.to eq('success')
- end
- end
- end
- end
-
- describe '#detailed_status' do
- let(:user) { create(:user) }
-
- subject { stage.detailed_status(user) }
-
- context 'when build is created' do
- let!(:stage_build) { create_job(:ci_build, status: :created) }
-
- it 'returns detailed status for created stage' do
- expect(subject.text).to eq s_('CiStatusText|created')
- end
- end
-
- context 'when build is pending' do
- let!(:stage_build) { create_job(:ci_build, status: :pending) }
-
- it 'returns detailed status for pending stage' do
- expect(subject.text).to eq s_('CiStatusText|pending')
- end
- end
-
- context 'when build is running' do
- let!(:stage_build) { create_job(:ci_build, status: :running) }
-
- it 'returns detailed status for running stage' do
- expect(subject.text).to eq s_('CiStatus|running')
- end
- end
-
- context 'when build is successful' do
- let!(:stage_build) { create_job(:ci_build, status: :success) }
-
- it 'returns detailed status for successful stage' do
- expect(subject.text).to eq s_('CiStatusText|passed')
- end
- end
-
- context 'when build is failed' do
- let!(:stage_build) { create_job(:ci_build, status: :failed) }
-
- it 'returns detailed status for failed stage' do
- expect(subject.text).to eq s_('CiStatusText|failed')
- end
- end
-
- context 'when build is canceled' do
- let!(:stage_build) { create_job(:ci_build, status: :canceled) }
-
- it 'returns detailed status for canceled stage' do
- expect(subject.text).to eq s_('CiStatusText|canceled')
- end
- end
-
- context 'when build is skipped' do
- let!(:stage_build) { create_job(:ci_build, status: :skipped) }
-
- it 'returns detailed status for skipped stage' do
- expect(subject.text).to eq s_('CiStatusText|skipped')
- end
- end
- end
-
- describe '#success?' do
- context 'when stage is successful' do
- before do
- create_job(:ci_build, status: :success)
- create_job(:generic_commit_status, status: :success)
- end
-
- it 'is successful' do
- expect(stage).to be_success
- end
- end
-
- context 'when stage is not successful' do
- before do
- create_job(:ci_build, status: :failed)
- create_job(:generic_commit_status, status: :success)
- end
-
- it 'is not successful' do
- expect(stage).not_to be_success
- end
- end
- end
-
- describe '#has_warnings?' do
- context 'when stage has warnings' do
- context 'when using memoized warnings flag' do
- context 'when there are warnings' do
- let(:stage) { build(:ci_stage, warnings: true) }
-
- it 'returns true using memoized value' do
- expect(stage).not_to receive(:statuses)
- expect(stage).to have_warnings
- end
- end
-
- context 'when there are no warnings' do
- let(:stage) { build(:ci_stage, warnings: false) }
-
- it 'returns false using memoized value' do
- expect(stage).not_to receive(:statuses)
- expect(stage).not_to have_warnings
- end
- end
- end
-
- context 'when calculating warnings from statuses' do
- before do
- create(:ci_build, :failed, :allowed_to_fail,
- stage: stage_name, pipeline: pipeline)
- end
-
- it 'has warnings calculated from statuses' do
- expect(stage).to receive(:statuses).and_call_original
- expect(stage).to have_warnings
- end
- end
- end
-
- context 'when stage does not have warnings' do
- before do
- create(:ci_build, :success, stage: stage_name,
- pipeline: pipeline)
- end
-
- it 'does not have warnings calculated from statuses' do
- expect(stage).to receive(:statuses).and_call_original
- expect(stage).not_to have_warnings
- end
- end
- end
-
- def create_job(type, status: 'success', stage: stage_name, **opts)
- create(type, pipeline: pipeline, stage: stage, status: status, **opts)
- end
-
- it_behaves_like 'manual playable stage', :ci_stage
-end
diff --git a/spec/models/ci/pending_build_spec.rb b/spec/models/ci/pending_build_spec.rb
index 5692444339f..4bb43233dbd 100644
--- a/spec/models/ci/pending_build_spec.rb
+++ b/spec/models/ci/pending_build_spec.rb
@@ -118,41 +118,27 @@ RSpec.describe Ci::PendingBuild do
project.shared_runners_enabled = true
end
- context 'when ci_pending_builds_maintain_denormalized_data is enabled' do
- it 'sets instance_runners_enabled to true' do
- described_class.upsert_from_build!(build)
-
- expect(described_class.last.instance_runners_enabled).to be_truthy
- end
-
- context 'when project is about to be deleted' do
- before do
- build.project.update!(pending_delete: true)
- end
+ it 'sets instance_runners_enabled to true' do
+ described_class.upsert_from_build!(build)
- it 'sets instance_runners_enabled to false' do
- described_class.upsert_from_build!(build)
+ expect(described_class.last.instance_runners_enabled).to be_truthy
+ end
- expect(described_class.last.instance_runners_enabled).to be_falsey
- end
+ context 'when project is about to be deleted' do
+ before do
+ build.project.update!(pending_delete: true)
end
- context 'when builds are disabled' do
- before do
- build.project.project_feature.update!(builds_access_level: false)
- end
-
- it 'sets instance_runners_enabled to false' do
- described_class.upsert_from_build!(build)
+ it 'sets instance_runners_enabled to false' do
+ described_class.upsert_from_build!(build)
- expect(described_class.last.instance_runners_enabled).to be_falsey
- end
+ expect(described_class.last.instance_runners_enabled).to be_falsey
end
end
- context 'when ci_pending_builds_maintain_denormalized_data is disabled' do
+ context 'when builds are disabled' do
before do
- stub_feature_flags(ci_pending_builds_maintain_denormalized_data: false)
+ build.project.project_feature.update!(builds_access_level: false)
end
it 'sets instance_runners_enabled to false' do
@@ -168,24 +154,10 @@ RSpec.describe Ci::PendingBuild do
subject(:ci_pending_build) { described_class.last }
- context 'when ci_pending_builds_maintain_denormalized_data is enabled' do
- it 'sets tag_ids' do
- described_class.upsert_from_build!(build)
-
- expect(ci_pending_build.tag_ids).to eq(build.tags_ids)
- end
- end
-
- context 'when ci_pending_builds_maintain_denormalized_data is disabled' do
- before do
- stub_feature_flags(ci_pending_builds_maintain_denormalized_data: false)
- end
-
- it 'does not set tag_ids' do
- described_class.upsert_from_build!(build)
+ it 'sets tag_ids' do
+ described_class.upsert_from_build!(build)
- expect(ci_pending_build.tag_ids).to be_empty
- end
+ expect(ci_pending_build.tag_ids).to eq(build.tags_ids)
end
end
diff --git a/spec/models/ci/pipeline_artifact_spec.rb b/spec/models/ci/pipeline_artifact_spec.rb
index 801505f0231..b051f646bd4 100644
--- a/spec/models/ci/pipeline_artifact_spec.rb
+++ b/spec/models/ci/pipeline_artifact_spec.rb
@@ -196,6 +196,80 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
end
end
+ describe '.create_or_replace_for_pipeline!' do
+ let_it_be(:pipeline) { create(:ci_empty_pipeline) }
+
+ let(:file_type) { :code_coverage }
+ let(:file) { CarrierWaveStringFile.new_file(file_content: 'content', filename: 'file.json', content_type: 'json') }
+ let(:size) { file['tempfile'].size }
+
+ subject do
+ Ci::PipelineArtifact.create_or_replace_for_pipeline!(
+ pipeline: pipeline,
+ file_type: file_type,
+ file: file,
+ size: size
+ )
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ context 'when there is no existing record' do
+ it 'creates a new pipeline artifact for the given parameters' do
+ expect { subject }.to change { Ci::PipelineArtifact.count }.from(0).to(1)
+
+ expect(subject.code_coverage?).to be(true)
+ expect(subject.pipeline).to eq(pipeline)
+ expect(subject.project_id).to eq(pipeline.project_id)
+ expect(subject.file.filename).to eq(file['filename'])
+ expect(subject.size).to eq(size)
+ expect(subject.file_format).to eq(Ci::PipelineArtifact::REPORT_TYPES[file_type].to_s)
+ expect(subject.expire_at).to eq(Ci::PipelineArtifact::EXPIRATION_DATE.from_now)
+ end
+ end
+
+ context 'when there are existing records with different types' do
+ let!(:existing_artifact) do
+ create(:ci_pipeline_artifact, pipeline: pipeline, file_type: file_type, expire_at: 1.day.from_now)
+ end
+
+ let!(:other_artifact) { create(:ci_pipeline_artifact, pipeline: pipeline, file_type: :code_quality_mr_diff) }
+
+ it 'replaces the existing pipeline artifact record with the given file type' do
+ expect { subject }.not_to change { Ci::PipelineArtifact.count }
+
+ expect(subject.id).not_to eq(existing_artifact.id)
+
+ expect(subject.code_coverage?).to be(true)
+ expect(subject.pipeline).to eq(pipeline)
+ expect(subject.project_id).to eq(pipeline.project_id)
+ expect(subject.file.filename).to eq(file['filename'])
+ expect(subject.size).to eq(size)
+ expect(subject.file_format).to eq(Ci::PipelineArtifact::REPORT_TYPES[file_type].to_s)
+ expect(subject.expire_at).to eq(Ci::PipelineArtifact::EXPIRATION_DATE.from_now)
+ end
+ end
+
+ context 'when ActiveRecordError is raised' do
+ let(:pipeline) { instance_double(Ci::Pipeline, id: 1) }
+ let(:file_type) { :code_coverage }
+ let(:error) { ActiveRecord::ActiveRecordError.new('something went wrong') }
+
+ before do
+ allow(pipeline).to receive(:pipeline_artifacts).and_raise(error)
+ end
+
+ it 'tracks and raise the exception' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_exception)
+ .with(error, { pipeline_id: pipeline.id, file_type: file_type }).and_call_original
+
+ expect { subject }.to raise_error(ActiveRecord::ActiveRecordError, 'something went wrong')
+ end
+ end
+ end
+
describe '#present' do
subject(:presenter) { report.present }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 31752f300f4..081fa6cbbae 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -106,6 +106,50 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe 'state machine transitions' do
+ context 'from failed to success' do
+ let_it_be(:pipeline) { create(:ci_empty_pipeline, :failed) }
+
+ it 'schedules CoverageReportWorker' do
+ expect(Ci::PipelineArtifacts::CoverageReportWorker).to receive(:perform_async).with(pipeline.id)
+
+ pipeline.succeed!
+ end
+ end
+ end
+
+ describe 'pipeline age metric' do
+ let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
+
+ let(:pipeline_age_histogram) do
+ ::Gitlab::Ci::Pipeline::Metrics.pipeline_age_histogram
+ end
+
+ context 'when pipeline age histogram is enabled' do
+ before do
+ stub_feature_flags(ci_pipeline_age_histogram: true)
+ end
+
+ it 'observes pipeline age' do
+ expect(pipeline_age_histogram).to receive(:observe)
+
+ described_class.find(pipeline.id)
+ end
+ end
+
+ context 'when pipeline age histogram is disabled' do
+ before do
+ stub_feature_flags(ci_pipeline_age_histogram: false)
+ end
+
+ it 'observes pipeline age' do
+ expect(pipeline_age_histogram).not_to receive(:observe)
+
+ described_class.find(pipeline.id)
+ end
+ end
+ end
+
describe '#set_status' do
let(:pipeline) { build(:ci_empty_pipeline, :created) }
@@ -167,6 +211,28 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe '.created_after' do
+ let_it_be(:old_pipeline) { create(:ci_pipeline, created_at: 1.week.ago) }
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+
+ subject { described_class.created_after(1.day.ago) }
+
+ it 'returns the pipeline' do
+ is_expected.to contain_exactly(pipeline)
+ end
+ end
+
+ describe '.created_before_id' do
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+ let_it_be(:new_pipeline) { create(:ci_pipeline) }
+
+ subject { described_class.created_before_id(new_pipeline.id) }
+
+ it 'returns the pipeline' do
+ is_expected.to contain_exactly(pipeline)
+ end
+ end
+
describe '.for_sha' do
subject { described_class.for_sha(sha) }
@@ -997,6 +1063,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
'CI_MERGE_REQUEST_PROJECT_PATH' => merge_request.project.full_path,
'CI_MERGE_REQUEST_PROJECT_URL' => merge_request.project.web_url,
'CI_MERGE_REQUEST_TARGET_BRANCH_NAME' => merge_request.target_branch.to_s,
+ 'CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED' => ProtectedBranch.protected?(merge_request.target_project, merge_request.target_branch).to_s,
'CI_MERGE_REQUEST_TARGET_BRANCH_SHA' => '',
'CI_MERGE_REQUEST_SOURCE_PROJECT_ID' => merge_request.source_project.id.to_s,
'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' => merge_request.source_project.full_path,
@@ -1093,6 +1160,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
'CI_MERGE_REQUEST_PROJECT_PATH' => merge_request.project.full_path,
'CI_MERGE_REQUEST_PROJECT_URL' => merge_request.project.web_url,
'CI_MERGE_REQUEST_TARGET_BRANCH_NAME' => merge_request.target_branch.to_s,
+ 'CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED' => ProtectedBranch.protected?(merge_request.target_project, merge_request.target_branch).to_s,
'CI_MERGE_REQUEST_TARGET_BRANCH_SHA' => merge_request.target_branch_sha,
'CI_MERGE_REQUEST_SOURCE_PROJECT_ID' => merge_request.source_project.id.to_s,
'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' => merge_request.source_project.full_path,
@@ -1289,48 +1357,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
status: 'success')
end
- describe '#legacy_stages' do
- using RSpec::Parameterized::TableSyntax
-
- subject { pipeline.legacy_stages }
-
- context 'stages list' do
- it 'returns ordered list of stages' do
- expect(subject.map(&:name)).to eq(%w[build test deploy])
- end
- end
-
- context 'stages with statuses' do
- let(:statuses) do
- subject.map { |stage| [stage.name, stage.status] }
- end
-
- it 'returns list of stages with correct statuses' do
- expect(statuses).to eq([%w(build failed),
- %w(test success),
- %w(deploy running)])
- end
- end
-
- context 'when there is a stage with warnings' do
- before do
- create(:commit_status, pipeline: pipeline,
- stage: 'deploy',
- name: 'prod:2',
- stage_idx: 2,
- status: 'failed',
- allow_failure: true)
- end
-
- it 'populates stage with correct number of warnings' do
- deploy_stage = pipeline.legacy_stages.third
-
- expect(deploy_stage).not_to receive(:statuses)
- expect(deploy_stage).to have_warnings
- end
- end
- end
-
describe '#stages_count' do
it 'returns a valid number of stages' do
expect(pipeline.stages_count).to eq(3)
@@ -1344,37 +1370,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
- describe '#legacy_stage' do
- subject { pipeline.legacy_stage('test') }
-
- let(:pipeline) { build(:ci_empty_pipeline, :created) }
-
- context 'with status in stage' do
- before do
- create(:commit_status, pipeline: pipeline, stage: 'test')
- end
-
- it { expect(subject).to be_a Ci::LegacyStage }
- it { expect(subject.name).to eq 'test' }
- it { expect(subject.statuses).not_to be_empty }
- end
-
- context 'without status in stage' do
- before do
- create(:commit_status, pipeline: pipeline, stage: 'build')
- end
-
- it 'return stage object' do
- is_expected.to be_nil
- end
- end
- end
-
describe '#stages' do
let(:pipeline) { build(:ci_empty_pipeline, :created) }
before do
- create(:ci_stage_entity, project: project,
+ create(:ci_stage, project: project,
pipeline: pipeline,
position: 4,
name: 'deploy')
@@ -1391,12 +1391,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
stage_idx: 2,
name: 'build')
- create(:ci_stage_entity, project: project,
+ create(:ci_stage, project: project,
pipeline: pipeline,
position: 1,
name: 'sanity')
- create(:ci_stage_entity, project: project,
+ create(:ci_stage, project: project,
pipeline: pipeline,
position: 5,
name: 'cleanup')
@@ -1435,7 +1435,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
let(:build_c) { create_build('build3', queued_at: 0) }
%w[succeed! drop! cancel! skip! block! delay!].each do |action|
- context "when the pipeline recieved #{action} event" do
+ context "when the pipeline received #{action} event" do
it 'deletes a persistent ref' do
expect(pipeline.persistent_ref).to receive(:delete).once
@@ -1658,7 +1658,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
%w[succeed! drop! cancel! skip!].each do |action|
- context "when the pipeline recieved #{action} event" do
+ context "when the pipeline received #{action} event" do
it 'performs AutoMergeProcessWorker' do
expect(AutoMergeProcessWorker).to receive(:perform_async).with(merge_request.id)
@@ -3074,6 +3074,13 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
let(:pipeline_action) { action }
it 'schedules a new PipelineHooksWorker job' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ message: include("Enqueuing hooks for Pipeline #{pipeline.id}"),
+ class: described_class.name,
+ pipeline_id: pipeline.id,
+ project_id: pipeline.project_id,
+ pipeline_status: String
+ )
expect(PipelineHooksWorker).to receive(:perform_async).with(pipeline.id)
pipeline.public_send(pipeline_action)
@@ -3760,6 +3767,24 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe '#self_and_descendants_complete?' do
+ let_it_be(:pipeline) { create(:ci_pipeline, :success) }
+ let_it_be(:child_pipeline) { create(:ci_pipeline, :success, child_of: pipeline) }
+ let_it_be_with_reload(:grandchild_pipeline) { create(:ci_pipeline, :success, child_of: child_pipeline) }
+
+ context 'when all pipelines in the hierarchy is complete' do
+ it { expect(pipeline.self_and_descendants_complete?).to be(true) }
+ end
+
+ context 'when a pipeline in the hierarchy is not complete' do
+ before do
+ grandchild_pipeline.update!(status: :running)
+ end
+
+ it { expect(pipeline.self_and_descendants_complete?).to be(false) }
+ end
+ end
+
describe '#builds_in_self_and_descendants' do
subject(:builds) { pipeline.builds_in_self_and_descendants }
@@ -3928,7 +3953,21 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running) }
- it { is_expected.to be_falsey }
+ context 'with mr_show_reports_immediately flag enabled' do
+ before do
+ stub_feature_flags(mr_show_reports_immediately: project)
+ end
+
+ it { expect(subject).to be_truthy }
+ end
+
+ context 'with mr_show_reports_immediately flag disabled' do
+ before do
+ stub_feature_flags(mr_show_reports_immediately: false)
+ end
+
+ it { expect(subject).to be_falsey }
+ end
end
context 'when pipeline status is success' do
@@ -4002,7 +4041,21 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running) }
- it { expect(subject).to be_falsey }
+ context 'with mr_show_reports_immediately flag enabled' do
+ before do
+ stub_feature_flags(mr_show_reports_immediately: project)
+ end
+
+ it { expect(subject).to be_truthy }
+ end
+
+ context 'with mr_show_reports_immediately flag disabled' do
+ before do
+ stub_feature_flags(mr_show_reports_immediately: false)
+ end
+
+ it { expect(subject).to be_falsey }
+ end
end
context 'when pipeline status is success' do
@@ -4251,13 +4304,13 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
- describe '#find_stage_by_name' do
+ describe 'fetching a stage by name' do
let_it_be(:pipeline) { create(:ci_pipeline) }
let(:stage_name) { 'test' }
let(:stage) do
- create(:ci_stage_entity,
+ create(:ci_stage,
pipeline: pipeline,
project: pipeline.project,
name: 'test')
@@ -4267,19 +4320,37 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
create_list(:ci_build, 2, pipeline: pipeline, stage: stage.name)
end
- subject { pipeline.find_stage_by_name!(stage_name) }
+ describe '#stage' do
+ subject { pipeline.stage(stage_name) }
- context 'when stage exists' do
- it { is_expected.to eq(stage) }
+ context 'when stage exists' do
+ it { is_expected.to eq(stage) }
+ end
+
+ context 'when stage does not exist' do
+ let(:stage_name) { 'build' }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
end
- context 'when stage does not exist' do
- let(:stage_name) { 'build' }
+ describe '#find_stage_by_name' do
+ subject { pipeline.find_stage_by_name!(stage_name) }
- it 'raises an ActiveRecord exception' do
- expect do
- subject
- end.to raise_exception(ActiveRecord::RecordNotFound)
+ context 'when stage exists' do
+ it { is_expected.to eq(stage) }
+ end
+
+ context 'when stage does not exist' do
+ let(:stage_name) { 'build' }
+
+ it 'raises an ActiveRecord exception' do
+ expect do
+ subject
+ end.to raise_exception(ActiveRecord::RecordNotFound)
+ end
end
end
end
@@ -4832,13 +4903,13 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
- describe '#has_expired_test_reports?' do
- subject { pipeline.has_expired_test_reports? }
+ describe '#has_test_reports?' do
+ subject { pipeline.has_test_reports? }
let(:pipeline) { create(:ci_pipeline, :success, :with_test_reports) }
context 'when artifacts are not expired' do
- it { is_expected.to be_falsey }
+ it { is_expected.to be_truthy }
end
context 'when artifacts are expired' do
@@ -4849,6 +4920,14 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
it { is_expected.to be_truthy }
end
+ context 'when artifacts are removed' do
+ before do
+ pipeline.job_artifacts.each(&:destroy)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
context 'when the pipeline is still running' do
let(:pipeline) { create(:ci_pipeline, :running) }
@@ -4942,4 +5021,34 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
end
+
+ describe '#age_in_minutes' do
+ let(:pipeline) { build(:ci_pipeline) }
+
+ context 'when pipeline has not been persisted' do
+ it 'returns zero' do
+ expect(pipeline.age_in_minutes).to eq 0
+ end
+ end
+
+ context 'when pipeline has been saved' do
+ it 'returns pipeline age in minutes' do
+ pipeline.save!
+
+ travel_to(pipeline.created_at + 2.hours) do
+ expect(pipeline.age_in_minutes).to eq 120
+ end
+ end
+ end
+
+ context 'when pipeline has been loaded without all attributes' do
+ it 'raises an exception' do
+ pipeline.save!
+
+ pipeline_id = Ci::Pipeline.where(id: pipeline.id).select(:id).first
+
+ expect { pipeline_id.age_in_minutes }.to raise_error(ArgumentError)
+ end
+ end
+ end
end
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index cdd96d45561..789ae3a2ccc 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Ci::Processable do
new_proc
end
- let_it_be(:stage) { create(:ci_stage_entity, project: project, pipeline: pipeline, name: 'test') }
+ let_it_be(:stage) { create(:ci_stage, project: project, pipeline: pipeline, name: 'test') }
shared_context 'processable bridge' do
let_it_be(:downstream_project) { create(:project, :repository) }
@@ -57,7 +57,7 @@ RSpec.describe Ci::Processable do
let(:clone_accessors) { ::Ci::Build.clone_accessors.without(::Ci::Build.extra_accessors) }
let(:reject_accessors) do
- %i[id status user token token_encrypted coverage trace runner
+ %i[id status user token_encrypted coverage trace runner
artifacts_expire_at
created_at updated_at started_at finished_at queued_at erased_by
erased_at auto_canceled_by job_artifacts job_artifacts_archive
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 74d8b012b29..2fbfbbaf830 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Ci::Runner do
end
describe 'groups association' do
- # Due to other assoctions such as projects this whole spec is allowed to
+ # Due to other associations such as projects this whole spec is allowed to
# generate cross-database queries. So we have this temporary spec to
# validate that at least groups association does not generate cross-DB
# queries.
@@ -35,6 +35,46 @@ RSpec.describe Ci::Runner do
end
end
+ describe 'acts_as_taggable' do
+ let(:tag_name) { 'tag123' }
+
+ context 'on save' do
+ let_it_be_with_reload(:runner) { create(:ci_runner) }
+
+ before do
+ runner.tag_list = [tag_name]
+ end
+
+ context 'tag does not exist' do
+ it 'creates a tag' do
+ expect { runner.save! }.to change(ActsAsTaggableOn::Tag, :count).by(1)
+ end
+
+ it 'creates an association to the tag' do
+ runner.save!
+
+ expect(described_class.tagged_with(tag_name)).to include(runner)
+ end
+ end
+
+ context 'tag already exists' do
+ before do
+ ActsAsTaggableOn::Tag.create!(name: tag_name)
+ end
+
+ it 'does not create a tag' do
+ expect { runner.save! }.not_to change(ActsAsTaggableOn::Tag, :count)
+ end
+
+ it 'creates an association to the tag' do
+ runner.save!
+
+ expect(described_class.tagged_with(tag_name)).to include(runner)
+ end
+ end
+ end
+ end
+
describe 'validation' do
it { is_expected.to validate_presence_of(:access_level) }
it { is_expected.to validate_presence_of(:runner_type) }
@@ -1062,18 +1102,6 @@ RSpec.describe Ci::Runner do
end
end
end
-
- context 'with updated version' do
- before do
- runner.version = '1.2.3'
- end
-
- it 'updates version components with new version' do
- heartbeat
-
- expect(runner.reload.read_attribute(:semver)).to eq '15.0.1'
- end
- end
end
def expect_redis_update
@@ -1088,7 +1116,6 @@ RSpec.describe Ci::Runner do
.and change { runner.reload.read_attribute(:architecture) }
.and change { runner.reload.read_attribute(:config) }
.and change { runner.reload.read_attribute(:executor_type) }
- .and change { runner.reload.read_attribute(:semver) }
end
end
@@ -1193,6 +1220,47 @@ RSpec.describe Ci::Runner do
end
end
+ describe '#save_tags' do
+ let(:runner) { build(:ci_runner, tag_list: ['tag']) }
+
+ it 'saves tags' do
+ runner.save!
+
+ expect(runner.tags.count).to eq(1)
+ expect(runner.tags.first.name).to eq('tag')
+ end
+
+ it 'strips tags' do
+ runner.tag_list = [' taga', 'tagb ', ' tagc ']
+
+ runner.save!
+ expect(runner.tags.map(&:name)).to match_array(%w[taga tagb tagc])
+ end
+
+ context 'with BulkInsertableTags.with_bulk_insert_tags' do
+ it 'does not save_tags' do
+ Ci::BulkInsertableTags.with_bulk_insert_tags do
+ runner.save!
+ end
+
+ expect(runner.tags).to be_empty
+ end
+
+ context 'over TAG_LIST_MAX_LENGTH' do
+ let(:tag_list) { (1..described_class::TAG_LIST_MAX_LENGTH + 1).map { |i| "tag#{i}" } }
+ let(:runner) { build(:ci_runner, tag_list: tag_list) }
+
+ it 'fails validation if over tag limit' do
+ Ci::BulkInsertableTags.with_bulk_insert_tags do
+ expect { runner.save! }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ expect(runner.tags).to be_empty
+ end
+ end
+ end
+ end
+
describe '#has_tags?' do
context 'when runner has tags' do
subject { create(:ci_runner, tag_list: ['tag']) }
@@ -1700,40 +1768,37 @@ RSpec.describe Ci::Runner do
end
end
- describe '.save' do
- context 'with initial value' do
- let(:runner) { create(:ci_runner, version: 'v1.2.3') }
-
- it 'updates semver column' do
- expect(runner.semver).to eq '1.2.3'
- end
- end
+ describe '#with_upgrade_status' do
+ subject { described_class.with_upgrade_status(upgrade_status) }
- context 'with no initial version value' do
- let(:runner) { build(:ci_runner) }
+ let_it_be(:runner_14_0_0) { create(:ci_runner, version: '14.0.0') }
+ let_it_be(:runner_14_1_0) { create(:ci_runner, version: '14.1.0') }
+ let_it_be(:runner_14_1_1) { create(:ci_runner, version: '14.1.1') }
+ let_it_be(:runner_version_14_0_0) { create(:ci_runner_version, version: '14.0.0', status: :available) }
+ let_it_be(:runner_version_14_1_0) { create(:ci_runner_version, version: '14.1.0', status: :recommended) }
+ let_it_be(:runner_version_14_1_1) { create(:ci_runner_version, version: '14.1.1', status: :not_available) }
- context 'with version change' do
- subject(:update_version) { runner.update!(version: new_version) }
+ context ':not_available' do
+ let(:upgrade_status) { :not_available }
- context 'to invalid version' do
- let(:new_version) { 'invalid version' }
-
- it 'updates semver column to nil' do
- update_version
+ it 'returns runners whose version is assigned :not_available' do
+ is_expected.to contain_exactly(runner_14_1_1)
+ end
+ end
- expect(runner.reload.semver).to be_nil
- end
- end
+ context ':available' do
+ let(:upgrade_status) { :available }
- context 'to v14.10.1' do
- let(:new_version) { 'v14.10.1' }
+ it 'returns runners whose version is assigned :available' do
+ is_expected.to contain_exactly(runner_14_0_0)
+ end
+ end
- it 'updates semver column' do
- update_version
+ context ':recommended' do
+ let(:upgrade_status) { :recommended}
- expect(runner.reload.semver).to eq '14.10.1'
- end
- end
+ it 'returns runners whose version is assigned :recommended' do
+ is_expected.to contain_exactly(runner_14_1_0)
end
end
end
diff --git a/spec/models/ci/runner_version_spec.rb b/spec/models/ci/runner_version_spec.rb
new file mode 100644
index 00000000000..d3395942a39
--- /dev/null
+++ b/spec/models/ci/runner_version_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::RunnerVersion do
+ it_behaves_like 'having unique enum values'
+
+ let_it_be(:runner_version_not_available) do
+ create(:ci_runner_version, version: 'abc123', status: :not_available)
+ end
+
+ let_it_be(:runner_version_recommended) do
+ create(:ci_runner_version, version: 'abc234', status: :recommended)
+ end
+
+ describe '.not_available' do
+ subject { described_class.not_available }
+
+ it { is_expected.to match_array([runner_version_not_available]) }
+ end
+
+ describe '.potentially_outdated' do
+ subject { described_class.potentially_outdated }
+
+ let_it_be(:runner_version_nil) { create(:ci_runner_version, version: 'abc345', status: nil) }
+ let_it_be(:runner_version_available) do
+ create(:ci_runner_version, version: 'abc456', status: :available)
+ end
+
+ let_it_be(:runner_version_unknown) do
+ create(:ci_runner_version, version: 'abc567', status: :unknown)
+ end
+
+ it 'contains any runner version that is not already recommended' do
+ is_expected.to match_array([
+ runner_version_nil,
+ runner_version_not_available,
+ runner_version_available,
+ runner_version_unknown
+ ])
+ end
+ end
+
+ describe 'validation' do
+ context 'when runner version is too long' do
+ let(:runner_version) { build(:ci_runner_version, version: 'a' * 2049) }
+
+ it 'is not valid' do
+ expect(runner_version).to be_invalid
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index b91348eb408..d55a8509a98 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Ci::Stage, :models do
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { create(:ci_stage_entity, pipeline: pipeline, project: pipeline.project) }
+ let(:stage) { create(:ci_stage, pipeline: pipeline, project: pipeline.project) }
it_behaves_like 'having unique enum values'
@@ -30,9 +30,9 @@ RSpec.describe Ci::Stage, :models do
describe '.by_position' do
it 'finds stages by position' do
- a = create(:ci_stage_entity, position: 1)
- b = create(:ci_stage_entity, position: 2)
- c = create(:ci_stage_entity, position: 3)
+ a = create(:ci_stage, position: 1)
+ b = create(:ci_stage, position: 2)
+ c = create(:ci_stage, position: 3)
expect(described_class.by_position(1)).to contain_exactly(a)
expect(described_class.by_position(2)).to contain_exactly(b)
@@ -42,9 +42,9 @@ RSpec.describe Ci::Stage, :models do
describe '.by_name' do
it 'finds stages by name' do
- a = create(:ci_stage_entity, name: 'a')
- b = create(:ci_stage_entity, name: 'b')
- c = create(:ci_stage_entity, name: 'c')
+ a = create(:ci_stage, name: 'a')
+ b = create(:ci_stage, name: 'b')
+ c = create(:ci_stage, name: 'c')
expect(described_class.by_name('a')).to contain_exactly(a)
expect(described_class.by_name('b')).to contain_exactly(b)
@@ -54,7 +54,7 @@ RSpec.describe Ci::Stage, :models do
describe '#status' do
context 'when stage is pending' do
- let(:stage) { create(:ci_stage_entity, status: 'pending') }
+ let(:stage) { create(:ci_stage, status: 'pending') }
it 'has a correct status value' do
expect(stage.status).to eq 'pending'
@@ -62,7 +62,7 @@ RSpec.describe Ci::Stage, :models do
end
context 'when stage is success' do
- let(:stage) { create(:ci_stage_entity, status: 'success') }
+ let(:stage) { create(:ci_stage, status: 'success') }
it 'has a correct status value' do
expect(stage.status).to eq 'success'
@@ -119,7 +119,7 @@ RSpec.describe Ci::Stage, :models do
end
context 'when stage has only created builds' do
- let(:stage) { create(:ci_stage_entity, status: :created) }
+ let(:stage) { create(:ci_stage, status: :created) }
before do
create(:ci_build, :created, stage_id: stage.id)
@@ -206,7 +206,7 @@ RSpec.describe Ci::Stage, :models do
using RSpec::Parameterized::TableSyntax
let(:user) { create(:user) }
- let(:stage) { create(:ci_stage_entity, status: :created) }
+ let(:stage) { create(:ci_stage, status: :created) }
subject { stage.detailed_status(user) }
@@ -269,7 +269,7 @@ RSpec.describe Ci::Stage, :models do
describe '#delay' do
subject { stage.delay }
- let(:stage) { create(:ci_stage_entity, status: :created) }
+ let(:stage) { create(:ci_stage, status: :created) }
it 'updates stage status' do
subject
@@ -361,12 +361,12 @@ RSpec.describe Ci::Stage, :models do
end
end
- it_behaves_like 'manual playable stage', :ci_stage_entity
+ it_behaves_like 'manual playable stage', :ci_stage
context 'loose foreign key on ci_stages.project_id' do
it_behaves_like 'cleanup by a loose foreign key' do
let!(:parent) { create(:project) }
- let!(:model) { create(:ci_stage_entity, project: parent) }
+ let!(:model) { create(:ci_stage, project: parent) }
end
end
end
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index 29ca088ee04..f0af229ff2c 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -51,4 +51,10 @@ RSpec.describe Ci::Variable do
let!(:model) { create(:ci_variable, project: parent) }
end
end
+
+ describe '#audit_details' do
+ it "equals to the variable's key" do
+ expect(subject.audit_details).to eq(subject.key)
+ end
+ end
end