joblin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +1 -0
- data/app/models/joblin/background_task/api_access.rb +148 -0
- data/app/models/joblin/background_task/attachments.rb +47 -0
- data/app/models/joblin/background_task/executor.rb +63 -0
- data/app/models/joblin/background_task/options.rb +75 -0
- data/app/models/joblin/background_task/retention_policy.rb +28 -0
- data/app/models/joblin/background_task.rb +72 -0
- data/app/models/joblin/concerns/job_working_dirs.rb +21 -0
- data/db/migrate/20250903184852_create_background_tasks.rb +12 -0
- data/joblin.gemspec +35 -0
- data/lib/joblin/batching/batch.rb +537 -0
- data/lib/joblin/batching/callback.rb +135 -0
- data/lib/joblin/batching/chain_builder.rb +247 -0
- data/lib/joblin/batching/compat/active_job.rb +108 -0
- data/lib/joblin/batching/compat/sidekiq/web/batches_assets/css/styles.less +182 -0
- data/lib/joblin/batching/compat/sidekiq/web/batches_assets/js/batch_tree.js +108 -0
- data/lib/joblin/batching/compat/sidekiq/web/batches_assets/js/util.js +2 -0
- data/lib/joblin/batching/compat/sidekiq/web/helpers.rb +41 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/_batch_tree.erb +6 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/_batches_table.erb +44 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/_common.erb +13 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/_jobs_table.erb +21 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/_pagination.erb +26 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/batch.erb +81 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/batches.erb +23 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/pool.erb +137 -0
- data/lib/joblin/batching/compat/sidekiq/web/views/pools.erb +47 -0
- data/lib/joblin/batching/compat/sidekiq/web.rb +218 -0
- data/lib/joblin/batching/compat/sidekiq.rb +149 -0
- data/lib/joblin/batching/compat.rb +20 -0
- data/lib/joblin/batching/context_hash.rb +157 -0
- data/lib/joblin/batching/hier_batch_ids.lua +25 -0
- data/lib/joblin/batching/jobs/base_job.rb +7 -0
- data/lib/joblin/batching/jobs/concurrent_batch_job.rb +20 -0
- data/lib/joblin/batching/jobs/managed_batch_job.rb +175 -0
- data/lib/joblin/batching/jobs/serial_batch_job.rb +20 -0
- data/lib/joblin/batching/pool.rb +254 -0
- data/lib/joblin/batching/pool_refill.lua +47 -0
- data/lib/joblin/batching/schedule_callback.lua +14 -0
- data/lib/joblin/batching/status.rb +89 -0
- data/lib/joblin/engine.rb +15 -0
- data/lib/joblin/lazy_access.rb +72 -0
- data/lib/joblin/uniqueness/compat/active_job.rb +75 -0
- data/lib/joblin/uniqueness/compat/sidekiq.rb +135 -0
- data/lib/joblin/uniqueness/compat.rb +20 -0
- data/lib/joblin/uniqueness/configuration.rb +25 -0
- data/lib/joblin/uniqueness/job_uniqueness.rb +49 -0
- data/lib/joblin/uniqueness/lock_context.rb +199 -0
- data/lib/joblin/uniqueness/locksmith.rb +92 -0
- data/lib/joblin/uniqueness/on_conflict/base.rb +32 -0
- data/lib/joblin/uniqueness/on_conflict/log.rb +13 -0
- data/lib/joblin/uniqueness/on_conflict/null_strategy.rb +9 -0
- data/lib/joblin/uniqueness/on_conflict/raise.rb +11 -0
- data/lib/joblin/uniqueness/on_conflict/reject.rb +21 -0
- data/lib/joblin/uniqueness/on_conflict/reschedule.rb +20 -0
- data/lib/joblin/uniqueness/on_conflict.rb +62 -0
- data/lib/joblin/uniqueness/strategy/base.rb +107 -0
- data/lib/joblin/uniqueness/strategy/until_and_while_executing.rb +35 -0
- data/lib/joblin/uniqueness/strategy/until_executed.rb +20 -0
- data/lib/joblin/uniqueness/strategy/until_executing.rb +20 -0
- data/lib/joblin/uniqueness/strategy/until_expired.rb +16 -0
- data/lib/joblin/uniqueness/strategy/while_executing.rb +26 -0
- data/lib/joblin/uniqueness/strategy.rb +27 -0
- data/lib/joblin/uniqueness/unique_job_common.rb +79 -0
- data/lib/joblin/version.rb +3 -0
- data/lib/joblin.rb +37 -0
- data/spec/batching/batch_spec.rb +493 -0
- data/spec/batching/callback_spec.rb +38 -0
- data/spec/batching/compat/active_job_spec.rb +107 -0
- data/spec/batching/compat/sidekiq_spec.rb +127 -0
- data/spec/batching/context_hash_spec.rb +54 -0
- data/spec/batching/flow_spec.rb +82 -0
- data/spec/batching/integration/fail_then_succeed.rb +42 -0
- data/spec/batching/integration/integration.rb +57 -0
- data/spec/batching/integration/nested.rb +88 -0
- data/spec/batching/integration/simple.rb +47 -0
- data/spec/batching/integration/workflow.rb +134 -0
- data/spec/batching/integration_helper.rb +50 -0
- data/spec/batching/pool_spec.rb +161 -0
- data/spec/batching/status_spec.rb +76 -0
- data/spec/batching/support/base_job.rb +19 -0
- data/spec/batching/support/sample_callback.rb +2 -0
- data/spec/internal/config/database.yml +5 -0
- data/spec/internal/config/routes.rb +5 -0
- data/spec/internal/config/storage.yml +3 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +6 -0
- data/spec/internal/log/test.log +48200 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/models/background_task_spec.rb +41 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/uniqueness/compat/active_job_spec.rb +49 -0
- data/spec/uniqueness/compat/sidekiq_spec.rb +68 -0
- data/spec/uniqueness/lock_context_spec.rb +106 -0
- data/spec/uniqueness/on_conflict/log_spec.rb +11 -0
- data/spec/uniqueness/on_conflict/raise_spec.rb +10 -0
- data/spec/uniqueness/on_conflict/reschedule_spec.rb +63 -0
- data/spec/uniqueness/on_conflict_spec.rb +16 -0
- data/spec/uniqueness/spec_helper.rb +19 -0
- data/spec/uniqueness/strategy/base_spec.rb +100 -0
- data/spec/uniqueness/strategy/until_and_while_executing_spec.rb +48 -0
- data/spec/uniqueness/strategy/until_executed_spec.rb +23 -0
- data/spec/uniqueness/strategy/until_executing_spec.rb +23 -0
- data/spec/uniqueness/strategy/until_expired_spec.rb +23 -0
- data/spec/uniqueness/strategy/while_executing_spec.rb +33 -0
- data/spec/uniqueness/support/lock_strategy.rb +28 -0
- data/spec/uniqueness/support/on_conflict.rb +24 -0
- data/spec/uniqueness/support/test_worker.rb +19 -0
- data/spec/uniqueness/unique_job_common_spec.rb +45 -0
- metadata +308 -0
| @@ -0,0 +1,493 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Joblin::Batching::Batch do
         | 
