debian-mirror-gitlab/spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb
2021-01-29 00:20:46 +05:30

235 lines
8 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ContainerExpirationPolicies::CleanupContainerRepositoryWorker do
let_it_be(:repository, reload: true) { create(:container_repository, :cleanup_scheduled) }
let_it_be(:project) { repository.project }
let_it_be(:policy) { project.container_expiration_policy }
let_it_be(:other_repository) { create(:container_repository) }
let(:worker) { described_class.new }
describe '#perform_work' do
subject { worker.perform_work }
before do
policy.update_column(:enabled, true)
end
RSpec.shared_examples 'handling all repository conditions' do
it 'sends the repository for cleaning' do
expect(ContainerExpirationPolicies::CleanupService)
.to receive(:new).with(repository).and_return(double(execute: cleanup_service_response(repository: repository)))
expect(worker).to receive(:log_extra_metadata_on_done).with(:cleanup_status, :finished)
expect(worker).to receive(:log_extra_metadata_on_done).with(:container_repository_id, repository.id)
subject
end
context 'with unfinished cleanup' do
it 'logs an unfinished cleanup' do
expect(ContainerExpirationPolicies::CleanupService)
.to receive(:new).with(repository).and_return(double(execute: cleanup_service_response(status: :unfinished, repository: repository)))
expect(worker).to receive(:log_extra_metadata_on_done).with(:cleanup_status, :unfinished)
expect(worker).to receive(:log_extra_metadata_on_done).with(:container_repository_id, repository.id)
subject
end
end
context 'with policy running shortly' do
before do
repository.project
.container_expiration_policy
.update_column(:next_run_at, 1.minute.from_now)
end
it 'skips the repository' do
expect(ContainerExpirationPolicies::CleanupService).not_to receive(:new)
expect(worker).to receive(:log_extra_metadata_on_done).with(:container_repository_id, repository.id)
expect(worker).to receive(:log_extra_metadata_on_done).with(:cleanup_status, :skipped)
expect { subject }.to change { ContainerRepository.waiting_for_cleanup.count }.from(1).to(0)
expect(repository.reload.cleanup_unscheduled?).to be_truthy
end
end
context 'with disabled policy' do
before do
repository.project
.container_expiration_policy
.disable!
end
it 'skips the repository' do
expect(ContainerExpirationPolicies::CleanupService).not_to receive(:new)
expect { subject }.to change { ContainerRepository.waiting_for_cleanup.count }.from(1).to(0)
expect(repository.reload.cleanup_unscheduled?).to be_truthy
end
end
end
context 'with repository in cleanup scheduled state' do
it_behaves_like 'handling all repository conditions'
end
context 'with repository in cleanup unfinished state' do
before do
repository.cleanup_unfinished!
end
it_behaves_like 'handling all repository conditions'
end
context 'with another repository in cleanup unfinished state' do
let_it_be(:another_repository) { create(:container_repository, :cleanup_unfinished) }
it 'process the cleanup scheduled repository first' do
expect(ContainerExpirationPolicies::CleanupService)
.to receive(:new).with(repository).and_return(double(execute: cleanup_service_response(repository: repository)))
expect(worker).to receive(:log_extra_metadata_on_done).with(:cleanup_status, :finished)
expect(worker).to receive(:log_extra_metadata_on_done).with(:container_repository_id, repository.id)
subject
end
end
context 'with multiple repositories in cleanup unfinished state' do
let_it_be(:repository2) { create(:container_repository, :cleanup_unfinished, expiration_policy_started_at: 20.minutes.ago) }
let_it_be(:repository3) { create(:container_repository, :cleanup_unfinished, expiration_policy_started_at: 10.minutes.ago) }
before do
repository.update!(expiration_policy_cleanup_status: :cleanup_unfinished, expiration_policy_started_at: 30.minutes.ago)
end
it 'process the repository with the oldest expiration_policy_started_at' do
expect(ContainerExpirationPolicies::CleanupService)
.to receive(:new).with(repository).and_return(double(execute: cleanup_service_response(repository: repository)))
expect(worker).to receive(:log_extra_metadata_on_done).with(:cleanup_status, :finished)
expect(worker).to receive(:log_extra_metadata_on_done).with(:container_repository_id, repository.id)
subject
end
end
context 'with repository in cleanup ongoing state' do
before do
repository.cleanup_ongoing!
end
it 'does not process it' do
expect(Projects::ContainerRepository::CleanupTagsService).not_to receive(:new)
expect { subject }.not_to change { ContainerRepository.waiting_for_cleanup.count }
expect(repository.cleanup_ongoing?).to be_truthy
end
end
context 'with no repository in any cleanup state' do
before do
repository.cleanup_unscheduled!
end
it 'does not process it' do
expect(Projects::ContainerRepository::CleanupTagsService).not_to receive(:new)
expect { subject }.not_to change { ContainerRepository.waiting_for_cleanup.count }
expect(repository.cleanup_unscheduled?).to be_truthy
end
end
context 'with no container repository waiting' do
before do
repository.destroy!
end
it 'does not execute the cleanup tags service' do
expect(Projects::ContainerRepository::CleanupTagsService).not_to receive(:new)
expect { subject }.not_to change { ContainerRepository.waiting_for_cleanup.count }
end
end
context 'with feature flag disabled' do
before do
stub_feature_flags(container_registry_expiration_policies_throttling: false)
end
it 'is a no-op' do
expect(Projects::ContainerRepository::CleanupTagsService).not_to receive(:new)
expect { subject }.not_to change { ContainerRepository.waiting_for_cleanup.count }
end
end
def cleanup_service_response(status: :finished, repository:)
ServiceResponse.success(message: "cleanup #{status}", payload: { cleanup_status: status, container_repository_id: repository.id })
end
end
describe '#remaining_work_count' do
subject { worker.remaining_work_count }
context 'with container repositoires waiting for cleanup' do
let_it_be(:unfinished_repositories) { create_list(:container_repository, 2, :cleanup_unfinished) }
it { is_expected.to eq(3) }
it 'logs the work count' do
expect_log_info(
cleanup_scheduled_count: 1,
cleanup_unfinished_count: 2,
cleanup_total_count: 3
)
subject
end
end
context 'with no container repositories waiting for cleanup' do
before do
repository.cleanup_ongoing!
end
it { is_expected.to eq(0) }
it 'logs 0 work count' do
expect_log_info(
cleanup_scheduled_count: 0,
cleanup_unfinished_count: 0,
cleanup_total_count: 0
)
subject
end
end
end
describe '#max_running_jobs' do
let(:capacity) { 50 }
subject { worker.max_running_jobs }
before do
stub_application_setting(container_registry_expiration_policies_worker_capacity: capacity)
end
it { is_expected.to eq(capacity) }
context 'with feature flag disabled' do
before do
stub_feature_flags(container_registry_expiration_policies_throttling: false)
end
it { is_expected.to eq(0) }
end
end
def expect_log_info(structure)
expect(worker.logger)
.to receive(:info).with(worker.structured_payload(structure))
end
end