# frozen_string_literal: true RSpec.describe ::Jobs::Base do class GoodJob < ::Jobs::Base attr_accessor :count def execute(args) self.count ||= 0 self.count += 1 end end class BadJob < ::Jobs::Base class BadJobError < StandardError end attr_accessor :fail_count def execute(args) @fail_count ||= 0 @fail_count += 1 raise BadJobError end end it 'handles correct jobs' do job = GoodJob.new job.perform({}) expect(job.count).to eq(1) end it 'handles errors in multisite' do RailsMultisite::ConnectionManagement.expects(:all_dbs).returns(['default', 'default', 'default']) # one exception per database Discourse.expects(:handle_job_exception).times(3) bad = BadJob.new expect { bad.perform({}) }.to raise_error(Jobs::HandledExceptionWrapper) expect(bad.fail_count).to eq(3) end describe '#perform' do context 'when a job raises an error' do before do Discourse.reset_job_exception_stats! end after do Discourse.reset_job_exception_stats! end it 'collects stats for failing jobs in Discourse.job_exception_stats' do bad = BadJob.new 3.times do # During test env handle_job_exception errors out # in production this is suppressed expect { bad.perform({}) }.to raise_error(BadJob::BadJobError) end expect(Discourse.job_exception_stats).to eq({ BadJob => 3 }) end end end it 'delegates the process call to execute' do ::Jobs::Base.any_instance.expects(:execute).with({ 'hello' => 'world' }) ::Jobs::Base.new.perform('hello' => 'world', 'sync_exec' => true) end it 'converts to an indifferent access hash' do ::Jobs::Base.any_instance.expects(:execute).with(instance_of(HashWithIndifferentAccess)) ::Jobs::Base.new.perform('hello' => 'world', 'sync_exec' => true) end context "with fake jobs" do let(:common_state) { [] } let(:test_job_1) { Class.new(Jobs::Base).tap do |klass| state = common_state klass.define_method(:execute) do |args| state << "job_1_executed" end end } let(:test_job_2) { Class.new(Jobs::Base).tap do |klass| state = common_state job_1 = test_job_1 klass.define_method(:execute) do |args| state << "job_2_started" Jobs.enqueue(job_1) state << "job_2_finished" end end } it "runs jobs synchronously sequentially in tests" do Jobs.run_immediately! Jobs.enqueue(test_job_2) expect(common_state).to eq([ "job_2_started", "job_2_finished", "job_1_executed" ]) end end end