| 4 | 
            +
              describe '#initialize' do
         | 
| 5 | 
            +
                subject { described_class }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                it 'creates bid when called without it' do
         | 
| 8 | 
            +
                  expect(subject.new.bid).not_to be_nil
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                it 'reuses bid when called with it' do
         | 
| 12 | 
            +
                  batch = subject.new('dayPO5KxuRXXxw')
         | 
| 13 | 
            +
                  expect(batch.bid).to eq('dayPO5KxuRXXxw')
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              describe '#description' do
         | 
| 18 | 
            +
                let(:description) { 'custom description' }
         | 
| 19 | 
            +
                before do
         | 
| 20 | 
            +
                  subject.description = description
         | 
| 21 | 
            +
                  subject.jobs { }
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                it 'sets descriptions' do
         | 
| 25 | 
            +
                  expect(subject.description).to eq(description)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it 'persists description' do
         | 
| 29 | 
            +
                  expect(Joblin::Batching::Batch.redis { |r| r.hget("BID-#{subject.bid}", 'description') })
         | 
| 30 | 
            +
                    .to eq(description)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              describe '#callback_queue' do
         | 
| 35 | 
            +
                let(:callback_queue) { 'custom_queue' }
         | 
| 36 | 
            +
                before do
         | 
| 37 | 
            +
                  subject.callback_queue = callback_queue
         | 
| 38 | 
            +
                  subject.jobs { }
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it 'sets callback_queue' do
         | 
| 42 | 
            +
                  expect(subject.callback_queue).to eq(callback_queue)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it 'persists callback_queue' do
         | 
| 46 | 
            +
                  expect(Joblin::Batching::Batch.redis { |r| r.hget("BID-#{subject.bid}", 'callback_queue') })
         | 
| 47 | 
            +
                    .to eq(callback_queue)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              describe '#jobs' do
         | 
| 52 | 
            +
                it 'throws error if no block given' do
         | 
| 53 | 
            +
                  expect { subject.jobs }.to raise_error Joblin::Batching::Batch::NoBlockGivenError
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                it 'increments to_process (when started)'
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                it 'decrements to_process (when finished)'
         | 
| 59 | 
            +
                # it 'calls process_successful_job to wait for block to finish' do
         | 
| 60 | 
            +
                #   batch = Joblin::Batching::Batch.new
         | 
| 61 | 
            +
                #   expect(Joblin::Batching::Batch).to receive(:process_successful_job).with(batch.bid)
         | 
| 62 | 
            +
                #   batch.jobs {}
         | 
| 63 | 
            +
                # end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it 'sets Thread.current bid' do
         | 
| 66 | 
            +
                  batch = Joblin::Batching::Batch.new
         | 
| 67 | 
            +
                  batch.jobs do
         | 
