diff options
Diffstat (limited to 'spec/workers')
19 files changed, 726 insertions, 104 deletions
diff --git a/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb b/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb index 8db86071dc4..667ec0bcb75 100644 --- a/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb +++ b/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do it 'counts a scope and stores the result' do subject - measurement = Analytics::InstanceStatistics::Measurement.first + measurement = Analytics::InstanceStatistics::Measurement.users.first expect(measurement.recorded_at).to be_like_time(recorded_at) expect(measurement.identifier).to eq('users') expect(measurement.count).to eq(2) @@ -33,7 +33,7 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do it 'sets 0 as the count' do subject - measurement = Analytics::InstanceStatistics::Measurement.first + measurement = Analytics::InstanceStatistics::Measurement.groups.first expect(measurement.recorded_at).to be_like_time(recorded_at) expect(measurement.identifier).to eq('groups') expect(measurement.count).to eq(0) @@ -51,4 +51,20 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do expect { subject }.not_to change { Analytics::InstanceStatistics::Measurement.count } end + + context 'when pipelines_succeeded identifier is passed' do + let_it_be(:pipeline) { create(:ci_pipeline, :success) } + + let(:successful_pipelines_measurement_identifier) { ::Analytics::InstanceStatistics::Measurement.identifiers.fetch(:pipelines_succeeded) } + let(:job_args) { [successful_pipelines_measurement_identifier, pipeline.id, pipeline.id, recorded_at] } + + it 'counts successful pipelines' do + subject + + measurement = Analytics::InstanceStatistics::Measurement.pipelines_succeeded.first + expect(measurement.recorded_at).to be_like_time(recorded_at) + expect(measurement.identifier).to eq('pipelines_succeeded') + expect(measurement.count).to eq(1) + end + end end diff --git a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb index 2d633828ae3..9d4d48d0568 100644 --- a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb +++ b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb @@ -11,17 +11,5 @@ RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateWorker do subject.perform end - - context 'feature flag :periodic_project_authorization_recalculation is disabled' do - before do - stub_feature_flags(periodic_project_authorization_recalculation: false) - end - - it 'does not call AuthorizedProjectUpdate::PeriodicRecalculateService' do - expect(AuthorizedProjectUpdate::PeriodicRecalculateService).not_to receive(:new) - - subject.perform - end - end end end diff --git a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb index c49e4c453bf..a27c431523e 100644 --- a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb +++ b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb @@ -14,17 +14,5 @@ RSpec.describe AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker do subject.perform(start_user_id, end_user_id) end - - context 'feature flag :periodic_project_authorization_recalculation is disabled' do - before do - stub_feature_flags(periodic_project_authorization_recalculation: false) - end - - it 'does not call AuthorizedProjectUpdate::RecalculateForUserRangeService' do - expect(AuthorizedProjectUpdate::RecalculateForUserRangeService).not_to receive(:new) - - subject.perform(start_user_id, end_user_id) - end - end end end diff --git a/spec/workers/cleanup_container_repository_worker_spec.rb b/spec/workers/cleanup_container_repository_worker_spec.rb index 0545f7a35e4..9cf8974a2a1 100644 --- a/spec/workers/cleanup_container_repository_worker_spec.rb +++ b/spec/workers/cleanup_container_repository_worker_spec.rb @@ -40,14 +40,35 @@ RSpec.describe CleanupContainerRepositoryWorker, :clean_gitlab_redis_shared_stat context 'container expiration policy' do let(:params) { { key: 'value', 'container_expiration_policy' => true } } + before do + allow(ContainerRepository) + .to receive(:find_by_id).with(repository.id).and_return(repository) + end + it 'executes the destroy service' do + expect(repository).to receive(:start_expiration_policy!).and_call_original + expect(repository).to receive(:reset_expiration_policy_started_at!).and_call_original expect(Projects::ContainerRepository::CleanupTagsService).to receive(:new) .with(project, nil, params.merge('container_expiration_policy' => true)) .and_return(service) - expect(service).to receive(:execute) + expect(service).to receive(:execute).and_return(status: :success) + + subject.perform(nil, repository.id, params) + expect(repository.reload.expiration_policy_started_at).to be_nil + end + + it "doesn't reset the expiration policy started at if the destroy service returns an error" do + expect(repository).to receive(:start_expiration_policy!).and_call_original + expect(repository).not_to receive(:reset_expiration_policy_started_at!) + expect(Projects::ContainerRepository::CleanupTagsService).to receive(:new) + .with(project, nil, params.merge('container_expiration_policy' => true)) + .and_return(service) + + expect(service).to receive(:execute).and_return(status: :error, message: 'timeout while deleting tags') subject.perform(nil, repository.id, params) + expect(repository.reload.expiration_policy_started_at).not_to be_nil end end end diff --git a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb new file mode 100644 index 00000000000..2c79f347903 --- /dev/null +++ b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_queues do + let(:job_tracker) do + described_class.new('namespace') + end + + describe '#register' do + it 'adds jid to the set' do + job_tracker.register('a-job-id') + + expect(job_tracker.running_jids).to contain_exactly('a-job-id') + end + + it 'updates the counter' do + expect { job_tracker.register('a-job-id') } + .to change { job_tracker.count } + .from(0) + .to(1) + end + + it 'does it in only one Redis call' do + expect(job_tracker).to receive(:with_redis).once.and_call_original + + job_tracker.register('a-job-id') + end + end + + describe '#remove' do + before do + job_tracker.register(%w[a-job-id other-job-id]) + end + + it 'removes jid from the set' do + job_tracker.remove('other-job-id') + + expect(job_tracker.running_jids).to contain_exactly('a-job-id') + end + + it 'updates the counter' do + expect { job_tracker.remove('other-job-id') } + .to change { job_tracker.count } + .from(2) + .to(1) + end + + it 'does it in only one Redis call' do + expect(job_tracker).to receive(:with_redis).once.and_call_original + + job_tracker.remove('other-job-id') + end + end + + describe '#clean_up' do + before do + job_tracker.register('a-job-id') + end + + context 'with running jobs' do + before do + expect(Gitlab::SidekiqStatus).to receive(:completed_jids) + .with(%w[a-job-id]) + .and_return([]) + end + + it 'does not remove the jid from the set' do + expect { job_tracker.clean_up } + .not_to change { job_tracker.running_jids.include?('a-job-id') } + end + + it 'does only one Redis call to get the job ids' do + expect(job_tracker).to receive(:with_redis).once.and_call_original + + job_tracker.clean_up + end + end + + context 'with completed jobs' do + it 'removes the jid from the set' do + expect { job_tracker.clean_up } + .to change { job_tracker.running_jids.include?('a-job-id') } + end + + it 'updates the counter' do + expect { job_tracker.clean_up } + .to change { job_tracker.count } + .from(1) + .to(0) + end + + it 'gets the job ids, removes them, and updates the counter with only two Redis calls' do + expect(job_tracker).to receive(:with_redis).twice.and_call_original + + job_tracker.clean_up + end + end + end +end diff --git a/spec/workers/concerns/limited_capacity/worker_spec.rb b/spec/workers/concerns/limited_capacity/worker_spec.rb new file mode 100644 index 00000000000..8a15675c04d --- /dev/null +++ b/spec/workers/concerns/limited_capacity/worker_spec.rb @@ -0,0 +1,285 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_failures do + let(:worker_class) do + Class.new do + def self.name + 'DummyWorker' + end + + include ApplicationWorker + include LimitedCapacity::Worker + end + end + + let(:worker) { worker_class.new } + + let(:job_tracker) do + LimitedCapacity::JobTracker.new(worker_class.name) + end + + before do + worker.jid = 'my-jid' + allow(worker).to receive(:job_tracker).and_return(job_tracker) + end + + describe 'required methods' do + it { expect { worker.perform_work }.to raise_error(NotImplementedError) } + it { expect { worker.remaining_work_count }.to raise_error(NotImplementedError) } + it { expect { worker.max_running_jobs }.to raise_error(NotImplementedError) } + end + + describe 'Sidekiq options' do + it 'does not retry failed jobs' do + expect(worker_class.sidekiq_options['retry']).to eq(0) + end + + it 'does not deduplicate jobs' do + expect(worker_class.get_deduplicate_strategy).to eq(:none) + end + end + + describe '.perform_with_capacity' do + subject(:perform_with_capacity) { worker_class.perform_with_capacity(:arg) } + + before do + expect_next_instance_of(worker_class) do |instance| + expect(instance).to receive(:remove_failed_jobs) + expect(instance).to receive(:report_prometheus_metrics) + + allow(instance).to receive(:remaining_work_count).and_return(remaining_work_count) + allow(instance).to receive(:remaining_capacity).and_return(remaining_capacity) + end + end + + context 'when capacity is larger than work' do + let(:remaining_work_count) { 2 } + let(:remaining_capacity) { 3 } + + it 'enqueues jobs for remaining work' do + expect(worker_class) + .to receive(:bulk_perform_async) + .with([[:arg], [:arg]]) + + perform_with_capacity + end + end + + context 'when capacity is lower than work' do + let(:remaining_work_count) { 5 } + let(:remaining_capacity) { 3 } + + it 'enqueues jobs for remaining work' do + expect(worker_class) + .to receive(:bulk_perform_async) + .with([[:arg], [:arg], [:arg]]) + + perform_with_capacity + end + end + end + + describe '#perform' do + subject(:perform) { worker.perform(:arg) } + + context 'with capacity' do + before do + allow(worker).to receive(:max_running_jobs).and_return(10) + allow(worker).to receive(:running_jobs_count).and_return(0) + allow(worker).to receive(:remaining_work_count).and_return(0) + end + + it 'calls perform_work' do + expect(worker).to receive(:perform_work).with(:arg) + + perform + end + + it 're-enqueues itself' do + allow(worker).to receive(:perform_work) + expect(worker).to receive(:re_enqueue).with(:arg) + + perform + end + + it 'registers itself in the running set' do + allow(worker).to receive(:perform_work) + expect(job_tracker).to receive(:register).with('my-jid') + + perform + end + + it 'removes itself from the running set' do + expect(job_tracker).to receive(:remove).with('my-jid') + + allow(worker).to receive(:perform_work) + + perform + end + + it 'reports prometheus metrics' do + allow(worker).to receive(:perform_work) + expect(worker).to receive(:report_prometheus_metrics) + + perform + end + end + + context 'with capacity and without work' do + before do + allow(worker).to receive(:max_running_jobs).and_return(10) + allow(worker).to receive(:running_jobs_count).and_return(0) + allow(worker).to receive(:remaining_work_count).and_return(0) + allow(worker).to receive(:perform_work) + end + + it 'does not re-enqueue itself' do + expect(worker_class).not_to receive(:perform_async) + + perform + end + end + + context 'without capacity' do + before do + allow(worker).to receive(:max_running_jobs).and_return(10) + allow(worker).to receive(:running_jobs_count).and_return(15) + allow(worker).to receive(:remaining_work_count).and_return(10) + end + + it 'does not call perform_work' do + expect(worker).not_to receive(:perform_work) + + perform + end + + it 'does not re-enqueue itself' do + expect(worker_class).not_to receive(:perform_async) + + perform + end + + it 'does not register in the running set' do + expect(job_tracker).not_to receive(:register) + + perform + end + + it 'removes itself from the running set' do + expect(job_tracker).to receive(:remove).with('my-jid') + + perform + end + + it 'reports prometheus metrics' do + expect(worker).to receive(:report_prometheus_metrics) + + perform + end + end + + context 'when perform_work fails' do + it 'does not re-enqueue itself' do + expect(worker).not_to receive(:re_enqueue) + + expect { perform }.to raise_error(NotImplementedError) + end + + it 'removes itself from the running set' do + expect(job_tracker).to receive(:remove) + + expect { perform }.to raise_error(NotImplementedError) + end + + it 'reports prometheus metrics' do + expect(worker).to receive(:report_prometheus_metrics) + + expect { perform }.to raise_error(NotImplementedError) + end + end + end + + describe '#remaining_capacity' do + subject(:remaining_capacity) { worker.remaining_capacity } + + before do + expect(worker).to receive(:max_running_jobs).and_return(max_capacity) + end + + context 'when changing the capacity to a lower value' do + let(:max_capacity) { -1 } + + it { expect(remaining_capacity).to eq(0) } + end + + context 'when registering new jobs' do + let(:max_capacity) { 2 } + + before do + job_tracker.register('a-job-id') + end + + it { expect(remaining_capacity).to eq(1) } + end + + context 'with jobs in the queue' do + let(:max_capacity) { 2 } + + before do + expect(worker_class).to receive(:queue_size).and_return(1) + end + + it { expect(remaining_capacity).to eq(1) } + end + + context 'with both running jobs and queued jobs' do + let(:max_capacity) { 10 } + + before do + expect(worker_class).to receive(:queue_size).and_return(5) + expect(worker).to receive(:running_jobs_count).and_return(3) + end + + it { expect(remaining_capacity).to eq(2) } + end + end + + describe '#remove_failed_jobs' do + subject(:remove_failed_jobs) { worker.remove_failed_jobs } + + before do + job_tracker.register('a-job-id') + allow(worker).to receive(:max_running_jobs).and_return(2) + + expect(job_tracker).to receive(:clean_up).and_call_original + end + + context 'with failed jobs' do + it 'update the available capacity' do + expect { remove_failed_jobs }.to change { worker.remaining_capacity }.by(1) + end + end + end + + describe '#report_prometheus_metrics' do + subject(:report_prometheus_metrics) { worker.report_prometheus_metrics } + + before do + allow(worker).to receive(:running_jobs_count).and_return(5) + allow(worker).to receive(:max_running_jobs).and_return(7) + allow(worker).to receive(:remaining_work_count).and_return(9) + end + + it 'reports number of running jobs' do + labels = { worker: 'DummyWorker' } + + report_prometheus_metrics + + expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_running_jobs).get(labels)).to eq(5) + expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_max_running_jobs).get(labels)).to eq(7) + expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_remaining_work_count).get(labels)).to eq(9) + end + end +end diff --git a/spec/workers/design_management/copy_design_collection_worker_spec.rb b/spec/workers/design_management/copy_design_collection_worker_spec.rb new file mode 100644 index 00000000000..45bfc47ca7e --- /dev/null +++ b/spec/workers/design_management/copy_design_collection_worker_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe DesignManagement::CopyDesignCollectionWorker, :clean_gitlab_redis_shared_state do + describe '#perform' do + let_it_be(:user) { create(:user) } + let_it_be(:issue) { create(:issue) } + let_it_be(:target_issue) { create(:issue) } + + subject { described_class.new.perform(user.id, issue.id, target_issue.id) } + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [user.id, issue.id, target_issue.id] } + + specify { subject } + end + + it 'calls DesignManagement::CopyDesignCollection::CopyService' do + expect_next_instance_of(DesignManagement::CopyDesignCollection::CopyService) do |service| + expect(service).to receive(:execute).and_return(ServiceResponse.success) + end + + subject + end + + it 'logs if there was an error calling the service' do + message = 'Error message' + + allow_next_instance_of(DesignManagement::CopyDesignCollection::CopyService) do |service| + allow(service).to receive(:execute).and_return(ServiceResponse.error(message: message)) + end + + expect(Gitlab::AppLogger).to receive(:warn).with(message) + + subject + end + end +end diff --git a/spec/workers/design_management/new_version_worker_spec.rb b/spec/workers/design_management/new_version_worker_spec.rb index 4d57c46487e..3320d7a062d 100644 --- a/spec/workers/design_management/new_version_worker_spec.rb +++ b/spec/workers/design_management/new_version_worker_spec.rb @@ -36,6 +36,10 @@ RSpec.describe DesignManagement::NewVersionWorker do expect { worker.perform(version.id) }.to change { Note.system.count }.by(1) end + it 'does not create a system note if skip_system_notes is true' do + expect { worker.perform(version.id, true) }.not_to change { Note.system.count } + end + it 'invokes GenerateImageVersionsService' do expect_next_instance_of(DesignManagement::GenerateImageVersionsService) do |service| expect(service).to receive(:execute) diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 1be6e86b650..018971e288c 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -129,46 +129,36 @@ RSpec.describe GitGarbageCollectWorker do let_it_be(:lfs_reference) { create(:lfs_objects_project, project: project) } let(:lfs_object) { lfs_reference.lfs_object } - context 'with cleanup_lfs_during_gc feature flag enabled' do - before do - stub_feature_flags(cleanup_lfs_during_gc: true) + it 'cleans up unreferenced LFS objects' do + expect_next_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences) do |svc| + expect(svc.project).to eq(project) + expect(svc.dry_run).to be_falsy + expect(svc).to receive(:run!).and_call_original end - it 'cleans up unreferenced LFS objects' do - expect_next_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences) do |svc| - expect(svc.project).to eq(project) - expect(svc.dry_run).to be_falsy - expect(svc).to receive(:run!).and_call_original - end - - subject.perform(*params) - - expect(project.lfs_objects.reload).not_to include(lfs_object) - end + subject.perform(*params) - it 'does nothing if the database is read-only' do - allow(Gitlab::Database).to receive(:read_only?) { true } + expect(project.lfs_objects.reload).not_to include(lfs_object) + end - expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!) + it 'catches and logs exceptions' do + expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences) + .to receive(:run!) + .and_raise(/Failed/) - subject.perform(*params) + expect(Gitlab::GitLogger).to receive(:warn) + expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception) - expect(project.lfs_objects.reload).to include(lfs_object) - end + subject.perform(*params) end - context 'with cleanup_lfs_during_gc feature flag disabled' do - before do - stub_feature_flags(cleanup_lfs_during_gc: false) - end - - it 'does not clean up unreferenced LFS objects' do - expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!) + it 'does nothing if the database is read-only' do + allow(Gitlab::Database).to receive(:read_only?) { true } + expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!) - subject.perform(*params) + subject.perform(*params) - expect(project.lfs_objects.reload).to include(lfs_object) - end + expect(project.lfs_objects.reload).to include(lfs_object) end end end diff --git a/spec/workers/group_import_worker_spec.rb b/spec/workers/group_import_worker_spec.rb index fb2d49c21af..3fa24ecd7bc 100644 --- a/spec/workers/group_import_worker_spec.rb +++ b/spec/workers/group_import_worker_spec.rb @@ -3,12 +3,14 @@ require 'spec_helper' RSpec.describe GroupImportWorker do - let!(:user) { create(:user) } - let!(:group) { create(:group) } + let(:user) { create(:user) } + let(:group) { create(:group) } subject { described_class.new } before do + create(:group_import_state, group: group, user: user) + allow_next_instance_of(described_class) do |job| allow(job).to receive(:jid).and_return(SecureRandom.hex(8)) end @@ -26,44 +28,11 @@ RSpec.describe GroupImportWorker do subject.perform(user.id, group.id) end - context 'when the import state does not exist' do - it 'creates group import' do - expect(group.import_state).to be_nil - - subject.perform(user.id, group.id) - import_state = group.reload.import_state - - expect(import_state).to be_instance_of(GroupImportState) - expect(import_state.status_name).to eq(:finished) - expect(import_state.jid).not_to be_empty - end - - it 'sets the group import status to started' do - expect_next_instance_of(GroupImportState) do |import| - expect(import).to receive(:start!).and_call_original - end - - subject.perform(user.id, group.id) - end - - it 'sets the group import status to finished' do - expect_next_instance_of(GroupImportState) do |import| - expect(import).to receive(:finish!).and_call_original - end + it 'updates the existing state' do + expect { subject.perform(user.id, group.id) } + .not_to change { GroupImportState.count } - subject.perform(user.id, group.id) - end - end - - context 'when the import state already exists' do - it 'updates the existing state' do - existing_state = create(:group_import_state, group: group) - - expect { subject.perform(user.id, group.id) } - .not_to change { GroupImportState.count } - - expect(existing_state.reload).to be_finished - end + expect(group.import_state.reload).to be_finished end end @@ -83,11 +52,9 @@ RSpec.describe GroupImportWorker do end it 'sets the group import status to failed' do - expect_next_instance_of(GroupImportState) do |import| - expect(import).to receive(:fail_op).and_call_original - end - expect { subject.perform(user.id, group.id) }.to raise_exception(Gitlab::ImportExport::Error) + + expect(group.import_state.reload.status).to eq(-1) end end end diff --git a/spec/workers/incident_management/add_severity_system_note_worker_spec.rb b/spec/workers/incident_management/add_severity_system_note_worker_spec.rb new file mode 100644 index 00000000000..203c62ffe6f --- /dev/null +++ b/spec/workers/incident_management/add_severity_system_note_worker_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:issuable_severity) { create(:issuable_severity, issue: incident, severity: :medium) } + + describe '#perform' do + let(:incident_id) { incident.id } + let(:user_id) { user.id } + + subject(:perform) { described_class.new.perform(incident_id, user_id) } + + shared_examples 'does not add a system note' do + it 'does not change incident notes count' do + expect { perform }.not_to change { incident.notes.count } + end + end + + context 'when incident and user exist' do + it 'creates a system note' do + expect { perform }.to change { incident.notes.where(author: user).count }.by(1) + end + end + + context 'when incident does not exist' do + let(:incident_id) { -1 } + + it_behaves_like 'does not add a system note' + end + + context 'when incident_id is nil' do + let(:incident_id) { nil } + + it_behaves_like 'does not add a system note' + end + + context 'when issue is not an incident' do + let_it_be(:issue) { create(:issue, project: project) } + let(:incident_id) { issue.id } + + it_behaves_like 'does not add a system note' + end + + context 'when user does not exist' do + let(:user_id) { -1 } + + it_behaves_like 'does not add a system note' + end + + context 'when user_id is nil' do + let(:user_id) { nil } + + it_behaves_like 'does not add a system note' + end + end +end diff --git a/spec/workers/incident_management/process_alert_worker_spec.rb b/spec/workers/incident_management/process_alert_worker_spec.rb index 20ab283b49b..41d4f31da24 100644 --- a/spec/workers/incident_management/process_alert_worker_spec.rb +++ b/spec/workers/incident_management/process_alert_worker_spec.rb @@ -9,7 +9,6 @@ RSpec.describe IncidentManagement::ProcessAlertWorker do describe '#perform' do let_it_be(:started_at) { Time.now.rfc3339 } let_it_be(:payload) { { 'title' => 'title', 'start_time' => started_at } } - let_it_be(:parsed_payload) { Gitlab::Alerting::NotificationPayloadParser.call(payload, project) } let_it_be(:alert) { create(:alert_management_alert, project: project, payload: payload, started_at: started_at) } let(:created_issue) { Issue.last! } @@ -68,7 +67,6 @@ RSpec.describe IncidentManagement::ProcessAlertWorker do context 'prometheus alert' do let_it_be(:alert) { create(:alert_management_alert, :prometheus, project: project, started_at: started_at) } - let_it_be(:parsed_payload) { alert.payload } it_behaves_like 'creates issue successfully' end diff --git a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb index c294892a66f..2ca4193aa72 100644 --- a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb +++ b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb @@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::ProcessPrometheusAlertWorker do describe '#perform' do let_it_be(:project) { create(:project) } let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) } - let(:payload_key) { Gitlab::Alerting::Alert.new(project: project, payload: alert_params).gitlab_fingerprint } + let(:payload_key) { Gitlab::AlertManagement::Payload::Prometheus.new(project: project, payload: alert_params).gitlab_fingerprint } let!(:prometheus_alert_event) { create(:prometheus_alert_event, prometheus_alert: prometheus_alert, payload_key: payload_key) } let!(:settings) { create(:project_incident_management_setting, project: project, create_issue: true) } diff --git a/spec/workers/member_invitation_reminder_emails_worker_spec.rb b/spec/workers/member_invitation_reminder_emails_worker_spec.rb new file mode 100644 index 00000000000..64d096f84f5 --- /dev/null +++ b/spec/workers/member_invitation_reminder_emails_worker_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MemberInvitationReminderEmailsWorker do + describe '#perform' do + subject { described_class.new.perform } + + context 'feature flag disabled' do + before do + stub_experiment(invitation_reminders: false) + end + + it 'does not raise an error' do + expect { subject }.not_to raise_error + end + end + + context 'feature flag enabled' do + before do + stub_experiment(invitation_reminders: true) + end + + it 'does not raise an error' do + expect { subject }.not_to raise_error + end + end + end +end diff --git a/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb new file mode 100644 index 00000000000..19b79835825 --- /dev/null +++ b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Metrics::Dashboard::SyncDashboardsWorker do + include MetricsDashboardHelpers + subject(:worker) { described_class.new } + + let(:project) { project_with_dashboard(dashboard_path) } + let(:dashboard_path) { '.gitlab/dashboards/test.yml' } + + describe ".perform" do + it 'imports metrics' do + expect { worker.perform(project.id) }.to change(PrometheusMetric, :count).by(3) + end + + it 'is idempotent' do + 2.times do + worker.perform(project.id) + end + + expect(PrometheusMetric.count).to eq(3) + end + end +end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 50d164d1705..cb626b08456 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -290,7 +290,7 @@ RSpec.describe PostReceive do # MySQL drops milliseconds in the timestamps, so advance at least # a second to ensure we see changes. - Timecop.freeze(1.second.from_now) do + travel_to(1.second.from_now) do expect do perform project.reload diff --git a/spec/workers/propagate_integration_group_worker_spec.rb b/spec/workers/propagate_integration_group_worker_spec.rb new file mode 100644 index 00000000000..b3c9255db57 --- /dev/null +++ b/spec/workers/propagate_integration_group_worker_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PropagateIntegrationGroupWorker do + describe '#perform' do + let_it_be(:group1) { create(:group) } + let_it_be(:group2) { create(:group) } + let_it_be(:integration) { create(:redmine_service, :instance) } + + before do + allow(BulkCreateIntegrationService).to receive(:new) + .with(integration, match_array([group1, group2]), 'group') + .and_return(double(execute: nil)) + end + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [integration.id, group1.id, group2.id] } + + it 'calls to BulkCreateIntegrationService' do + expect(BulkCreateIntegrationService).to receive(:new) + .with(integration, match_array([group1, group2]), 'group') + .and_return(double(execute: nil)) + + subject + end + end + + context 'with an invalid integration id' do + it 'returns without failure' do + expect(BulkCreateIntegrationService).not_to receive(:new) + + subject.perform(0, group1.id, group2.id) + end + end + end +end diff --git a/spec/workers/propagate_integration_inherit_worker_spec.rb b/spec/workers/propagate_integration_inherit_worker_spec.rb new file mode 100644 index 00000000000..88946b9926e --- /dev/null +++ b/spec/workers/propagate_integration_inherit_worker_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PropagateIntegrationInheritWorker do + describe '#perform' do + let_it_be(:integration) { create(:redmine_service, :instance) } + let_it_be(:integration1) { create(:redmine_service, inherit_from_id: integration.id) } + let_it_be(:integration2) { create(:bugzilla_service, inherit_from_id: integration.id) } + let_it_be(:integration3) { create(:redmine_service) } + + before do + allow(BulkUpdateIntegrationService).to receive(:new) + .with(integration, match_array(integration1)) + .and_return(double(execute: nil)) + end + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [integration.id, integration1.id, integration3.id] } + + it 'calls to BulkCreateIntegrationService' do + expect(BulkUpdateIntegrationService).to receive(:new) + .with(integration, match_array(integration1)) + .and_return(double(execute: nil)) + + subject + end + end + + context 'with an invalid integration id' do + it 'returns without failure' do + expect(BulkUpdateIntegrationService).not_to receive(:new) + + subject.perform(0, integration1.id, integration3.id) + end + end + end +end diff --git a/spec/workers/propagate_integration_project_worker_spec.rb b/spec/workers/propagate_integration_project_worker_spec.rb new file mode 100644 index 00000000000..3742ce5fde8 --- /dev/null +++ b/spec/workers/propagate_integration_project_worker_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PropagateIntegrationProjectWorker do + describe '#perform' do + let_it_be(:project1) { create(:project) } + let_it_be(:project2) { create(:project) } + let_it_be(:integration) { create(:redmine_service, :instance) } + + before do + allow(BulkCreateIntegrationService).to receive(:new) + .with(integration, match_array([project1, project2]), 'project') + .and_return(double(execute: nil)) + end + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [integration.id, project1.id, project2.id] } + + it 'calls to BulkCreateIntegrationService' do + expect(BulkCreateIntegrationService).to receive(:new) + .with(integration, match_array([project1, project2]), 'project') + .and_return(double(execute: nil)) + + subject + end + end + + context 'with an invalid integration id' do + it 'returns without failure' do + expect(BulkCreateIntegrationService).not_to receive(:new) + + subject.perform(0, project1.id, project2.id) + end + end + end +end |