diff options
Diffstat (limited to 'spec/workers/container_registry/delete_container_repository_worker_spec.rb')
-rw-r--r-- | spec/workers/container_registry/delete_container_repository_worker_spec.rb | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/spec/workers/container_registry/delete_container_repository_worker_spec.rb b/spec/workers/container_registry/delete_container_repository_worker_spec.rb new file mode 100644 index 00000000000..381e0cc164c --- /dev/null +++ b/spec/workers/container_registry/delete_container_repository_worker_spec.rb @@ -0,0 +1,146 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ContainerRegistry::DeleteContainerRepositoryWorker, :aggregate_failures do + let_it_be_with_reload(:container_repository) { create(:container_repository) } + let_it_be(:second_container_repository) { create(:container_repository) } + + let(:worker) { described_class.new } + + describe '#perform_work' do + subject(:perform_work) { worker.perform_work } + + context 'with no work to do - no container repositories pending deletion' do + it 'will not delete any container repository' do + expect(::Projects::ContainerRepository::CleanupTagsService).not_to receive(:new) + + expect { perform_work }.to not_change { ContainerRepository.count } + end + end + + context 'with work to do' do + let(:tags_count) { 0 } + let(:cleanup_tags_service_response) { { status: :success, original_size: 100, deleted_size: 0 } } + let(:cleanup_tags_service_double) do + instance_double('Projects::ContainerRepository::CleanupTagsService', execute: cleanup_tags_service_response) + end + + before do + container_repository.delete_scheduled! + allow(Projects::ContainerRepository::CleanupTagsService) + .to receive(:new) + .with(container_repository: container_repository, params: described_class::CLEANUP_TAGS_SERVICE_PARAMS) + .and_return(cleanup_tags_service_double) + end + + it 'picks and destroys the delete scheduled container repository' do + expect_next_pending_destruction_container_repository do |repo| + expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0) + expect(repo).to receive(:destroy!).and_call_original + end + perform_work + expect(ContainerRepository.all).to contain_exactly(second_container_repository) + end + + context 'with an error during the tags cleanup' do + let(:cleanup_tags_service_response) { { status: :error, original_size: 100, deleted_size: 0 } } + + it 'does not delete the container repository' do + expect_next_pending_destruction_container_repository do |repo| + expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0) + expect(repo).to receive(:set_delete_scheduled_status).and_call_original + expect(repo).not_to receive(:destroy!) + end + expect { perform_work }.to not_change(ContainerRepository, :count) + .and not_change { container_repository.reload.status } + expect(container_repository.delete_started_at).to eq(nil) + end + end + + context 'with an error during the destroy' do + it 'does not delete the container repository' do + expect_next_pending_destruction_container_repository do |repo| + expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0) + expect(repo).to receive(:destroy!).and_raise('Error!') + expect(repo).to receive(:set_delete_scheduled_status).and_call_original + end + + expect(::Gitlab::ErrorTracking).to receive(:log_exception) + .with(instance_of(RuntimeError), class: described_class.name) + expect { perform_work }.to not_change(ContainerRepository, :count) + .and not_change { container_repository.reload.status } + expect(container_repository.delete_started_at).to eq(nil) + end + end + + context 'with tags left to destroy' do + let(:tags_count) { 10 } + + it 'does not delete the container repository' do + expect_next_pending_destruction_container_repository do |repo| + expect(repo).not_to receive(:destroy!) + expect(repo).to receive(:set_delete_scheduled_status).and_call_original + end + + expect { perform_work }.to not_change(ContainerRepository, :count) + .and not_change { container_repository.reload.status } + expect(container_repository.delete_started_at).to eq(nil) + end + end + + context 'with no tags on the container repository' do + let(:tags_count) { 0 } + let(:cleanup_tags_service_response) { { status: :success, original_size: 0, deleted_size: 0 } } + + it 'picks and destroys the delete scheduled container repository' do + expect_next_pending_destruction_container_repository do |repo| + expect_logs_on(repo, tags_size_before_delete: 0, deleted_tags_size: 0) + expect(repo).to receive(:destroy!).and_call_original + end + perform_work + expect(ContainerRepository.all).to contain_exactly(second_container_repository) + end + end + + def expect_next_pending_destruction_container_repository + original_method = ContainerRepository.method(:next_pending_destruction) + expect(ContainerRepository).to receive(:next_pending_destruction).with(order_by: nil) do + original_method.call(order_by: nil).tap do |repo| + allow(repo).to receive(:tags_count).and_return(tags_count) + expect(repo).to receive(:set_delete_ongoing_status).and_call_original + yield repo + end + end + end + + def expect_logs_on(container_repository, tags_size_before_delete:, deleted_tags_size:) + payload = { + project_id: container_repository.project.id, + container_repository_id: container_repository.id, + container_repository_path: container_repository.path, + tags_size_before_delete: tags_size_before_delete, + deleted_tags_size: deleted_tags_size + } + expect(worker.logger).to receive(:info).with(worker.structured_payload(payload)) + .and_call_original + end + end + end + + describe '#max_running_jobs' do + subject { worker.max_running_jobs } + + it { is_expected.to eq(described_class::MAX_CAPACITY) } + end + + describe '#remaining_work_count' do + let_it_be(:delete_scheduled_container_repositories) do + create_list(:container_repository, described_class::MAX_CAPACITY + 2, :status_delete_scheduled) + end + + subject { worker.remaining_work_count } + + it { is_expected.to eq(described_class::MAX_CAPACITY + 1) } + end +end |