| 68 | 
            +
                    expect(Thread.current[Joblin::Batching::CURRENT_BATCH_THREAD_KEY]).to eq(batch)
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              describe '#invalidate_all' do
         | 
| 74 | 
            +
                class InvalidatableJob < BatchTestJobBase
         | 
| 75 | 
            +
                  def perform
         | 
| 76 | 
            +
                    return unless valid_within_batch?
         | 
| 77 | 
            +
                    was_performed
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def was_performed; end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                it 'marks batch in redis as invalidated' do
         | 
| 84 | 
            +
                  batch = Joblin::Batching::Batch.new
         | 
| 85 | 
            +
                  job = InvalidatableJob.new
         | 
| 86 | 
            +
                  allow(job).to receive(:was_performed)
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  batch.invalidate_all
         | 
| 89 | 
            +
                  batch.jobs { job.perform }
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  expect(job).not_to have_received(:was_performed)
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                context 'nested batches' do
         | 
| 95 | 
            +
                  let(:batch_parent) { Joblin::Batching::Batch.new }
         | 
| 96 | 
            +
                  let(:batch_child_1) { Joblin::Batching::Batch.new }
         | 
| 97 | 
            +
                  let(:batch_child_2) { Joblin::Batching::Batch.new }
         | 
| 98 | 
            +
                  let(:job_of_parent) { InvalidatableJob.new }
         | 
| 99 | 
            +
                  let(:job_of_child_1) { InvalidatableJob.new }
         | 
| 100 | 
            +
                  let(:job_of_child_2) { InvalidatableJob.new }
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  before do
         | 
| 103 | 
            +
                    allow(job_of_parent).to receive(:was_performed)
         | 
| 104 | 
            +
                    allow(job_of_child_1).to receive(:was_performed)
         | 
| 105 | 
            +
                    allow(job_of_child_2).to receive(:was_performed)
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  it 'invalidates all job if parent batch is marked as invalidated' do
         | 
| 109 | 
            +
                    batch_parent.invalidate_all
         | 
| 110 | 
            +
                    batch_parent.jobs do
         | 
| 111 | 
            +
                      [
         | 
| 112 | 
            +
                        job_of_parent.perform,
         | 
| 113 | 
            +
                        batch_child_1.jobs do
         | 
| 114 | 
            +
                          [
         | 
| 115 | 
            +
                            job_of_child_1.perform,
         | 
| 116 | 
            +
                            batch_child_2.jobs { job_of_child_2.perform }
         | 
| 117 | 
            +
                          ]
         | 
| 118 | 
            +
                        end
         | 
| 119 | 
            +
                      ]
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    expect(job_of_parent).not_to have_received(:was_performed)
         | 
| 123 | 
            +
                    expect(job_of_child_1).not_to have_received(:was_performed)
         | 
| 124 | 
            +
                    expect(job_of_child_2).not_to have_received(:was_performed)
         | 
| 125 | 
            +
                  end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                  it 'invalidates only requested batch' do
         | 
| 128 | 
            +
                    batch_child_2.invalidate_all
         | 
| 129 | 
            +
                    batch_parent.jobs do
         | 
| 130 | 
            +
                      [
         | 
| 131 | 
            +
                        job_of_parent.perform,
         | 
| 132 | 
            +
                        batch_child_1.jobs do
         | 
| 133 | 
            +
                          [
         | 
| 134 | 
            +
                            job_of_child_1.perform,
         | 
| 135 | 
            +
                            batch_child_2.jobs { job_of_child_2.perform }
         | 
| 136 | 
            +
                          ]
         | 
| 137 | 
            +
                        end
         | 
| 138 | 
            +
                      ]
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    expect(job_of_parent).to have_received(:was_performed)
         | 
| 142 | 
            +
                    expect(job_of_child_1).to have_received(:was_performed)
         | 
| 143 | 
            +
                    expect(job_of_child_2).not_to have_received(:was_performed)
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              describe '#process_failed_job' do
         | 
| 149 | 
            +
                let(:batch) { Joblin::Batching::Batch.new }
         | 
| 150 | 
            +
                let(:bid) { batch.bid }
         | 
| 151 | 
            +
                let(:jid) { 'ABCD' }
         | 
| 152 | 
            +
                before { Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 1) } }
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                context 'complete' do
         | 
| 155 | 
            +
                  let(:failed_jid) { 'xxx' }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                  it 'tries to call complete callback' do
         | 
| 158 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:complete, bid)
         | 
| 159 | 
            +
                    Joblin::Batching::Batch.process_failed_job(bid, failed_jid)
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                  it 'add job to failed list' do
         | 
| 163 | 
            +
                    Joblin::Batching::Batch.process_failed_job(bid, 'failed-job-id')
         | 
| 164 | 
            +
                    Joblin::Batching::Batch.process_failed_job(bid, failed_jid)
         | 
| 165 | 
            +
                    failed = Joblin::Batching::Batch.redis { |r| r.smembers("BID-#{bid}-failed") }
         | 
| 166 | 
            +
                    expect(failed).to contain_exactly('xxx', 'failed-job-id')
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
              describe '#process_dead_job' do
         | 
