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:
Diffstat (limited to 'spec/models/ci')
-rw-r--r--spec/models/ci/bridge_spec.rb33
-rw-r--r--spec/models/ci/build_spec.rb266
-rw-r--r--spec/models/ci/job_artifact_spec.rb40
-rw-r--r--spec/models/ci/namespace_mirror_spec.rb5
-rw-r--r--spec/models/ci/pipeline_spec.rb178
-rw-r--r--spec/models/ci/runner_spec.rb62
-rw-r--r--spec/models/ci/secure_file_spec.rb15
-rw-r--r--spec/models/ci/sources/pipeline_spec.rb2
8 files changed, 397 insertions, 204 deletions
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 6409ea9fc3d..cb29cce554f 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -259,25 +259,16 @@ RSpec.describe Ci::Bridge do
context 'forward variables' do
using RSpec::Parameterized::TableSyntax
- where(:yaml_variables, :pipeline_variables, :ff, :variables) do
- nil | nil | true | %w[BRIDGE]
- nil | false | true | %w[BRIDGE]
- nil | true | true | %w[BRIDGE PVAR1]
- false | nil | true | %w[]
- false | false | true | %w[]
- false | true | true | %w[PVAR1]
- true | nil | true | %w[BRIDGE]
- true | false | true | %w[BRIDGE]
- true | true | true | %w[BRIDGE PVAR1]
- nil | nil | false | %w[BRIDGE]
- nil | false | false | %w[BRIDGE]
- nil | true | false | %w[BRIDGE]
- false | nil | false | %w[BRIDGE]
- false | false | false | %w[BRIDGE]
- false | true | false | %w[BRIDGE]
- true | nil | false | %w[BRIDGE]
- true | false | false | %w[BRIDGE]
- true | true | false | %w[BRIDGE]
+ where(:yaml_variables, :pipeline_variables, :variables) do
+ nil | nil | %w[BRIDGE]
+ nil | false | %w[BRIDGE]
+ nil | true | %w[BRIDGE PVAR1]
+ false | nil | %w[]
+ false | false | %w[]
+ false | true | %w[PVAR1]
+ true | nil | %w[BRIDGE]
+ true | false | %w[BRIDGE]
+ true | true | %w[BRIDGE PVAR1]
end
with_them do
@@ -292,10 +283,6 @@ RSpec.describe Ci::Bridge do
}
end
- before do
- stub_feature_flags(ci_trigger_forward_variables: ff)
- end
-
it 'returns variables according to the forward value' do
expect(bridge.downstream_variables.map { |v| v[:key] }).to contain_exactly(*variables)
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index dcf6915a01e..6ad6bb16eb5 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -294,31 +294,28 @@ RSpec.describe Ci::Build do
end
end
- describe '.with_reports' do
- subject { described_class.with_reports(Ci::JobArtifact.test_reports) }
+ describe '.with_artifacts' do
+ subject(:builds) { described_class.with_artifacts(artifact_scope) }
- context 'when build has a test report' do
- let!(:build) { create(:ci_build, :success, :test_reports) }
+ let(:artifact_scope) { Ci::JobArtifact.where(file_type: 'archive') }
- it 'selects the build' do
- is_expected.to eq([build])
- end
- end
+ let!(:build_1) { create(:ci_build, :artifacts) }
+ let!(:build_2) { create(:ci_build, :codequality_reports) }
+ let!(:build_3) { create(:ci_build, :test_reports) }
+ let!(:build_4) { create(:ci_build, :artifacts) }
- context 'when build does not have test reports' do
- let!(:build) { create(:ci_build, :success, :trace_artifact) }
-
- it 'does not select the build' do
- is_expected.to be_empty
- end
+ it 'returns artifacts matching the given scope' do
+ expect(builds).to contain_exactly(build_1, build_4)
end
- context 'when there are multiple builds with test reports' do
- let!(:builds) { create_list(:ci_build, 5, :success, :test_reports) }
+ context 'when there are multiple builds containing artifacts' do
+ before do
+ create_list(:ci_build, 5, :success, :test_reports)
+ end
it 'does not execute a query for selecting job artifact one by one' do
recorded = ActiveRecord::QueryRecorder.new do
- subject.each do |build|
+ builds.each do |build|
build.job_artifacts.map { |a| a.file.exists? }
end
end
@@ -1367,7 +1364,7 @@ RSpec.describe Ci::Build do
before do
allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
- allow(Deployments::HooksWorker).to receive(:perform_async)
+ allow(deployment).to receive(:execute_hooks)
end
it 'has deployments record with created status' do
@@ -1423,7 +1420,7 @@ RSpec.describe Ci::Build do
before do
allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
- allow(Deployments::HooksWorker).to receive(:perform_async)
+ allow(deployment).to receive(:execute_hooks)
end
it_behaves_like 'avoid deadlock'
@@ -1509,14 +1506,28 @@ RSpec.describe Ci::Build do
it 'transitions to running and calls webhook' do
freeze_time do
- expect(Deployments::HooksWorker)
- .to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
+ expect(deployment).to receive(:execute_hooks).with(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
@@ -1830,6 +1841,27 @@ RSpec.describe Ci::Build do
end
context 'build is erasable' do
+ context 'when project is undergoing stats refresh' do
+ let!(:build) { create(:ci_build, :test_reports, :trace_artifact, :success, :artifacts) }
+
+ describe '#erase' do
+ before do
+ allow(build.project).to receive(:refreshing_build_artifacts_size?).and_return(true)
+ end
+
+ it 'logs and continues with deleting the artifacts' do
+ expect(Gitlab::ProjectStatsRefreshConflictsLogger).to receive(:warn_artifact_deletion_during_stats_refresh).with(
+ method: 'Ci::Build#erase',
+ project_id: build.project.id
+ )
+
+ build.erase
+
+ expect(build.job_artifacts.count).to eq(0)
+ end
+ end
+ end
+
context 'new artifacts' do
let!(:build) { create(:ci_build, :test_reports, :trace_artifact, :success, :artifacts) }
@@ -1924,6 +1956,23 @@ RSpec.describe Ci::Build do
expect(build.send("job_artifacts_#{file_type}")).not_to be_nil
end
end
+
+ context 'when the project is undergoing stats refresh' do
+ before do
+ allow(build.project).to receive(:refreshing_build_artifacts_size?).and_return(true)
+ end
+
+ it 'logs and continues with deleting the artifacts' do
+ expect(Gitlab::ProjectStatsRefreshConflictsLogger).to receive(:warn_artifact_deletion_during_stats_refresh).with(
+ method: 'Ci::Build#erase_erasable_artifacts!',
+ project_id: build.project.id
+ )
+
+ subject
+
+ expect(build.job_artifacts.erasable).to be_empty
+ end
+ end
end
describe '#first_pending' do
@@ -2757,6 +2806,7 @@ RSpec.describe Ci::Build do
{ key: 'CI_PROJECT_ID', value: project.id.to_s, public: true, masked: false },
{ key: 'CI_PROJECT_NAME', value: project.path, public: true, masked: false },
{ key: 'CI_PROJECT_TITLE', value: project.title, public: true, masked: false },
+ { key: 'CI_PROJECT_DESCRIPTION', value: project.description, public: true, masked: false },
{ key: 'CI_PROJECT_PATH', value: project.full_path, public: true, masked: false },
{ key: 'CI_PROJECT_PATH_SLUG', value: project.full_path_slug, public: true, masked: false },
{ key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true, masked: false },
@@ -3486,7 +3536,7 @@ RSpec.describe Ci::Build do
]
end
- context 'when gitlab-deploy-token exists' do
+ context 'when gitlab-deploy-token exists for project' do
before do
project.deploy_tokens << deploy_token
end
@@ -3496,11 +3546,32 @@ RSpec.describe Ci::Build do
end
end
- context 'when gitlab-deploy-token does not exist' do
+ context 'when gitlab-deploy-token does not exist for project' do
it 'does not include deploy token variables' do
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_USER'}).to be_nil
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_PASSWORD'}).to be_nil
end
+
+ context 'when gitlab-deploy-token exists for group' do
+ before do
+ group.deploy_tokens << deploy_token
+ end
+
+ it 'includes deploy token variables' do
+ is_expected.to include(*deploy_token_variables)
+ end
+
+ context 'when the FF ci_variable_for_group_gitlab_deploy_token is disabled' do
+ before do
+ stub_feature_flags(ci_variable_for_group_gitlab_deploy_token: false)
+ end
+
+ it 'does not include deploy token variables' do
+ expect(subject.find { |v| v[:key] == 'CI_DEPLOY_USER'}).to be_nil
+ expect(subject.find { |v| v[:key] == 'CI_DEPLOY_PASSWORD'}).to be_nil
+ end
+ end
+ end
end
end
@@ -4298,6 +4369,56 @@ RSpec.describe Ci::Build do
end
end
end
+
+ 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 }
+
+ before do
+ build_1.collect_test_reports!(test_report)
+ end
+
+ it 'uses the group name for test suite name' do
+ expect(test_report.test_suites.keys).to contain_exactly('build')
+ end
+
+ context 'when there are more than one parallel builds' do
+ let(:build_2) { create(:ci_build, name: 'build 2/2') }
+
+ before do
+ build_2.collect_test_reports!(test_report)
+ end
+
+ it 'merges the test suite from parallel builds' do
+ expect(test_report.test_suites.keys).to contain_exactly('build')
+ end
+ end
+ end
+
+ context 'when build is part of matrix build' do
+ let(:test_report) { Gitlab::Ci::Reports::TestReports.new }
+ let(:matrix_build_1) { create(:ci_build, :matrix) }
+
+ before do
+ matrix_build_1.collect_test_reports!(test_report)
+ end
+
+ it 'uses the job name for the test suite' do
+ expect(test_report.test_suites.keys).to contain_exactly(matrix_build_1.name)
+ end
+
+ context 'when there are more than one matrix builds' do
+ let(:matrix_build_2) { create(:ci_build, :matrix) }
+
+ before do
+ matrix_build_2.collect_test_reports!(test_report)
+ end
+
+ it 'keeps separate test suites' do
+ expect(test_report.test_suites.keys).to match_array([matrix_build_1.name, matrix_build_2.name])
+ end
+ end
+ end
end
describe '#collect_accessibility_reports!' do
@@ -4355,68 +4476,6 @@ RSpec.describe Ci::Build do
end
end
- describe '#collect_coverage_reports!' do
- subject { build.collect_coverage_reports!(coverage_report) }
-
- let(:coverage_report) { Gitlab::Ci::Reports::CoverageReports.new }
-
- it { expect(coverage_report.files).to eq({}) }
-
- context 'when build has a coverage report' do
- context 'when there is a Cobertura coverage report from simplecov-cobertura' do
- before do
- create(:ci_job_artifact, :cobertura, job: build, project: build.project)
- end
-
- it 'parses blobs and add the results to the coverage report' do
- expect { subject }.not_to raise_error
-
- expect(coverage_report.files.keys).to match_array(['app/controllers/abuse_reports_controller.rb'])
- expect(coverage_report.files['app/controllers/abuse_reports_controller.rb'].count).to eq(23)
- end
- end
-
- context 'when there is a Cobertura coverage report from gocov-xml' do
- before do
- create(:ci_job_artifact, :coverage_gocov_xml, job: build, project: build.project)
- end
-
- it 'parses blobs and add the results to the coverage report' do
- expect { subject }.not_to raise_error
-
- expect(coverage_report.files.keys).to match_array(['auth/token.go', 'auth/rpccredentials.go'])
- expect(coverage_report.files['auth/token.go'].count).to eq(49)
- expect(coverage_report.files['auth/rpccredentials.go'].count).to eq(10)
- end
- end
-
- context 'when there is a Cobertura coverage report with class filename paths not relative to project root' do
- before do
- allow(build.project).to receive(:full_path).and_return('root/javademo')
- allow(build.pipeline).to receive(:all_worktree_paths).and_return(['src/main/java/com/example/javademo/User.java'])
-
- create(:ci_job_artifact, :coverage_with_paths_not_relative_to_project_root, job: build, project: build.project)
- end
-
- it 'parses blobs and add the results to the coverage report with corrected paths' do
- expect { subject }.not_to raise_error
-
- expect(coverage_report.files.keys).to match_array(['src/main/java/com/example/javademo/User.java'])
- end
- end
-
- context 'when there is a corrupted Cobertura coverage report' do
- before do
- create(:ci_job_artifact, :coverage_with_corrupted_data, job: build, project: build.project)
- end
-
- it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Ci::Parsers::Coverage::Cobertura::InvalidLineInformationError)
- end
- end
- end
- end
-
describe '#collect_codequality_reports!' do
subject(:codequality_report) { build.collect_codequality_reports!(Gitlab::Ci::Reports::CodequalityReports.new) }
@@ -4506,6 +4565,18 @@ RSpec.describe Ci::Build do
end
end
+ describe '#each_report' do
+ let(:report_types) { Ci::JobArtifact::COVERAGE_REPORT_FILE_TYPES }
+
+ let!(:codequality) { create(:ci_job_artifact, :codequality, job: build) }
+ let!(:coverage) { create(:ci_job_artifact, :coverage_gocov_xml, job: build) }
+ let!(:junit) { create(:ci_job_artifact, :junit, job: build) }
+
+ it 'yields job artifact blob that matches the type' do
+ expect { |b| build.each_report(report_types, &b) }.to yield_with_args(coverage.file_type, String, coverage)
+ end
+ end
+
describe '#report_artifacts' do
subject { build.report_artifacts }
@@ -4947,6 +5018,18 @@ RSpec.describe Ci::Build do
build.execute_hooks
end
+
+ context 'with blocked users' do
+ before do
+ allow(build).to receive(:user) { FactoryBot.build(:user, :blocked) }
+ end
+
+ it 'does not call project.execute_hooks' do
+ expect(build.project).not_to receive(:execute_hooks)
+
+ build.execute_hooks
+ end
+ end
end
context 'without project hooks' do
@@ -5410,6 +5493,19 @@ RSpec.describe Ci::Build do
subject
end
+ context 'with deployment' do
+ let(:environment) { create(:environment) }
+ let(:build) { create(:ci_build, :with_deployment, environment: environment.name, pipeline: pipeline) }
+
+ it 'updates the deployment status', :aggregate_failures do
+ expect(build.deployment).to receive(:sync_status_with).with(build).and_call_original
+
+ subject
+
+ expect(build.deployment.reload.status).to eq("failed")
+ end
+ end
+
context 'with queued builds' do
let(:traits) { [:queued] }
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index 24265242172..b9cac6c3f99 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -33,10 +33,10 @@ RSpec.describe Ci::JobArtifact do
end
end
- describe '.with_reports' do
+ describe '.all_reports' do
let!(:artifact) { create(:ci_job_artifact, :archive) }
- subject { described_class.with_reports }
+ subject { described_class.all_reports }
it { is_expected.to be_empty }
@@ -302,6 +302,42 @@ RSpec.describe Ci::JobArtifact do
end
end
+ describe '.created_at_before' do
+ it 'returns artifacts' do
+ artifact1 = create(:ci_job_artifact, created_at: 1.day.ago)
+ _artifact2 = create(:ci_job_artifact, created_at: 1.day.from_now)
+
+ expect(described_class.created_at_before(Time.current)).to match_array([artifact1])
+ end
+ end
+
+ describe '.id_before' do
+ it 'returns artifacts' do
+ artifact1 = create(:ci_job_artifact)
+ artifact2 = create(:ci_job_artifact)
+
+ expect(described_class.id_before(artifact2.id)).to match_array([artifact1, artifact2])
+ end
+ end
+
+ describe '.id_after' do
+ it 'returns artifacts' do
+ artifact1 = create(:ci_job_artifact)
+ artifact2 = create(:ci_job_artifact)
+
+ expect(described_class.id_after(artifact1.id)).to match_array([artifact2])
+ end
+ end
+
+ describe '.ordered_by_id' do
+ it 'returns artifacts in asc order' do
+ artifact1 = create(:ci_job_artifact)
+ artifact2 = create(:ci_job_artifact)
+
+ expect(described_class.ordered_by_id).to eq([artifact1, artifact2])
+ end
+ end
+
describe 'callbacks' do
describe '#schedule_background_upload' do
subject { create(:ci_job_artifact, :archive) }
diff --git a/spec/models/ci/namespace_mirror_spec.rb b/spec/models/ci/namespace_mirror_spec.rb
index 9b4e86916b8..3e77c349ccb 100644
--- a/spec/models/ci/namespace_mirror_spec.rb
+++ b/spec/models/ci/namespace_mirror_spec.rb
@@ -151,10 +151,9 @@ RSpec.describe Ci::NamespaceMirror do
it_behaves_like 'changing the middle namespace'
- context 'when the FFs sync_traversal_ids, use_traversal_ids and use_traversal_ids_for_ancestors are disabled' do
+ context 'when the FFs use_traversal_ids and use_traversal_ids_for_ancestors are disabled' do
before do
- stub_feature_flags(sync_traversal_ids: false,
- use_traversal_ids: false,
+ stub_feature_flags(use_traversal_ids: false,
use_traversal_ids_for_ancestors: false)
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 8dc041814fa..31752f300f4 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -73,6 +73,17 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe '#latest_successful_builds' do
+ it 'has a one to many relationship with its latest successful builds' do
+ _old_build = create(:ci_build, :retried, pipeline: pipeline)
+ _expired_build = create(:ci_build, :expired, pipeline: pipeline)
+ _failed_builds = create_list(:ci_build, 2, :failed, pipeline: pipeline)
+ successful_builds = create_list(:ci_build, 2, :success, pipeline: pipeline)
+
+ expect(pipeline.latest_successful_builds).to contain_exactly(successful_builds.first, successful_builds.second)
+ end
+ end
+
describe '#downloadable_artifacts' do
let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
let_it_be(:downloadable_artifact) { create(:ci_job_artifact, :codequality, job: build) }
@@ -3045,7 +3056,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'hooks trigerring' do
- let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
+ let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, :created) }
%i[
enqueue
@@ -3065,7 +3076,19 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
it 'schedules a new PipelineHooksWorker job' do
expect(PipelineHooksWorker).to receive(:perform_async).with(pipeline.id)
- pipeline.reload.public_send(pipeline_action)
+ pipeline.public_send(pipeline_action)
+ end
+
+ context 'with blocked users' do
+ before do
+ allow(pipeline).to receive(:user) { build(:user, :blocked) }
+ end
+
+ it 'does not schedule a new PipelineHooksWorker job' do
+ expect(PipelineHooksWorker).not_to receive(:perform_async)
+
+ pipeline.public_send(pipeline_action)
+ end
end
end
end
@@ -3625,6 +3648,18 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
pipeline.succeed!
end
end
+
+ context 'when the user is blocked' do
+ before do
+ pipeline.user.block!
+ end
+
+ it 'does not enqueue PipelineNotificationWorker' do
+ expect(PipelineNotificationWorker).not_to receive(:perform_async)
+
+ pipeline.succeed
+ end
+ end
end
context 'with failed pipeline' do
@@ -3645,6 +3680,18 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
pipeline.drop
end
+
+ context 'when the user is blocked' do
+ before do
+ pipeline.user.block!
+ end
+
+ it 'does not enqueue PipelineNotificationWorker' do
+ expect(PipelineNotificationWorker).not_to receive(:perform_async)
+
+ pipeline.drop
+ end
+ end
end
context 'with skipped pipeline' do
@@ -3842,6 +3889,34 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe '#latest_report_builds_in_self_and_descendants' do
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let_it_be(:grandchild_pipeline) { create(:ci_pipeline, child_of: child_pipeline) }
+
+ it 'returns builds with reports artifacts from pipelines in the hierarcy' do
+ parent_build = create(:ci_build, :test_reports, pipeline: pipeline)
+ child_build = create(:ci_build, :coverage_reports, pipeline: child_pipeline)
+ grandchild_build = create(:ci_build, :codequality_reports, pipeline: grandchild_pipeline)
+
+ expect(pipeline.latest_report_builds_in_self_and_descendants).to contain_exactly(parent_build, child_build, grandchild_build)
+ end
+
+ it 'filters builds by scope' do
+ create(:ci_build, :test_reports, pipeline: pipeline)
+ grandchild_build = create(:ci_build, :codequality_reports, pipeline: grandchild_pipeline)
+
+ expect(pipeline.latest_report_builds_in_self_and_descendants(Ci::JobArtifact.codequality_reports)).to contain_exactly(grandchild_build)
+ end
+
+ it 'only returns builds that are not retried' do
+ create(:ci_build, :codequality_reports, :retried, pipeline: grandchild_pipeline)
+ grandchild_build = create(:ci_build, :codequality_reports, pipeline: grandchild_pipeline)
+
+ expect(pipeline.latest_report_builds_in_self_and_descendants).to contain_exactly(grandchild_build)
+ end
+ end
+
describe '#has_reports?' do
subject { pipeline.has_reports?(Ci::JobArtifact.test_reports) }
@@ -3900,38 +3975,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
- describe '#can_generate_coverage_reports?' do
- subject { pipeline.can_generate_coverage_reports? }
-
- context 'when pipeline has builds with coverage reports' do
- before do
- create(:ci_build, :coverage_reports, pipeline: pipeline)
- end
-
- context 'when pipeline status is running' do
- let(:pipeline) { create(:ci_pipeline, :running) }
-
- it { expect(subject).to be_falsey }
- end
-
- context 'when pipeline status is success' do
- let(:pipeline) { create(:ci_pipeline, :success) }
-
- it { expect(subject).to be_truthy }
- end
- end
-
- context 'when pipeline does not have builds with coverage reports' do
- before do
- create(:ci_build, :artifacts, pipeline: pipeline)
- end
-
- let(:pipeline) { create(:ci_pipeline, :success) }
-
- it { expect(subject).to be_falsey }
- end
- end
-
describe '#has_codequality_mr_diff_report?' do
subject { pipeline.has_codequality_mr_diff_report? }
@@ -4082,55 +4125,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
- describe '#coverage_reports' do
- subject { pipeline.coverage_reports }
-
- let_it_be(:pipeline) { create(:ci_pipeline) }
-
- context 'when pipeline has multiple builds with coverage reports' do
- let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
- let!(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
-
- before do
- create(:ci_job_artifact, :cobertura, job: build_rspec)
- create(:ci_job_artifact, :coverage_gocov_xml, job: build_golang)
- end
-
- it 'returns coverage reports with collected data' do
- expect(subject.files.keys).to match_array([
- "auth/token.go",
- "auth/rpccredentials.go",
- "app/controllers/abuse_reports_controller.rb"
- ])
- end
-
- it 'does not execute N+1 queries' do
- single_build_pipeline = create(:ci_empty_pipeline, :created)
- single_rspec = create(:ci_build, :success, name: 'rspec', pipeline: single_build_pipeline)
- create(:ci_job_artifact, :cobertura, job: single_rspec, project: project)
-
- control = ActiveRecord::QueryRecorder.new { single_build_pipeline.coverage_reports }
-
- expect { subject }.not_to exceed_query_limit(control)
- end
-
- context 'when builds are retried' do
- let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
- let!(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
-
- it 'does not take retried builds into account' do
- expect(subject.files).to eql({})
- end
- end
- end
-
- context 'when pipeline does not have any builds with coverage reports' do
- it 'returns empty coverage reports' do
- expect(subject.files).to eql({})
- end
- end
- end
-
describe '#codequality_reports' do
subject(:codequality_reports) { pipeline.codequality_reports }
@@ -4839,9 +4833,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#has_expired_test_reports?' do
- subject { pipeline_with_test_report.has_expired_test_reports? }
+ subject { pipeline.has_expired_test_reports? }
- let(:pipeline_with_test_report) { create(:ci_pipeline, :with_test_reports) }
+ let(:pipeline) { create(:ci_pipeline, :success, :with_test_reports) }
context 'when artifacts are not expired' do
it { is_expected.to be_falsey }
@@ -4849,11 +4843,23 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when artifacts are expired' do
before do
- pipeline_with_test_report.job_artifacts.first.update!(expire_at: Date.yesterday)
+ pipeline.job_artifacts.first.update!(expire_at: Date.yesterday)
end
it { is_expected.to be_truthy }
end
+
+ context 'when the pipeline is still running' do
+ let(:pipeline) { create(:ci_pipeline, :running) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when the pipeline is completed without test reports' do
+ let(:pipeline) { create(:ci_pipeline, :success) }
+
+ it { is_expected.to be_falsey }
+ end
end
it_behaves_like 'it has loose foreign keys' do
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 8a1dcbfbdeb..74d8b012b29 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1002,8 +1002,11 @@ RSpec.describe Ci::Runner do
describe '#heartbeat' do
let(:runner) { create(:ci_runner, :project) }
let(:executor) { 'shell' }
+ let(:version) { '15.0.1' }
- subject { runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor) }
+ subject(:heartbeat) do
+ runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version)
+ end
context 'when database was updated recently' do
before do
@@ -1013,7 +1016,7 @@ RSpec.describe Ci::Runner do
it 'updates cache' do
expect_redis_update
- subject
+ heartbeat
end
end
@@ -1047,7 +1050,7 @@ RSpec.describe Ci::Runner do
it 'updates with expected executor type' do
expect_redis_update
- subject
+ heartbeat
expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
end
@@ -1059,6 +1062,18 @@ 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
@@ -1069,10 +1084,11 @@ RSpec.describe Ci::Runner do
end
def does_db_update
- expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
+ expect { heartbeat }.to change { runner.reload.read_attribute(:contacted_at) }
.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
@@ -1683,4 +1699,42 @@ RSpec.describe Ci::Runner do
end
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
+
+ context 'with no initial version value' do
+ let(:runner) { build(:ci_runner) }
+
+ context 'with version change' do
+ subject(:update_version) { runner.update!(version: new_version) }
+
+ context 'to invalid version' do
+ let(:new_version) { 'invalid version' }
+
+ it 'updates semver column to nil' do
+ update_version
+
+ expect(runner.reload.semver).to be_nil
+ end
+ end
+
+ context 'to v14.10.1' do
+ let(:new_version) { 'v14.10.1' }
+
+ it 'updates semver column' do
+ update_version
+
+ expect(runner.reload.semver).to eq '14.10.1'
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/ci/secure_file_spec.rb b/spec/models/ci/secure_file_spec.rb
index 40ddafad013..a3f1c7b7ef7 100644
--- a/spec/models/ci/secure_file_spec.rb
+++ b/spec/models/ci/secure_file_spec.rb
@@ -48,6 +48,21 @@ RSpec.describe Ci::SecureFile do
end
end
+ describe 'ordered scope' do
+ it 'returns the newest item first' do
+ project = create(:project)
+ file1 = create(:ci_secure_file, created_at: 1.week.ago, project: project)
+ file2 = create(:ci_secure_file, created_at: 2.days.ago, project: project)
+ file3 = create(:ci_secure_file, created_at: 1.day.ago, project: project)
+
+ files = project.secure_files.order_by_created_at
+
+ expect(files[0]).to eq(file3)
+ expect(files[1]).to eq(file2)
+ expect(files[2]).to eq(file1)
+ end
+ end
+
describe '#checksum' do
it 'computes SHA256 checksum on the file before encrypted' do
expect(subject.checksum).to eq(Digest::SHA256.hexdigest(sample_file))
diff --git a/spec/models/ci/sources/pipeline_spec.rb b/spec/models/ci/sources/pipeline_spec.rb
index 73f7cfa739f..732dd5c3df3 100644
--- a/spec/models/ci/sources/pipeline_spec.rb
+++ b/spec/models/ci/sources/pipeline_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Ci::Sources::Pipeline do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:pipeline) }
- it { is_expected.to belong_to(:source_project) }
+ it { is_expected.to belong_to(:source_project).class_name('::Project') }
it { is_expected.to belong_to(:source_job) }
it { is_expected.to belong_to(:source_bridge) }
it { is_expected.to belong_to(:source_pipeline) }