diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 88cb09d9fa6c3ca75d3745e1b443a13445755f2d..27dda6f9b9e18918cf733bb64403c58dd07028b8 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -4564,6 +4564,16 @@ :idempotent: true :tags: [] :queue_namespace: +- :name: organizations_groups_transfer + :worker_name: Organizations::Groups::TransferWorker + :feature_category: :organization + :has_external_dependencies: false + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] + :queue_namespace: - :name: pages :worker_name: PagesWorker :feature_category: :pages diff --git a/app/workers/organizations/groups/transfer_worker.rb b/app/workers/organizations/groups/transfer_worker.rb new file mode 100644 index 0000000000000000000000000000000000000000..ed3694a771b9ef80f12649d5b8dff82006b1433b --- /dev/null +++ b/app/workers/organizations/groups/transfer_worker.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Organizations + module Groups + class TransferWorker + include ApplicationWorker + + data_consistency :sticky + idempotent! + + feature_category :organization + urgency :low + + defer_on_database_health_signal :gitlab_main, [:groups], 1.minute + + def perform(args) + group_id = args['group_id'] + organization_id = args['organization_id'] + current_user_id = args['current_user_id'] + + group = Group.find_by_id(group_id) + return unless group + + organization = Organization.find_by_id(organization_id) + return unless organization + + current_user = User.find_by_id(current_user_id) + return unless current_user + + Organizations::Groups::TransferService.new( + group: group, + new_organization: organization, + current_user: current_user + ).execute + end + end + end +end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 3e764c38432da9e15fea9e285e151302b68ceec0..c578c061a1e3647a6bc79f1344381c5133721a27 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -731,6 +731,8 @@ - 1 - - onboarding_progress_tracking - 1 +- - organizations_groups_transfer + - 1 - - package_cleanup - 1 - - package_metadata_global_advisory_scan diff --git a/spec/workers/organizations/groups/transfer_worker_spec.rb b/spec/workers/organizations/groups/transfer_worker_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3cf91065d241ea4daf1b89c6c8bed8eb4d4e9577 --- /dev/null +++ b/spec/workers/organizations/groups/transfer_worker_spec.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Organizations::Groups::TransferWorker, feature_category: :organization do + let_it_be(:group) { create(:group) } + let_it_be(:organization) { create(:organization) } + let_it_be(:user) { create(:user) } + + let(:worker) { described_class.new } + let(:args) do + { + 'group_id' => group.id, + 'organization_id' => organization.id, + 'current_user_id' => user.id + } + end + + describe '#perform' do + subject(:perform) { worker.perform(args) } + + context 'when all records exist' do + it 'calls the transfer service' do + expect_next_instance_of( + Organizations::Groups::TransferService, + group: group, + new_organization: organization, + current_user: user + ) do |service| + expect(service).to receive(:execute) + end + + perform + end + end + + context 'when group does not exist' do + let(:args) do + { + 'group_id' => non_existing_record_id, + 'organization_id' => organization.id, + 'current_user_id' => user.id + } + end + + it 'does not call the transfer service' do + expect(Organizations::Groups::TransferService).not_to receive(:new) + + perform + end + + it 'does not raise an error' do + expect { perform }.not_to raise_error + end + end + + context 'when organization does not exist' do + let(:args) do + { + 'group_id' => group.id, + 'organization_id' => non_existing_record_id, + 'current_user_id' => user.id + } + end + + it 'does not call the transfer service' do + expect(Organizations::Groups::TransferService).not_to receive(:new) + + perform + end + + it 'does not raise an error' do + expect { perform }.not_to raise_error + end + end + + context 'when user does not exist' do + let(:args) do + { + 'group_id' => group.id, + 'organization_id' => organization.id, + 'current_user_id' => non_existing_record_id + } + end + + it 'does not call the transfer service' do + expect(Organizations::Groups::TransferService).not_to receive(:new) + + perform + end + + it 'does not raise an error' do + expect { perform }.not_to raise_error + end + end + end + + describe 'worker attributes' do + it 'is idempotent' do + expect(described_class).to be_idempotent + end + + it 'has the correct feature category' do + expect(described_class.get_feature_category).to eq(:organization) + end + + it 'has low urgency' do + expect(described_class.get_urgency).to eq(:low) + end + end + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [args] } + end +end