| 172 | 
            +
                let(:batch) { Joblin::Batching::Batch.new }
         | 
| 173 | 
            +
                let(:bid) { batch.bid }
         | 
| 174 | 
            +
                let(:jid) { 'ABCD' }
         | 
| 175 | 
            +
                before { Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 1) } }
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                context 'dead' do
         | 
| 178 | 
            +
                  let(:failed_jid) { 'xxx' }
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  it 'tries to call death callback' do
         | 
| 181 | 
            +
                    allow(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:stagnated, bid)
         | 
| 182 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:death, bid)
         | 
| 183 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, failed_jid)
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  it 'add job to failed list' do
         | 
| 187 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, 'failed-job-id')
         | 
| 188 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, failed_jid)
         | 
| 189 | 
            +
                    failed = Joblin::Batching::Batch.redis { |r| r.smembers("BID-#{bid}-dead") }
         | 
| 190 | 
            +
                    expect(failed).to contain_exactly('xxx', 'failed-job-id')
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  it 'automattically triggers the :stagnated callback' do
         | 
| 194 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:stagnated, bid)
         | 
| 195 | 
            +
                    allow(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:death, bid)
         | 
| 196 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, failed_jid)
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  it 'does not trigger :stagnated if pending jobs are still present' do
         | 
| 200 | 
            +
                    Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 2) }
         | 
| 201 | 
            +
                    expect(Joblin::Batching::Batch).to_not receive(:enqueue_callbacks).with(:stagnated, bid)
         | 
| 202 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, failed_jid)
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                  it 'does not trigger :stagnated if pending batches are still present' do
         | 
| 206 | 
            +
                    Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 2) }
         | 
| 207 | 
            +
                    expect(Joblin::Batching::Batch).to_not receive(:enqueue_callbacks).with(:stagnated, bid)
         | 
| 208 | 
            +
                    Joblin::Batching::Batch.process_dead_job(bid, failed_jid)
         | 
| 209 | 
            +
                  end
         | 
| 210 | 
            +
                end
         | 
| 211 | 
            +
              end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
              describe '#process_successful_job' do
         | 
| 214 | 
            +
                let(:batch) { Joblin::Batching::Batch.new }
         | 
| 215 | 
            +
                let(:bid) { batch.bid }
         | 
| 216 | 
            +
                let(:jid) { 'ABCD' }
         | 
| 217 | 
            +
                before { Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 1) } }
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                context 'complete' do
         | 
| 220 | 
            +
                  before { batch.on(:complete, Object) }
         | 
| 221 | 
            +
                  # before { batch.append_jobs(bid) }
         | 
| 222 | 
            +
                  # before { batch.jobs do BatchTestWorker.perform_async end }
         | 
| 223 | 
            +
                  # before { Joblin::Batching::Batch.process_failed_job(bid, 'failed-job-id') }
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                  it 'tries to call complete callback' do
         | 
| 226 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:complete, bid)
         | 
| 227 | 
            +
                    Joblin::Batching::Batch.process_failed_job(bid, 'failed-job-id')
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                context 'success' do
         | 
| 232 | 
            +
                  before { batch.on(:complete, Object) }
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                  it 'tries to call complete callback' do
         | 
| 235 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
         | 
| 236 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:success, bid).ordered
         | 
| 237 | 
            +
                    Joblin::Batching::Batch.process_successful_job(bid, jid)
         | 
| 238 | 
            +
                  end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                  it 'tries to call success callback after a previous failure' do
         | 
| 241 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
         | 
| 242 | 
            +
                    Joblin::Batching::Batch.process_failed_job(bid, jid)
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
         | 
| 245 | 
            +
                    expect(Joblin::Batching::Batch).to receive(:enqueue_callbacks).with(:success, bid).ordered
         | 
| 246 | 
            +
                    Joblin::Batching::Batch.process_successful_job(bid, jid)
         | 
| 247 | 
            +
                  end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                  it 'triggers callbacks as expected' do
         | 
| 250 | 
            +
                    ActiveJob::Base.queue_adapter = :sidekiq
         | 
| 251 | 
            +
                    Joblin::Batching::Batch::Callback.worker_class = Joblin::Batching::Compat::Sidekiq::SidekiqCallbackWorker
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                    callback_instance = double('SampleCallback')
         | 
| 254 | 
            +
                    expect(SampleCallback).to receive(:new).at_least(1).times.and_return(callback_instance)
         | 
| 255 | 
            +
                    expect(callback_instance).to receive(:on_complete)
         | 
| 256 | 
            +
                    expect(callback_instance).to receive(:on_success)
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                    batch.on(:complete, SampleCallback)
         | 
| 259 | 
            +
                    batch.on(:success, SampleCallback)
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                    Sidekiq::Testing.inline! do
         | 
| 262 | 
            +
                      Joblin::Batching::Batch.process_failed_job(bid, jid)
         | 
| 263 | 
            +
                      Joblin::Batching::Batch.process_successful_job(bid, jid)
         | 
