mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
193 lines
5.9 KiB
Ruby
193 lines
5.9 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require 'rails_helper'
|
||
|
|
|
||
|
|
RSpec.describe Imports::DestroyJob, type: :job do
|
||
|
|
describe '#perform' do
|
||
|
|
let(:user) { create(:user) }
|
||
|
|
let(:import) { create(:import, user: user, status: :completed) }
|
||
|
|
|
||
|
|
describe 'queue configuration' do
|
||
|
|
it 'uses the default queue' do
|
||
|
|
expect(described_class.queue_name).to eq('default')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when import exists' do
|
||
|
|
before do
|
||
|
|
create_list(:point, 3, user: user, import: import)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'changes import status to deleting and deletes it' do
|
||
|
|
expect(import).not_to be_deleting
|
||
|
|
|
||
|
|
import_id = import.id
|
||
|
|
described_class.perform_now(import_id)
|
||
|
|
|
||
|
|
expect(Import.find_by(id: import_id)).to be_nil
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'calls the Imports::Destroy service' do
|
||
|
|
destroy_service = instance_double(Imports::Destroy)
|
||
|
|
allow(Imports::Destroy).to receive(:new).with(user, import).and_return(destroy_service)
|
||
|
|
allow(destroy_service).to receive(:call)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
|
||
|
|
expect(Imports::Destroy).to have_received(:new).with(user, import)
|
||
|
|
expect(destroy_service).to have_received(:call)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'broadcasts status update to the user' do
|
||
|
|
allow(ImportsChannel).to receive(:broadcast_to)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
|
||
|
|
expect(ImportsChannel).to have_received(:broadcast_to).with(
|
||
|
|
user,
|
||
|
|
hash_including(
|
||
|
|
action: 'status_update',
|
||
|
|
import: hash_including(
|
||
|
|
id: import.id,
|
||
|
|
status: 'deleting'
|
||
|
|
)
|
||
|
|
)
|
||
|
|
).at_least(:once)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'broadcasts deletion complete to the user' do
|
||
|
|
allow(ImportsChannel).to receive(:broadcast_to)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
|
||
|
|
expect(ImportsChannel).to have_received(:broadcast_to).with(
|
||
|
|
user,
|
||
|
|
hash_including(
|
||
|
|
action: 'delete',
|
||
|
|
import: hash_including(id: import.id)
|
||
|
|
)
|
||
|
|
).at_least(:once)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'broadcasts both status update and deletion messages' do
|
||
|
|
allow(ImportsChannel).to receive(:broadcast_to)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
|
||
|
|
expect(ImportsChannel).to have_received(:broadcast_to).twice
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'deletes the import and its points' do
|
||
|
|
import_id = import.id
|
||
|
|
point_ids = import.points.pluck(:id)
|
||
|
|
|
||
|
|
described_class.perform_now(import_id)
|
||
|
|
|
||
|
|
expect(Import.find_by(id: import_id)).to be_nil
|
||
|
|
expect(Point.where(id: point_ids)).to be_empty
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when import does not exist' do
|
||
|
|
let(:non_existent_id) { 999_999 }
|
||
|
|
|
||
|
|
it 'does not raise an error' do
|
||
|
|
expect { described_class.perform_now(non_existent_id) }.not_to raise_error
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'does not call the Imports::Destroy service' do
|
||
|
|
expect(Imports::Destroy).not_to receive(:new)
|
||
|
|
|
||
|
|
described_class.perform_now(non_existent_id)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'does not broadcast any messages' do
|
||
|
|
expect(ImportsChannel).not_to receive(:broadcast_to)
|
||
|
|
|
||
|
|
described_class.perform_now(non_existent_id)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'returns early without logging' do
|
||
|
|
allow(Rails.logger).to receive(:warn)
|
||
|
|
|
||
|
|
described_class.perform_now(non_existent_id)
|
||
|
|
|
||
|
|
expect(Rails.logger).not_to have_received(:warn)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when import is deleted during job execution' do
|
||
|
|
it 'handles RecordNotFound gracefully' do
|
||
|
|
allow(Import).to receive(:find_by).with(id: import.id).and_return(import)
|
||
|
|
allow(import).to receive(:deleting!).and_raise(ActiveRecord::RecordNotFound)
|
||
|
|
|
||
|
|
expect { described_class.perform_now(import.id) }.not_to raise_error
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'logs a warning when RecordNotFound is raised' do
|
||
|
|
allow(Import).to receive(:find_by).with(id: import.id).and_return(import)
|
||
|
|
allow(import).to receive(:deleting!).and_raise(ActiveRecord::RecordNotFound)
|
||
|
|
allow(Rails.logger).to receive(:warn)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
|
||
|
|
expect(Rails.logger).to have_received(:warn).with(/Import #{import.id} not found/)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when broadcast fails' do
|
||
|
|
before do
|
||
|
|
allow(ImportsChannel).to receive(:broadcast_to).and_raise(StandardError, 'Broadcast error')
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'allows the error to propagate' do
|
||
|
|
expect { described_class.perform_now(import.id) }.to raise_error(StandardError, 'Broadcast error')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when Imports::Destroy service fails' do
|
||
|
|
before do
|
||
|
|
allow_any_instance_of(Imports::Destroy).to receive(:call).and_raise(StandardError, 'Destroy failed')
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'allows the error to propagate' do
|
||
|
|
expect { described_class.perform_now(import.id) }.to raise_error(StandardError, 'Destroy failed')
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'has already set status to deleting before service is called' do
|
||
|
|
expect do
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
rescue StandardError
|
||
|
|
StandardError
|
||
|
|
end.to change { import.reload.status }.to('deleting')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'with multiple imports for different users' do
|
||
|
|
let(:user2) { create(:user) }
|
||
|
|
let(:import2) { create(:import, user: user2, status: :completed) }
|
||
|
|
|
||
|
|
it 'only broadcasts to the correct user' do
|
||
|
|
expect(ImportsChannel).to receive(:broadcast_to).with(user, anything).twice
|
||
|
|
expect(ImportsChannel).not_to receive(:broadcast_to).with(user2, anything)
|
||
|
|
|
||
|
|
described_class.perform_now(import.id)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'job enqueuing' do
|
||
|
|
it 'can be enqueued' do
|
||
|
|
expect do
|
||
|
|
described_class.perform_later(import.id)
|
||
|
|
end.to have_enqueued_job(described_class).with(import.id)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'can be performed later with correct arguments' do
|
||
|
|
expect do
|
||
|
|
described_class.perform_later(import.id)
|
||
|
|
end.to have_enqueued_job(described_class).on_queue('default').with(import.id)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|