diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
commit | 0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch) | |
tree | 4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /spec/models/ci | |
parent | 744144d28e3e7fddc117924fef88de5d9674fe4c (diff) | |
download | gitlab-ce-0653e08efd039a5905f3fa4f6e9cef9f5d2f799c.tar.gz |
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'spec/models/ci')
-rw-r--r-- | spec/models/ci/bridge_spec.rb | 8 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 57 | ||||
-rw-r--r-- | spec/models/ci/build_trace_chunks/fog_spec.rb | 42 | ||||
-rw-r--r-- | spec/models/ci/build_trace_metadata_spec.rb | 124 | ||||
-rw-r--r-- | spec/models/ci/pending_build_spec.rb | 111 | ||||
-rw-r--r-- | spec/models/ci/pipeline_schedule_spec.rb | 44 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 77 | ||||
-rw-r--r-- | spec/models/ci/pipeline_variable_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/ci/runner_spec.rb | 4 |
9 files changed, 345 insertions, 124 deletions
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index db956b26b6b..6dd3c40f228 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -74,18 +74,18 @@ RSpec.describe Ci::Bridge do it "schedules downstream pipeline creation when the status is #{status}" do bridge.status = status - expect(bridge).to receive(:schedule_downstream_pipeline!) - bridge.enqueue! + + expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id]) end end it "schedules downstream pipeline creation when the status is waiting for resource" do bridge.status = :waiting_for_resource - expect(bridge).to receive(:schedule_downstream_pipeline!) - bridge.enqueue_waiting_for_resource! + + expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id]) end it 'raises error when the status is failed' do diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 26abc98656e..1e06d566c80 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1307,7 +1307,9 @@ RSpec.describe Ci::Build do shared_examples_for 'avoid deadlock' do it 'executes UPDATE in the right order' do - recorded = ActiveRecord::QueryRecorder.new { subject } + recorded = with_cross_database_modification_prevented do + ActiveRecord::QueryRecorder.new { subject } + end index_for_build = recorded.log.index { |l| l.include?("UPDATE \"ci_builds\"") } index_for_deployment = recorded.log.index { |l| l.include?("UPDATE \"deployments\"") } @@ -1322,7 +1324,9 @@ RSpec.describe Ci::Build do it_behaves_like 'avoid deadlock' it 'transits deployment status to running' do - subject + with_cross_database_modification_prevented do + subject + end expect(deployment).to be_running end @@ -1340,7 +1344,9 @@ RSpec.describe Ci::Build do it_behaves_like 'calling proper BuildFinishedWorker' it 'transits deployment status to success' do - subject + with_cross_database_modification_prevented do + subject + end expect(deployment).to be_success end @@ -1353,7 +1359,9 @@ RSpec.describe Ci::Build do it_behaves_like 'calling proper BuildFinishedWorker' it 'transits deployment status to failed' do - subject + with_cross_database_modification_prevented do + subject + end expect(deployment).to be_failed end @@ -1365,7 +1373,9 @@ RSpec.describe Ci::Build do it_behaves_like 'avoid deadlock' it 'transits deployment status to skipped' do - subject + with_cross_database_modification_prevented do + subject + end expect(deployment).to be_skipped end @@ -1378,7 +1388,9 @@ RSpec.describe Ci::Build do it_behaves_like 'calling proper BuildFinishedWorker' it 'transits deployment status to canceled' do - subject + with_cross_database_modification_prevented do + subject + end expect(deployment).to be_canceled end @@ -2632,6 +2644,10 @@ RSpec.describe Ci::Build do value: "#{Gitlab.host_with_port}/#{project.namespace.root_ancestor.path.downcase}#{DependencyProxy::URL_SUFFIX}", public: true, masked: false }, + { key: 'CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX', + value: "#{Gitlab.host_with_port}/#{project.namespace.full_path.downcase}#{DependencyProxy::URL_SUFFIX}", + public: true, + masked: false }, { key: 'CI_API_V4_URL', value: 'http://localhost/api/v4', public: true, masked: false }, { key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s, public: true, masked: false }, { key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true, masked: false }, @@ -5243,4 +5259,33 @@ RSpec.describe Ci::Build do expect(described_class.with_coverage_regex).to eq([build_with_coverage_regex]) end end + + describe '#ensure_trace_metadata!' do + it 'delegates to Ci::BuildTraceMetadata' do + expect(Ci::BuildTraceMetadata) + .to receive(:find_or_upsert_for!) + .with(build.id) + + build.ensure_trace_metadata! + end + end + + describe '#doom!' do + subject { build.doom! } + + let_it_be(:build) { create(:ci_build, :queued) } + + it 'updates status and failure_reason', :aggregate_failures do + subject + + expect(build.status).to eq("failed") + expect(build.failure_reason).to eq("data_integrity_failure") + end + + it 'drops associated pending build' do + subject + + expect(build.reload.queuing_entry).not_to be_present + end + end end diff --git a/spec/models/ci/build_trace_chunks/fog_spec.rb b/spec/models/ci/build_trace_chunks/fog_spec.rb index 21dab6fad60..bbf04ef9430 100644 --- a/spec/models/ci/build_trace_chunks/fog_spec.rb +++ b/spec/models/ci/build_trace_chunks/fog_spec.rb @@ -107,37 +107,22 @@ RSpec.describe Ci::BuildTraceChunks::Fog do let(:model) { create(:ci_build_trace_chunk, :fog_with_data, initial_data: initial_data) } let(:data) { data_store.data(model) } - context 'when ci_job_trace_force_encode is enabled' do - it 'appends ASCII data' do - data_store.append_data(model, +'hello world', 4) + it 'appends ASCII data' do + data_store.append_data(model, +'hello world', 4) - expect(data.encoding).to eq(Encoding::ASCII_8BIT) - expect(data.force_encoding(Encoding::UTF_8)).to eq('😺hello world') - end - - it 'appends UTF-8 data' do - data_store.append_data(model, +'Résumé', 4) - - expect(data.encoding).to eq(Encoding::ASCII_8BIT) - expect(data.force_encoding(Encoding::UTF_8)).to eq("😺Résumé") - end - - context 'when initial data is UTF-8' do - let(:initial_data) { +'😺' } + expect(data.encoding).to eq(Encoding::ASCII_8BIT) + expect(data.force_encoding(Encoding::UTF_8)).to eq('😺hello world') + end - it 'appends ASCII data' do - data_store.append_data(model, +'hello world', 4) + it 'appends UTF-8 data' do + data_store.append_data(model, +'Résumé', 4) - expect(data.encoding).to eq(Encoding::ASCII_8BIT) - expect(data.force_encoding(Encoding::UTF_8)).to eq('😺hello world') - end - end + expect(data.encoding).to eq(Encoding::ASCII_8BIT) + expect(data.force_encoding(Encoding::UTF_8)).to eq("😺Résumé") end - context 'when ci_job_trace_force_encode is disabled' do - before do - stub_feature_flags(ci_job_trace_force_encode: false) - end + context 'when initial data is UTF-8' do + let(:initial_data) { +'😺' } it 'appends ASCII data' do data_store.append_data(model, +'hello world', 4) @@ -145,11 +130,6 @@ RSpec.describe Ci::BuildTraceChunks::Fog do expect(data.encoding).to eq(Encoding::ASCII_8BIT) expect(data.force_encoding(Encoding::UTF_8)).to eq('😺hello world') end - - it 'throws an exception when appending UTF-8 data' do - expect(Gitlab::ErrorTracking).to receive(:track_and_raise_exception).and_call_original - expect { data_store.append_data(model, +'Résumé', 4) }.to raise_exception(Encoding::CompatibilityError) - end end end diff --git a/spec/models/ci/build_trace_metadata_spec.rb b/spec/models/ci/build_trace_metadata_spec.rb index 42b9d5d34b6..5e4645c5dc4 100644 --- a/spec/models/ci/build_trace_metadata_spec.rb +++ b/spec/models/ci/build_trace_metadata_spec.rb @@ -7,4 +7,128 @@ RSpec.describe Ci::BuildTraceMetadata do it { is_expected.to belong_to(:trace_artifact) } it { is_expected.to validate_presence_of(:build) } + it { is_expected.to validate_presence_of(:archival_attempts) } + + describe '#can_attempt_archival_now?' do + let(:metadata) do + build(:ci_build_trace_metadata, + archival_attempts: archival_attempts, + last_archival_attempt_at: last_archival_attempt_at) + end + + subject { metadata.can_attempt_archival_now? } + + context 'when archival_attempts is over the limit' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS + 1 } + let(:last_archival_attempt_at) {} + + it { is_expected.to be_falsey } + end + + context 'when last_archival_attempt_at is not set' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS } + let(:last_archival_attempt_at) {} + + it { is_expected.to be_truthy } + end + + context 'when last_archival_attempt_at is set' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS } + let(:last_archival_attempt_at) { 6.days.ago } + + it { is_expected.to be_truthy } + end + + context 'when last_archival_attempt_at is too close' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS } + let(:last_archival_attempt_at) { 1.hour.ago } + + it { is_expected.to be_falsey } + end + end + + describe '#archival_attempts_available?' do + let(:metadata) do + build(:ci_build_trace_metadata, archival_attempts: archival_attempts) + end + + subject { metadata.archival_attempts_available? } + + context 'when archival_attempts is over the limit' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS + 1 } + + it { is_expected.to be_falsey } + end + + context 'when archival_attempts is at the limit' do + let(:archival_attempts) { described_class::MAX_ATTEMPTS } + + it { is_expected.to be_truthy } + end + end + + describe '#increment_archival_attempts!' do + let_it_be(:metadata) do + create(:ci_build_trace_metadata, + archival_attempts: 2, + last_archival_attempt_at: 1.day.ago) + end + + it 'increments the attempts' do + expect { metadata.increment_archival_attempts! } + .to change { metadata.reload.archival_attempts } + end + + it 'updates the last_archival_attempt_at timestamp' do + expect { metadata.increment_archival_attempts! } + .to change { metadata.reload.last_archival_attempt_at } + end + end + + describe '#track_archival!' do + let(:trace_artifact) { create(:ci_job_artifact) } + let(:metadata) { create(:ci_build_trace_metadata) } + + it 'stores the artifact id and timestamp' do + expect(metadata.trace_artifact_id).to be_nil + + metadata.track_archival!(trace_artifact.id) + metadata.reload + + expect(metadata.trace_artifact_id).to eq(trace_artifact.id) + expect(metadata.archived_at).to be_like_time(Time.current) + end + end + + describe '.find_or_upsert_for!' do + let_it_be(:build) { create(:ci_build) } + + subject(:execute) do + described_class.find_or_upsert_for!(build.id) + end + + it 'creates a new record' do + metadata = execute + + expect(metadata).to be_a(described_class) + expect(metadata.id).to eq(build.id) + expect(metadata.archival_attempts).to eq(0) + end + + context 'with existing records' do + before do + create(:ci_build_trace_metadata, + build: build, + archival_attempts: described_class::MAX_ATTEMPTS) + end + + it 'returns the existing record' do + metadata = execute + + expect(metadata).to be_a(described_class) + expect(metadata.id).to eq(build.id) + expect(metadata.archival_attempts).to eq(described_class::MAX_ATTEMPTS) + end + end + end end diff --git a/spec/models/ci/pending_build_spec.rb b/spec/models/ci/pending_build_spec.rb index 0518c9a1652..ad711f5622f 100644 --- a/spec/models/ci/pending_build_spec.rb +++ b/spec/models/ci/pending_build_spec.rb @@ -34,6 +34,47 @@ RSpec.describe Ci::PendingBuild do end end end + + describe '.for_tags' do + subject(:pending_builds) { described_class.for_tags(tag_ids) } + + let_it_be(:pending_build_with_tags) { create(:ci_pending_build, tag_ids: [1, 2]) } + let_it_be(:pending_build_without_tags) { create(:ci_pending_build) } + + context 'when tag_ids match pending builds' do + let(:tag_ids) { [1, 2] } + + it 'returns matching pending builds' do + expect(pending_builds).to contain_exactly(pending_build_with_tags, pending_build_without_tags) + end + end + + context 'when tag_ids does not match pending builds' do + let(:tag_ids) { [non_existing_record_id] } + + it 'returns matching pending builds without tags' do + expect(pending_builds).to contain_exactly(pending_build_without_tags) + end + end + + context 'when tag_ids is not provided' do + context 'with a nil value' do + let(:tag_ids) { nil } + + it 'returns matching pending builds without tags' do + expect(pending_builds).to contain_exactly(pending_build_without_tags) + end + end + + context 'with an empty array' do + let(:tag_ids) { [] } + + it 'returns matching pending builds without tags' do + expect(pending_builds).to contain_exactly(pending_build_without_tags) + end + end + end + end end describe '.upsert_from_build!' do @@ -58,7 +99,11 @@ RSpec.describe Ci::PendingBuild do end end - context 'when project does not have shared runner' do + context 'when project does not have shared runners enabled' do + before do + project.shared_runners_enabled = false + end + it 'sets instance_runners_enabled to false' do described_class.upsert_from_build!(build) @@ -69,6 +114,10 @@ RSpec.describe Ci::PendingBuild do context 'when project has shared runner' do let_it_be(:runner) { create(:ci_runner, :instance) } + before do + project.shared_runners_enabled = true + end + context 'when ci_pending_builds_maintain_shared_runners_data is enabled' do it 'sets instance_runners_enabled to true' do described_class.upsert_from_build!(build) @@ -113,5 +162,65 @@ RSpec.describe Ci::PendingBuild do end end end + + context 'when build has tags' do + let!(:build) { create(:ci_build, :tags) } + + subject(:ci_pending_build) { described_class.last } + + context 'when ci_pending_builds_maintain_tags_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_tags_data is disabled' do + before do + stub_feature_flags(ci_pending_builds_maintain_tags_data: false) + end + + it 'does not set tag_ids' do + described_class.upsert_from_build!(build) + + expect(ci_pending_build.tag_ids).to be_empty + end + end + end + + context 'when a build project is nested in a subgroup' do + let(:group) { create(:group, :with_hierarchy, depth: 2, children: 1) } + let(:project) { create(:project, namespace: group.descendants.first) } + let(:pipeline) { create(:ci_pipeline, project: project) } + let(:build) { create(:ci_build, :created, pipeline: pipeline) } + + subject { described_class.last } + + context 'when build can be picked by a group runner' do + before do + project.group_runners_enabled = true + end + + it 'denormalizes namespace traversal ids' do + described_class.upsert_from_build!(build) + + expect(subject.namespace_traversal_ids).not_to be_empty + expect(subject.namespace_traversal_ids).to eq [group.id, project.namespace.id] + end + end + + context 'when build can not be picked by a group runner' do + before do + project.group_runners_enabled = false + end + + it 'creates an empty namespace traversal ids array' do + described_class.upsert_from_build!(build) + + expect(subject.namespace_traversal_ids).to be_empty + end + end + end end end diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index 8de3ebb18b9..c7e1fe91b1e 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -107,31 +107,24 @@ RSpec.describe Ci::PipelineSchedule do describe '#set_next_run_at' do using RSpec::Parameterized::TableSyntax - where(:worker_cron, :schedule_cron, :plan_limit, :ff_enabled, :now, :result) do - '0 1 2 3 *' | '0 1 * * *' | nil | true | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0) - '0 1 2 3 *' | '0 1 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0) - '0 1 2 3 *' | '0 1 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | false | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0) - '*/5 * * * *' | '*/1 * * * *' | nil | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 5) - '*/5 * * * *' | '*/1 * * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) - '*/5 * * * *' | '*/1 * * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | false | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 5) - '*/5 * * * *' | '*/1 * * * *' | (1.day.in_minutes / 10).to_i | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10) - '*/5 * * * *' | '*/1 * * * *' | 200 | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10) - '*/5 * * * *' | '*/1 * * * *' | 200 | false | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 5) - '*/5 * * * *' | '0 * * * *' | nil | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5) - '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 10).to_i | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) - '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 10).to_i | false | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5) - '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) - '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 2.hours.in_minutes).to_i | true | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5) - '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) - '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 10).to_i | true | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) - '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 8).to_i | true | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) - '*/5 * * * *' | '0 1 1 * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 1, 1, 0) | Time.zone.local(2021, 6, 1, 1, 0) - '*/9 * * * *' | '0 1 1 * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 1, 1, 9) | Time.zone.local(2021, 6, 1, 1, 0) - '*/9 * * * *' | '0 1 1 * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | false | Time.zone.local(2021, 5, 1, 1, 9) | Time.zone.local(2021, 6, 1, 1, 9) - '*/5 * * * *' | '59 14 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | true | Time.zone.local(2021, 5, 1, 15, 0) | Time.zone.local(2021, 5, 2, 15, 0) - '*/5 * * * *' | '59 14 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | false | Time.zone.local(2021, 5, 1, 15, 0) | Time.zone.local(2021, 5, 2, 15, 0) - '*/5 * * * *' | '45 21 1 2 *' | (1.day.in_minutes / 5).to_i | true | Time.zone.local(2021, 2, 1, 21, 45) | Time.zone.local(2022, 2, 1, 21, 45) - '*/5 * * * *' | '45 21 1 2 *' | (1.day.in_minutes / 5).to_i | false | Time.zone.local(2021, 2, 1, 21, 45) | Time.zone.local(2022, 2, 1, 21, 50) + where(:worker_cron, :schedule_cron, :plan_limit, :now, :result) do + '0 1 2 3 *' | '0 1 * * *' | nil | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0) + '0 1 2 3 *' | '0 1 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0) + '*/5 * * * *' | '*/1 * * * *' | nil | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 5) + '*/5 * * * *' | '*/1 * * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) + '*/5 * * * *' | '*/1 * * * *' | (1.day.in_minutes / 10).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10) + '*/5 * * * *' | '*/1 * * * *' | 200 | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10) + '*/5 * * * *' | '0 * * * *' | nil | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5) + '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 10).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) + '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0) + '*/5 * * * *' | '0 * * * *' | (1.day.in_minutes / 2.hours.in_minutes).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5) + '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) + '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 10).to_i | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) + '*/5 * * * *' | '0 1 * * *' | (1.day.in_minutes / 8).to_i | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0) + '*/5 * * * *' | '0 1 1 * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 1, 1, 0) | Time.zone.local(2021, 6, 1, 1, 0) + '*/9 * * * *' | '0 1 1 * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 1, 1, 9) | Time.zone.local(2021, 6, 1, 1, 0) + '*/5 * * * *' | '59 14 * * *' | (1.day.in_minutes / 1.hour.in_minutes).to_i | Time.zone.local(2021, 5, 1, 15, 0) | Time.zone.local(2021, 5, 2, 15, 0) + '*/5 * * * *' | '45 21 1 2 *' | (1.day.in_minutes / 5).to_i | Time.zone.local(2021, 2, 1, 21, 45) | Time.zone.local(2022, 2, 1, 21, 45) end with_them do @@ -143,7 +136,6 @@ RSpec.describe Ci::PipelineSchedule do end create(:plan_limits, :default_plan, ci_daily_pipeline_schedule_triggers: plan_limit) if plan_limit - stub_feature_flags(ci_daily_limit_for_pipeline_schedules: false) unless ff_enabled # Setting this here to override initial save with the current time pipeline_schedule.next_run_at = now diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index da89eccc3b2..1007d64438f 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -183,6 +183,28 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do end end + describe '.where_not_sha' do + let_it_be(:pipeline) { create(:ci_pipeline, sha: 'abcx') } + let_it_be(:pipeline_2) { create(:ci_pipeline, sha: 'abc') } + + let(:sha) { 'abc' } + + subject { described_class.where_not_sha(sha) } + + it 'returns the pipeline without the specified sha' do + is_expected.to contain_exactly(pipeline) + end + + context 'when argument is array' do + let(:sha) { %w[abc abcx] } + + it 'returns the pipelines without the specified shas' do + pipeline_3 = create(:ci_pipeline, sha: 'abcy') + is_expected.to contain_exactly(pipeline_3) + end + end + end + describe '.for_source_sha' do subject { described_class.for_source_sha(source_sha) } @@ -2015,16 +2037,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do it 'returns external pull request modified paths' do expect(pipeline.modified_paths).to match(external_pull_request.modified_paths) end - - context 'when the FF ci_modified_paths_of_external_prs is disabled' do - before do - stub_feature_flags(ci_modified_paths_of_external_prs: false) - end - - it 'returns nil' do - expect(pipeline.modified_paths).to be_nil - end - end end end @@ -4524,51 +4536,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do subject(:reset_bridge) { pipeline.reset_source_bridge!(project.owner) } - # This whole block will be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/329194 - # It contains some duplicate checks. - context 'when the FF ci_reset_bridge_with_subsequent_jobs is disabled' do - before do - stub_feature_flags(ci_reset_bridge_with_subsequent_jobs: false) - end - - context 'when the pipeline is a child pipeline and the bridge is depended' do - let!(:parent_pipeline) { create(:ci_pipeline) } - let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) } - - it 'marks source bridge as pending' do - reset_bridge - - expect(bridge.reload).to be_pending - end - - context 'when the parent pipeline has subsequent jobs after the bridge' do - let!(:after_bridge_job) { create(:ci_build, :skipped, pipeline: parent_pipeline, stage_idx: bridge.stage_idx + 1) } - - it 'does not touch subsequent jobs of the bridge' do - reset_bridge - - expect(after_bridge_job.reload).to be_skipped - end - end - - context 'when the parent pipeline has a dependent upstream pipeline' do - let(:upstream_pipeline) { create(:ci_pipeline, project: create(:project)) } - let!(:upstream_bridge) { create_bridge(upstream_pipeline, parent_pipeline, true) } - - let(:upstream_upstream_pipeline) { create(:ci_pipeline, project: create(:project)) } - let!(:upstream_upstream_bridge) { create_bridge(upstream_upstream_pipeline, upstream_pipeline, true) } - - it 'marks all source bridges as pending' do - reset_bridge - - expect(bridge.reload).to be_pending - expect(upstream_bridge.reload).to be_pending - expect(upstream_upstream_bridge.reload).to be_pending - end - end - end - end - context 'when the pipeline is a child pipeline and the bridge is depended' do let!(:parent_pipeline) { create(:ci_pipeline) } let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) } diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb index 04fcaab4c2d..4e8d49585d0 100644 --- a/spec/models/ci/pipeline_variable_spec.rb +++ b/spec/models/ci/pipeline_variable_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Ci::PipelineVariable do it_behaves_like "CI variable" - it { is_expected.to validate_uniqueness_of(:key).scoped_to(:pipeline_id) } + it { is_expected.to validate_presence_of(:key) } describe '#hook_attrs' do let(:variable) { create(:ci_pipeline_variable, key: 'foo', value: 'bar') } diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index ffc8ab4cf8b..31e854c852e 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -531,6 +531,10 @@ RSpec.describe Ci::Runner do it 'can handle builds' do expect(runner.can_pick?(build)).to be_truthy end + + it 'knows namespace id it is assigned to' do + expect(runner.namespace_ids).to eq [group.id] + end end end |