| 264 | 
            +
                    end
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                  it 'delays triggering callbacks if keep_open is set' do
         | 
| 268 | 
            +
                    ActiveJob::Base.queue_adapter = :sidekiq
         | 
| 269 | 
            +
                    Joblin::Batching::Batch::Callback.worker_class = Joblin::Batching::Compat::Sidekiq::SidekiqCallbackWorker
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                    callback_instance = double('SampleCallback')
         | 
| 272 | 
            +
                    expect(SampleCallback).to receive(:new).at_least(1).times.and_return(callback_instance)
         | 
| 273 | 
            +
                    expect(callback_instance).not_to receive(:on_complete)
         | 
| 274 | 
            +
                    expect(callback_instance).not_to receive(:on_success)
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                    batch.on(:complete, SampleCallback)
         | 
| 277 | 
            +
                    batch.on(:success, SampleCallback)
         | 
| 278 | 
            +
                    batch.keep_open!
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                    Sidekiq::Testing.inline! do
         | 
| 281 | 
            +
                      Joblin::Batching::Batch.process_failed_job(bid, jid)
         | 
| 282 | 
            +
                      Joblin::Batching::Batch.process_successful_job(bid, jid)
         | 
| 283 | 
            +
                    end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                    RSpec::Mocks.space.proxy_for(callback_instance).reset
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                    expect(callback_instance).to receive(:on_complete)
         | 
| 288 | 
            +
                    expect(callback_instance).to receive(:on_success)
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                    Sidekiq::Testing.inline! do
         | 
| 291 | 
            +
                      batch.let_close!
         | 
| 292 | 
            +
                    end
         | 
| 293 | 
            +
                  end
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                  it 'triggers callbacks as expected' do
         | 
| 296 | 
            +
                    ActiveJob::Base.queue_adapter = :sidekiq
         | 
| 297 | 
            +
                    Joblin::Batching::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 0) }
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                    class RetryingJob < BatchTestJobBase
         | 
| 300 | 
            +
                      @@failed = false
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                      def perform
         | 
| 303 | 
            +
                        unless @@failed
         | 
| 304 | 
            +
                          @@failed = true
         | 
| 305 | 
            +
                          raise "A Failure"
         | 
| 306 | 
            +
                        end
         | 
| 307 | 
            +
                      end
         | 
| 308 | 
            +
                    end
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                    callback_instance = double('SampleCallback')
         | 
| 311 | 
            +
                    expect(SampleCallback).to receive(:new).at_least(1).times.and_return(callback_instance)
         | 
| 312 | 
            +
                    expect(callback_instance).to receive(:on_complete)
         | 
| 313 | 
            +
                    expect(callback_instance).to receive(:on_success)
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                    batch.on(:complete, SampleCallback)
         | 
| 316 | 
            +
                    batch.on(:success, SampleCallback)
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                    batch.jobs do
         | 
| 319 | 
            +
                      RetryingJob.perform_later
         | 
| 320 | 
            +
                    end
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                    job_def = Sidekiq::Worker.jobs[0]
         | 
| 323 | 
            +
                    int_job_class = job_def["class"].constantize
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                    begin
         | 
| 326 | 
            +
                      int_job_class.process_job(job_def)
         | 
| 327 | 
            +
                    rescue
         | 
| 328 | 
            +
                    end
         | 
| 329 | 
            +
                    Sidekiq::Worker.drain_all
         | 
| 330 | 
            +
                  end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                  it 'cleanups redis key' do
         | 
| 333 | 
            +
                    Joblin::Batching::Batch.process_successful_job(bid, jid)
         | 
| 334 | 
            +
                    expect(Joblin::Batching::Batch.redis { |r| r.get("BID-#{bid}-pending") }.to_i).to eq(0)
         | 
| 335 | 
            +
                  end
         | 
| 336 | 
            +
                end
         | 
| 337 | 
            +
              end
         | 
| 338 | 
            +
             | 
| 339 | 
            +
              describe '#append_jobs' do
         | 
| 340 | 
            +
                let(:batch) { Joblin::Batching::Batch.new }
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                it 'increments pending' do
         | 
| 343 | 
            +
                  batch.jobs do BatchTestWorker.perform_async end
         | 
| 344 | 
            +
                  pending = Joblin::Batching::Batch.redis { |r| r.hget("BID-#{batch.bid}", 'pending') }
         | 
| 345 | 
            +
                  expect(pending).to eq('1')
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
              end
         | 
| 348 | 
            +
             | 
| 349 | 
            +
              describe '#enqueue_callbacks' do
         | 
| 350 | 
            +
                let(:callback) { double('callback') }
         | 
| 351 | 
            +
                let(:event) { :complete }
         | 
| 352 | 
            +
             | 
| 353 | 
            +
                context 'on :success' do
         | 
| 354 | 
            +
                  let(:event) { :success }
         | 
| 355 | 
            +
                  context 'when no callbacks are defined' do
         | 
| 356 | 
            +
                    it 'clears redis keys' do
         | 
| 357 | 
            +
                      batch = Joblin::Batching::Batch.new
         | 
