gitlab-org--gitlab-foss/spec/services/ci/delete_objects_service_spec.rb

133 lines
3.8 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::DeleteObjectsService, :aggregate_failure do
let(:service) { described_class.new }
let(:artifact) { create(:ci_job_artifact, :archive) }
let(:data) { [artifact] }
describe '#execute' do
before do
Ci::DeletedObject.bulk_import(data)
# We disable the check because the specs are wrapped in a transaction
allow(service).to receive(:transaction_open?).and_return(false)
end
subject(:execute) { service.execute }
it 'deletes records' do
expect { execute }.to change { Ci::DeletedObject.count }.by(-1)
end
it 'deletes files' do
expect { execute }.to change { artifact.file.exists? }
end
context 'when trying to execute without records' do
let(:data) { [] }
it 'does not change the number of objects' do
expect { execute }.not_to change { Ci::DeletedObject.count }
end
end
context 'when trying to remove the same file multiple times' do
let(:objects) { Ci::DeletedObject.all.to_a }
before do
expect(service).to receive(:load_next_batch).twice.and_return(objects)
end
it 'executes successfully' do
2.times { expect(service.execute).to be_truthy }
end
end
context 'with artifacts both ready and not ready for deletion' do
let(:data) { [] }
let_it_be(:past_ready) { create(:ci_deleted_object, pick_up_at: 2.days.ago) }
let_it_be(:ready) { create(:ci_deleted_object, pick_up_at: 1.day.ago) }
it 'skips records with pick_up_at in the future' do
not_ready = create(:ci_deleted_object, pick_up_at: 1.day.from_now)
expect { execute }.to change { Ci::DeletedObject.count }.from(3).to(1)
expect(not_ready.reload.present?).to be_truthy
end
it 'limits the number of records removed' do
stub_const("#{described_class}::BATCH_SIZE", 1)
expect { execute }.to change { Ci::DeletedObject.count }.by(-1)
end
it 'removes records in order' do
stub_const("#{described_class}::BATCH_SIZE", 1)
execute
expect { past_ready.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect(ready.reload.present?).to be_truthy
end
it 'updates pick_up_at timestamp' do
allow(service).to receive(:destroy_everything)
execute
expect(past_ready.reload.pick_up_at).to be_like_time(10.minutes.from_now)
end
it 'does not delete objects for which file deletion has failed' do
expect(past_ready)
.to receive(:delete_file_from_storage)
.and_return(false)
expect(service)
.to receive(:load_next_batch)
.and_return([past_ready, ready])
expect { execute }.to change { Ci::DeletedObject.count }.from(2).to(1)
expect(past_ready.reload.present?).to be_truthy
end
end
context 'with an open database transaction' do
it 'raises an exception and does not remove records' do
expect(service).to receive(:transaction_open?).and_return(true)
expect { execute }
.to raise_error(Ci::DeleteObjectsService::TransactionInProgressError)
.and change { Ci::DeletedObject.count }.by(0)
end
end
end
describe '#remaining_batches_count' do
subject { service.remaining_batches_count(max_batch_count: 3) }
context 'when there is less than one batch size' do
before do
Ci::DeletedObject.bulk_import(data)
end
it { is_expected.to eq(1) }
end
context 'when there is more than one batch size' do
before do
objects_scope = double
expect(Ci::DeletedObject)
.to receive(:ready_for_destruction)
.and_return(objects_scope)
expect(objects_scope).to receive(:size).and_return(110)
end
it { is_expected.to eq(2) }
end
end
end