1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Reenqueuer, feature_category: :shared do
include ExclusiveLeaseHelpers
let_it_be(:worker_class) do
Class.new do
def self.name
'Gitlab::Foo::Bar::DummyWorker'
end
include ApplicationWorker
prepend Reenqueuer
attr_reader :performed_args
def perform(*args)
@performed_args = args
success? # for stubbing
end
def success?
false
end
def lease_timeout
30.seconds
end
end
end
subject(:job) { worker_class.new }
before do
allow(job).to receive(:sleep) # faster tests
end
it_behaves_like 'reenqueuer'
it_behaves_like '#perform is rate limited to 1 call per', 5.seconds
it 'disables Sidekiq retries' do
expect(job.sidekiq_options_hash).to include('retry' => false)
end
describe '#perform', :clean_gitlab_redis_shared_state do
let(:arbitrary_args) { [:foo, 'bar', { a: 1 }] }
context 'when the lease is available' do
it 'does perform' do
job.perform(*arbitrary_args)
expect(job.performed_args).to eq(arbitrary_args)
end
end
context 'when the lease is taken' do
before do
stub_exclusive_lease_taken(job.lease_key)
end
it 'does not perform' do
job.perform(*arbitrary_args)
expect(job.performed_args).to be_nil
end
end
context 'when #perform returns truthy' do
before do
allow(job).to receive(:success?).and_return(true)
end
it 'reenqueues the worker' do
expect(worker_class).to receive(:perform_async)
job.perform
end
it 'returns the original value from #perform' do
expect(job.perform).to eq(true)
end
end
context 'when #perform returns falsey' do
it 'does not reenqueue the worker' do
expect(worker_class).not_to receive(:perform_async)
job.perform
end
it 'returns the original value from #perform' do
expect(job.perform).to eq(false)
end
end
end
end
RSpec.describe Reenqueuer::ReenqueuerSleeper do
let_it_be(:dummy_class) do
Class.new do
include Reenqueuer::ReenqueuerSleeper
def perform
ensure_minimum_duration(11.seconds) do
# do work
end
end
end
end
subject(:dummy) { dummy_class.new }
# Slightly higher-level test of ensure_minimum_duration since we conveniently
# already have this shared example anyway.
it_behaves_like '#perform is rate limited to 1 call per', 11.seconds
# Unit test ensure_minimum_duration
describe '#ensure_minimum_duration' do
around do |example|
freeze_time { example.run }
end
let(:minimum_duration) { 4.seconds }
context 'when the block completes well before the minimum duration' do
let(:time_left) { 3.seconds }
it 'sleeps until the minimum duration' do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just before the minimum duration' do
let(:time_left) { 1.second }
it 'sleeps until the minimum duration' do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just after the minimum duration' do
let(:time_over) { 1.second }
it 'does not sleep' do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
travel(minimum_duration + time_over)
end
end
end
context 'when the block completes well after the minimum duration' do
let(:time_over) { 10.seconds }
it 'does not sleep' do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
travel(minimum_duration + time_over)
end
end
end
end
end
|