| 358 | 
            +
                      batch.jobs {}
         | 
| 359 | 
            +
                      expect(Joblin::Batching::Batch).to receive(:cleanup_redis).with(batch.bid)
         | 
| 360 | 
            +
                      Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 361 | 
            +
                    end
         | 
| 362 | 
            +
                  end
         | 
| 363 | 
            +
                end
         | 
| 364 | 
            +
             | 
| 365 | 
            +
                context 'when already called' do
         | 
| 366 | 
            +
                  it 'returns and does not enqueue callbacks' do
         | 
| 367 | 
            +
                    batch = Joblin::Batching::Batch.new
         | 
| 368 | 
            +
                    batch.on(event, SampleCallback)
         | 
| 369 | 
            +
                    Joblin::Batching::Batch.redis { |r| r.hset("BID-#{batch.bid}", event, "true") }
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                    expect(batch).not_to receive(:push_callbacks)
         | 
| 372 | 
            +
                    Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 373 | 
            +
                  end
         | 
| 374 | 
            +
                end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                context 'With ActiveJob Adapter' do
         | 
| 377 | 
            +
                  around(:all) do |block|
         | 
| 378 | 
            +
                    Joblin::Batching::Batch::Callback.worker_class = Joblin::Batching::Compat::ActiveJob::ActiveJobCallbackWorker
         | 
| 379 | 
            +
                    block.run
         | 
| 380 | 
            +
                  end
         | 
| 381 | 
            +
             | 
| 382 | 
            +
                  context 'when not yet called' do
         | 
| 383 | 
            +
                    context 'when there is no callback' do
         | 
| 384 | 
            +
                      it 'it returns' do
         | 
| 385 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                        expect(batch).not_to receive(:push_callbacks)
         | 
| 388 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 389 | 
            +
                      end
         | 
| 390 | 
            +
                    end
         | 
| 391 | 
            +
             | 
| 392 | 
            +
                    context 'when callback defined' do
         | 
| 393 | 
            +
                      let(:opts) { { 'a' => 'b' } }
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                      it 'calls it passing options' do
         | 
| 396 | 
            +
                        ActiveJob::Base.queue_adapter = :test
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 399 | 
            +
                        batch.on(event, SampleCallback, opts)
         | 
| 400 | 
            +
                        batch.jobs {}
         | 
| 401 | 
            +
             | 
| 402 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 403 | 
            +
             | 
| 404 | 
            +
                        expect(Joblin::Batching::Batch::Callback.worker_class).to have_been_enqueued.with(
         | 
| 405 | 
            +
                          'SampleCallback', event.to_s, opts, batch.bid, nil
         | 
| 406 | 
            +
                        )
         | 
| 407 | 
            +
                      end
         | 
| 408 | 
            +
                    end
         | 
| 409 | 
            +
             | 
| 410 | 
            +
                    context 'when multiple callbacks are defined' do
         | 
| 411 | 
            +
                      let(:opts) { { 'a' => 'b' } }
         | 
| 412 | 
            +
                      let(:opts2) { { 'b' => 'a' } }
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                      it 'enqueues each callback passing their options' do
         | 
| 415 | 
            +
                        ActiveJob::Base.queue_adapter = :test
         | 
| 416 | 
            +
             | 
| 417 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 418 | 
            +
                        batch.on(event, SampleCallback, opts)
         | 
| 419 | 
            +
                        batch.on(event, SampleCallback2, opts2)
         | 
| 420 | 
            +
                        batch.jobs{}
         | 
| 421 | 
            +
             | 
| 422 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 423 | 
            +
                        expect(Joblin::Batching::Batch::Callback.worker_class).to have_been_enqueued.with(
         | 
| 424 | 
            +
                          'SampleCallback2', event.to_s, opts2, batch.bid, nil
         | 
| 425 | 
            +
                        )
         | 
| 426 | 
            +
                        expect(Joblin::Batching::Batch::Callback.worker_class).to have_been_enqueued.with(
         | 
| 427 | 
            +
                          'SampleCallback', event.to_s, opts, batch.bid, nil
         | 
| 428 | 
            +
                        )
         | 
| 429 | 
            +
                      end
         | 
| 430 | 
            +
                    end
         | 
| 431 | 
            +
                  end
         | 
| 432 | 
            +
                end
         | 
| 433 | 
            +
             | 
| 434 | 
            +
                context 'With Sidekiq Adapter' do
         | 
| 435 | 
            +
                  around(:all) do |block|
         | 
| 436 | 
            +
                    Joblin::Batching::Batch::Callback.worker_class = Joblin::Batching::Compat::Sidekiq::SidekiqCallbackWorker
         | 
| 437 | 
            +
                    block.run
         | 
| 438 | 
            +
                  end
         | 
| 439 | 
            +
             | 
| 440 | 
            +
                  context 'when not yet called' do
         | 
| 441 | 
            +
                    context 'when there is no callback' do
         | 
| 442 | 
            +
                      it 'it returns' do
         | 
| 443 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 444 | 
            +
             | 
