2022-11-18 15:26:31 +01:00
|
|
|
describe BatchOperation, type: :model do
|
|
|
|
describe 'association' do
|
|
|
|
it { is_expected.to have_many(:dossiers) }
|
|
|
|
it { is_expected.to belong_to(:instructeur) }
|
2022-12-22 22:23:47 +01:00
|
|
|
it { is_expected.to have_many(:dossier_operations) }
|
2022-11-18 15:26:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
describe 'attributes' do
|
|
|
|
subject { BatchOperation.new }
|
|
|
|
it { expect(subject.payload).to eq({}) }
|
|
|
|
it { expect(subject.run_at).to eq(nil) }
|
|
|
|
it { expect(subject.finished_at).to eq(nil) }
|
|
|
|
it { expect(subject.operation).to eq(nil) }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'validations' do
|
|
|
|
it { is_expected.to validate_presence_of(:operation) }
|
|
|
|
end
|
|
|
|
|
2022-11-25 15:43:00 +01:00
|
|
|
describe '#enqueue_all' do
|
2022-11-18 16:59:46 +01:00
|
|
|
context 'given dossier_ids in instructeur procedures' do
|
|
|
|
subject do
|
|
|
|
create(:batch_operation, :archiver, instructeur: create(:instructeur))
|
|
|
|
end
|
2022-11-18 15:26:31 +01:00
|
|
|
|
2022-11-18 16:59:46 +01:00
|
|
|
it 'enqueues as many BatchOperationProcessOneJob as dossiers_ids' do
|
|
|
|
expect { subject.enqueue_all() }
|
|
|
|
.to have_enqueued_job(BatchOperationProcessOneJob)
|
|
|
|
.with(subject, subject.dossiers.first)
|
|
|
|
.with(subject, subject.dossiers.second)
|
|
|
|
.with(subject, subject.dossiers.third)
|
2022-11-18 15:26:31 +01:00
|
|
|
end
|
2022-11-25 15:43:00 +01:00
|
|
|
|
|
|
|
it 'pass through dossiers_safe_scope' do
|
|
|
|
expect(subject).to receive(:dossiers_safe_scope).and_return(subject.dossiers)
|
|
|
|
subject.enqueue_all
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#track_processed_dossier' do
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
let(:procedure) { create(:simple_procedure, instructeurs: [instructeur]) }
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, archived: true, procedure: procedure) }
|
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :archiver, instructeur: instructeur, dossiers: [dossier]) }
|
|
|
|
|
|
|
|
it 'unlock the dossier' do
|
|
|
|
expect { batch_operation.track_processed_dossier(true, dossier) }
|
|
|
|
.to change { dossier.reload.batch_operation }
|
|
|
|
.from(batch_operation)
|
|
|
|
.to(nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when it succeed' do
|
|
|
|
it 'pushes dossier_job id to batch_operation.success_dossier_ids' do
|
|
|
|
expect { batch_operation.track_processed_dossier(true, dossier) }
|
2022-12-22 22:23:47 +01:00
|
|
|
.to change { batch_operation.dossier_operations.success.pluck(:dossier_id) }
|
2022-11-25 15:43:00 +01:00
|
|
|
.from([])
|
|
|
|
.to([dossier.id])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when it succeed after a failure' do
|
2022-12-22 22:23:47 +01:00
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :archiver, instructeur: instructeur, dossiers: [dossier]) }
|
|
|
|
before do
|
|
|
|
batch_operation.track_processed_dossier(false, dossier)
|
|
|
|
end
|
2022-11-25 15:43:00 +01:00
|
|
|
it 'remove former dossier id from failed_dossier_ids' do
|
|
|
|
expect { batch_operation.track_processed_dossier(true, dossier) }
|
2022-12-22 22:23:47 +01:00
|
|
|
.to change { batch_operation.dossier_operations.error.pluck(:dossier_id) }
|
2022-11-25 15:43:00 +01:00
|
|
|
.from([dossier.id])
|
|
|
|
.to([])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when it fails' do
|
|
|
|
it 'pushes dossier_job id to batch_operation.failed_dossier_ids' do
|
|
|
|
expect { batch_operation.track_processed_dossier(false, dossier) }
|
2022-12-22 22:23:47 +01:00
|
|
|
.to change { batch_operation.dossier_operations.error.pluck(:dossier_id) }
|
2022-11-25 15:43:00 +01:00
|
|
|
.from([])
|
|
|
|
.to([dossier.id])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when it is the first job' do
|
|
|
|
it 'sets run_at at first' do
|
2022-12-02 17:16:29 +01:00
|
|
|
expect { batch_operation.track_processed_dossier(false, dossier) }
|
|
|
|
.to change { batch_operation.reload.run_at }
|
|
|
|
.from(nil)
|
|
|
|
.to(anything)
|
2022-11-25 15:43:00 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when it is the second job (meaning run_at was already set) but not the last' do
|
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :archiver, instructeur: instructeur, dossiers: [dossier], run_at: 2.days.ago) }
|
|
|
|
it 'does not change run_at' do
|
|
|
|
expect { batch_operation.track_processed_dossier(true, dossier) }
|
|
|
|
.not_to change { batch_operation.reload.run_at }
|
|
|
|
end
|
|
|
|
end
|
2023-02-01 14:59:37 +01:00
|
|
|
|
|
|
|
context 'when it is the last job' do
|
|
|
|
it 'sets finished_at' do
|
|
|
|
expect { batch_operation.track_processed_dossier(true, dossier) }
|
|
|
|
.to change { batch_operation.reload.finished_at }
|
|
|
|
.from(nil)
|
|
|
|
.to(anything)
|
|
|
|
end
|
|
|
|
end
|
2022-11-25 15:43:00 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
describe '#dossiers_safe_scope (with archiver)' do
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
let(:procedure) { create(:simple_procedure, instructeurs: [instructeur]) }
|
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :archiver, instructeur: instructeur, dossiers: [dossier]) }
|
|
|
|
|
|
|
|
context 'when dossier is valid' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'find dosssier' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
2022-12-12 10:02:33 +01:00
|
|
|
context 'when dossier is already archived' do
|
2022-11-25 15:43:00 +01:00
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, archived: true, procedure: procedure) }
|
|
|
|
|
2022-12-12 10:02:33 +01:00
|
|
|
it 'skips dossier is already archived' do
|
2022-11-25 15:43:00 +01:00
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is not in state termine' do
|
|
|
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'does not enqueue any job' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is not in instructeur procedures' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, procedure: create(:simple_procedure)) }
|
|
|
|
|
|
|
|
it 'does not enqueues any BatchOperationProcessOneJob' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-12-12 10:02:33 +01:00
|
|
|
describe '#dossiers_safe_scope (with passer_en_instruction)' do
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
let(:procedure) { create(:simple_procedure, instructeurs: [instructeur]) }
|
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :passer_en_instruction, instructeur: instructeur, dossiers: [dossier]) }
|
|
|
|
|
|
|
|
context 'when dossier is valid' do
|
|
|
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'find dosssier' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is already en instruction' do
|
|
|
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual, archived: true, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'skips dossier is already en instruction' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is not in state en construction' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'does not enqueue any job' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-12-15 17:35:50 +01:00
|
|
|
describe '#dossiers_safe_scope (with accepter)' do
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
let(:procedure) { create(:simple_procedure, instructeurs: [instructeur]) }
|
|
|
|
let(:batch_operation) { create(:batch_operation, operation: :accepter, instructeur: instructeur, dossiers: [dossier]) }
|
|
|
|
|
|
|
|
context 'when dossier is valid' do
|
|
|
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'find dosssier' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is already accepte' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, archived: true, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'skips dossier is already en instruction' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when dossier is not in state en instruction' do
|
|
|
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'does not enqueue any job' do
|
|
|
|
expect(batch_operation.dossiers_safe_scope).not_to include(dossier)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-11-25 15:43:00 +01:00
|
|
|
describe '#safe_create!' do
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
let(:procedure) { create(:simple_procedure, instructeurs: [instructeur]) }
|
2022-12-12 10:02:33 +01:00
|
|
|
let(:dossier_2) { create(:dossier, :accepte, procedure: procedure) }
|
2022-12-12 10:30:16 +01:00
|
|
|
subject { BatchOperation.safe_create!(instructeur: instructeur, operation: :archiver, dossier_ids: [dossier.id, dossier_2.id]) }
|
2022-11-25 15:43:00 +01:00
|
|
|
|
|
|
|
context 'success with divergent list of dossier_ids' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, archived: true, procedure: procedure) }
|
|
|
|
|
|
|
|
it 'does not keep archived dossier within batch_operation.dossiers' do
|
|
|
|
expect(subject.dossiers).not_to include(dossier)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'enqueue a BatchOperationEnqueueAllJob' do
|
|
|
|
expect { subject }.to have_enqueued_job(BatchOperationEnqueueAllJob)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with dossier already in a batch batch_operation' do
|
|
|
|
let(:dossier) { create(:dossier, :accepte, :with_individual, batch_operation: create(:batch_operation, :archiver, instructeur: instructeur), procedure: procedure) }
|
|
|
|
|
|
|
|
it 'does not keep dossier in batch_operation' do
|
|
|
|
expect(subject.dossiers).not_to include(dossier)
|
|
|
|
end
|
2022-11-18 15:26:31 +01:00
|
|
|
end
|
|
|
|
end
|
2022-12-05 13:36:38 +01:00
|
|
|
|
|
|
|
describe 'stale' do
|
|
|
|
let(:finished_at) { 6.hours.ago }
|
|
|
|
let(:staled_batch_operation) { create(:batch_operation, operation: :archiver, finished_at: 2.days.ago, updated_at: 2.days.ago) }
|
|
|
|
it 'finds stale jobs' do
|
|
|
|
expect(BatchOperation.stale).to match_array(staled_batch_operation)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'stuck' do
|
|
|
|
let(:stuck_batch_operation) { create(:batch_operation, operation: :archiver, finished_at: nil, updated_at: 2.days.ago) }
|
|
|
|
it 'finds stale jobs' do
|
|
|
|
expect(BatchOperation.stuck).to match_array(stuck_batch_operation)
|
|
|
|
end
|
|
|
|
end
|
2022-11-18 15:26:31 +01:00
|
|
|
end
|