diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
commit | 0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch) | |
tree | 7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /spec/models/ci | |
parent | 72123183a20411a36d607d70b12d57c484394c8e (diff) |
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'spec/models/ci')
-rw-r--r-- | spec/models/ci/bridge_spec.rb | 33 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 266 | ||||
-rw-r--r-- | spec/models/ci/job_artifact_spec.rb | 40 | ||||
-rw-r--r-- | spec/models/ci/namespace_mirror_spec.rb | 5 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 178 | ||||
-rw-r--r-- | spec/models/ci/runner_spec.rb | 62 | ||||
-rw-r--r-- | spec/models/ci/secure_file_spec.rb | 15 | ||||
-rw-r--r-- | spec/models/ci/sources/pipeline_spec.rb | 2 |
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) } |