| 445 | 
            +
                        expect(batch).not_to receive(:push_callbacks)
         | 
| 446 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 447 | 
            +
                      end
         | 
| 448 | 
            +
                    end
         | 
| 449 | 
            +
             | 
| 450 | 
            +
                    context 'when callback defined' do
         | 
| 451 | 
            +
                      let(:opts) { { 'a' => 'b' } }
         | 
| 452 | 
            +
             | 
| 453 | 
            +
                      it 'calls it passing options' do
         | 
| 454 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 455 | 
            +
                        batch.on(event, SampleCallback, opts)
         | 
| 456 | 
            +
                        batch.jobs{}
         | 
| 457 | 
            +
             | 
| 458 | 
            +
                        expect(Sidekiq::Client).to receive(:push_bulk).with(
         | 
| 459 | 
            +
                          'class' => Sidekiq::Batch::Callback.worker_class,
         | 
| 460 | 
            +
                          'args' => [['SampleCallback', event.to_s, opts, batch.bid, nil]],
         | 
| 461 | 
            +
                          'queue' => 'default'
         | 
| 462 | 
            +
                        )
         | 
| 463 | 
            +
             | 
| 464 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 465 | 
            +
                      end
         | 
| 466 | 
            +
                    end
         | 
| 467 | 
            +
             | 
| 468 | 
            +
                    context 'when multiple callbacks are defined' do
         | 
| 469 | 
            +
                      let(:opts) { { 'a' => 'b' } }
         | 
| 470 | 
            +
                      let(:opts2) { { 'b' => 'a' } }
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                      it 'enqueues each callback passing their options' do
         | 
| 473 | 
            +
                        batch = Joblin::Batching::Batch.new
         | 
| 474 | 
            +
                        batch.on(event, SampleCallback, opts)
         | 
| 475 | 
            +
                        batch.on(event, SampleCallback2, opts2)
         | 
| 476 | 
            +
                        batch.jobs{}
         | 
| 477 | 
            +
             | 
| 478 | 
            +
                        expect(Sidekiq::Client).to receive(:push_bulk).with(
         | 
| 479 | 
            +
                          'class' => Sidekiq::Batch::Callback.worker_class,
         | 
| 480 | 
            +
                          'args' => array_including(
         | 
| 481 | 
            +
                            ['SampleCallback', event.to_s, opts, batch.bid, nil],
         | 
| 482 | 
            +
                            ['SampleCallback2', event.to_s, opts2, batch.bid, nil],
         | 
| 483 | 
            +
                          ),
         | 
| 484 | 
            +
                          'queue' => 'default'
         | 
| 485 | 
            +
                        )
         | 
| 486 | 
            +
             | 
| 487 | 
            +
                        Joblin::Batching::Batch.enqueue_callbacks(event, batch.bid)
         | 
| 488 | 
            +
                      end
         | 
| 489 | 
            +
                    end
         | 
| 490 | 
            +
                  end
         | 
| 491 | 
            +
                end
         | 
| 492 | 
            +
              end
         | 
| 493 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Joblin::Batching::Batch::Callback.worker_class do
         | 
| 4 | 
            +
              describe '#perform' do
         | 
| 5 | 
            +
                it 'does not do anything if it cannot find the callback class' do
         | 
| 6 | 
            +
                  subject.perform('SampleCallback', 'complete', {}, 'ABCD', 'EFGH')
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                it 'does not do anything if event is different from complete or success' do
         | 
| 10 | 
            +
                  expect(SampleCallback).not_to receive(:new)
         | 
| 11 | 
            +
                  subject.perform('SampleCallback', 'ups', {}, 'ABCD', 'EFGH')
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                it 'calls on_success if defined' do
         | 
| 15 | 
            +
                  callback_instance = double('SampleCallback', on_success: true)
         | 
| 16 | 
            +
                  expect(SampleCallback).to receive(:new).and_return(callback_instance)
         | 
| 17 | 
            +
                  expect(callback_instance).to receive(:on_success)
         | 
| 18 | 
            +
                    .with(instance_of(Joblin::Batching::Batch::Status), {})
         | 
| 19 | 
            +
                  subject.perform('SampleCallback', 'success', {}, 'ABCD', 'EFGH')
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it 'calls on_complete if defined' do
         | 
| 23 | 
            +
                  callback_instance = double('SampleCallback')
         | 
| 24 | 
            +
                  expect(SampleCallback).to receive(:new).and_return(callback_instance)
         | 
| 25 | 
            +
                  expect(callback_instance).to receive(:on_complete)
         | 
| 26 | 
            +
                    .with(instance_of(Joblin::Batching::Batch::Status), {})
         | 
| 27 | 
            +
                  subject.perform('SampleCallback', 'complete', {}, 'ABCD', 'EFGH')
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                it 'calls specific callback if defined' do
         | 
| 31 | 
            +
                  callback_instance = double('SampleCallback')
         | 
| 32 | 
            +
                  expect(SampleCallback).to receive(:new).and_return(callback_instance)
         | 
| 33 | 
            +
                  expect(callback_instance).to receive(:sample_method)
         | 
| 34 | 
            +
                    .with(instance_of(Joblin::Batching::Batch::Status), {})
         | 
| 35 | 
            +
                  subject.perform('SampleCallback#sample_method', 'complete', {}, 'ABCD', 'EFGH')
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,107 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Joblin::Batching::Compat::ActiveJob do
         | 
| 4 | 
            +
              describe Joblin::Batching::Compat::ActiveJob::BatchAwareJob do
         | 
| 5 | 
            +
                include ActiveJob::TestHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                after do
         | 
| 8 | 
            +
                  clear_enqueued_jobs
         | 
| 9 | 
            +
                  clear_performed_jobs
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                context "When Performing" do
         | 
| 13 | 
            +
                  context 'when without batch' do
         | 
| 14 | 
            +
                    it 'just yields' do
         | 
| 15 | 
            +
                      expect(Joblin::Batching::Batch).not_to receive(:process_successful_job)
         | 
| 16 | 
            +
                      expect(Joblin::Batching::Batch).not_to receive(:process_failed_job)
         | 
| 17 | 
            +
                      expect_any_instance_of(BatchTestJobBase).to receive(:perform)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      BatchTestJobBase.perform_now
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  context 'when in batch' do
         | 
| 24 | 
            +
                    let(:bid) { 'SAMPLEBID' }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    context 'when successful' do
         | 
| 27 | 
            +
                      it 'yields' do
         | 
| 28 | 
            +
                        expect_any_instance_of(BatchTestJobBase).to receive(:perform)
         | 
| 29 | 
            +
                        BatchTestJobBase.perform_now
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      it 'calls process_successful_job' do
         | 
| 33 | 
            +
                        job = BatchTestJobBase.new
         | 
| 34 | 
            +
                        job.instance_variable_set(:@bid, bid)
         | 
| 35 | 
            +
                        expect(Joblin::Batching::Batch).to receive(:process_successful_job).with(bid, job.job_id)
         | 
| 36 | 
            +
                        job.perform_now
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    context 'when failed' do
         | 
| 41 | 
            +
                      it 'calls process_failed_job and reraises exception' do
         | 
| 42 | 
            +
                        reraised = false
         | 
| 43 | 
            +
                        job = FailingBatchTestJobBase.new
         | 
| 44 | 
            +
                        job.instance_variable_set(:@bid, bid)
         | 
| 45 | 
            +
                        expect(Joblin::Batching::Batch).to receive(:process_failed_job)
         | 
| 46 | 
            +
                        begin
         | 
| 47 | 
            +
                          job.perform_now
         | 
| 48 | 
            +
                        rescue
         | 
| 49 | 
            +
                          reraised = true
         | 
| 50 | 
            +
                        end
         | 
| 51 | 
            +
                        expect(reraised).to be_truthy
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                context "When Enqueueing" do
         | 
| 58 | 
            +
                  context 'when without batch' do
         | 
| 59 | 
            +
                    it 'just yields' do
         | 
| 60 | 
            +
                      expect(Joblin::Batching::Batch).not_to receive(:append_jobs)
         | 
| 61 | 
            +
                      BatchTestJobBase.perform_later
         | 
| 62 | 
            +
                      expect(BatchTestJobBase).to have_been_enqueued
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  context 'when in batch' do
         | 
| 67 | 
            +
                    let(:bid) { 'SAMPLEBID' }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    before do
         | 
| 70 | 
            +
                      Thread.current[Joblin::Batching::CURRENT_BATCH_THREAD_KEY] = Joblin::Batching::Batch.new(bid)
         | 
| 71 | 
            +
                      Thread.current[Joblin::Batching::CURRENT_BATCH_THREAD_KEY].instance_variable_set(:@open, true)
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                    after { Thread.current[Joblin::Batching::CURRENT_BATCH_THREAD_KEY] = nil }
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    it 'yields' do
         | 
| 76 | 
            +
                      expect {
         | 
| 77 | 
            +
                        BatchTestJobBase.perform_later
         | 
| 78 | 
            +
                      }.to enqueue_job(BatchTestJobBase)
         | 
| 79 | 
            +
                    end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                    it 'assigns bid to job metadata' do
         | 
| 82 | 
            +
                      job = BatchTestJobBase.perform_later
         | 
| 83 | 
            +
                      expect(job.bid).to eq bid
         | 
| 84 | 
            +
                      expect(job.serialize['batch_id']).to eq bid
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                context 'worker' do
         | 
| 90 | 
            +
                  it 'defines method bid' do
         | 
| 91 | 
            +
                    expect(ActiveJob::Base.instance_methods).to include(:bid)
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  it 'defines method batch' do
         | 
| 95 | 
            +
                    expect(ActiveJob::Base.instance_methods).to include(:batch)
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  it 'defines method valid_within_batch?' do
         | 
| 99 | 
            +
                    expect(ActiveJob::Base.instance_methods).to include(:valid_within_batch?)
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
              describe ".handle_job_death" do
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
            end
         |