gitlab-ce/spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb

206 lines
6.5 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::SidekiqMiddleware::SkipJobs, feature_category: :scalability do
let(:job) { { 'jid' => 123, 'args' => [456] } }
let(:queue) { 'test_queue' }
let(:worker) do
Class.new do
def self.name
'TestWorker'
end
include ApplicationWorker
end
end
subject { described_class.new }
before do
stub_const('TestWorker', worker)
stub_feature_flags("drop_sidekiq_jobs_#{TestWorker.name}": false)
end
describe '#call' do
context 'with worker not opted for database health check' do
let(:metric) { instance_double(Prometheus::Client::Counter, increment: true) }
shared_examples 'runs the job normally' do
it 'yields control' do
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
end
it 'does not increment any metric counter' do
expect(metric).not_to receive(:increment)
subject.call(TestWorker.new, job, queue) { nil }
end
it 'does not increment deferred_count' do
subject.call(TestWorker.new, job, queue) { nil }
expect(job).not_to include('deferred_count')
end
end
shared_examples 'drops the job' do
it 'does not yield control' do
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.not_to yield_control
end
it 'increments counter' do
expect(metric).to receive(:increment).with({ worker: "TestWorker", action: "dropped" })
subject.call(TestWorker.new, job, queue) { nil }
end
it 'does not increment deferred_count' do
subject.call(TestWorker.new, job, queue) { nil }
expect(job).not_to include('deferred_count')
end
it 'has dropped field in job equal to true' do
subject.call(TestWorker.new, job, queue) { nil }
expect(job).to include({ 'dropped' => true })
end
end
shared_examples 'defers the job' do
it 'does not yield control' do
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.not_to yield_control
end
it 'delays the job' do
expect(TestWorker).to receive(:perform_in).with(described_class::DELAY, *job['args'])
subject.call(TestWorker.new, job, queue) { nil }
end
it 'increments counter' do
expect(metric).to receive(:increment).with({ worker: "TestWorker", action: "deferred" })
subject.call(TestWorker.new, job, queue) { nil }
end
it 'has deferred related fields in job payload' do
subject.call(TestWorker.new, job, queue) { nil }
expect(job).to include({ 'deferred' => true, 'deferred_by' => :feature_flag, 'deferred_count' => 1 })
end
end
describe "with all combinations of drop and defer FFs" do
using RSpec::Parameterized::TableSyntax
before do
stub_feature_flags("drop_sidekiq_jobs_#{TestWorker.name}": drop_ff)
stub_feature_flags("run_sidekiq_jobs_#{TestWorker.name}": run_ff)
allow(Gitlab::Metrics).to receive(:counter).and_call_original
allow(Gitlab::Metrics).to receive(:counter).with(described_class::COUNTER, anything).and_return(metric)
end
where(:drop_ff, :run_ff, :resulting_behavior) do
false | true | "runs the job normally"
true | true | "drops the job"
false | false | "defers the job"
true | false | "drops the job"
end
with_them do
it_behaves_like params[:resulting_behavior]
end
end
describe 'using current_request actor', :request_store do
before do
allow(Gitlab::Metrics).to receive(:counter).and_call_original
allow(Gitlab::Metrics).to receive(:counter).with(described_class::COUNTER, anything).and_return(metric)
end
context 'with drop_sidekiq_jobs FF' do
before do
stub_feature_flags("drop_sidekiq_jobs_#{TestWorker.name}": Feature.current_request)
end
it_behaves_like 'drops the job'
context 'for different request' do
before do
stub_with_new_feature_current_request
end
it_behaves_like 'runs the job normally'
end
end
context 'with run_sidekiq_jobs FF' do
before do
stub_feature_flags("run_sidekiq_jobs_#{TestWorker.name}": Feature.current_request)
end
it_behaves_like 'runs the job normally'
context 'for different request' do
before do
stub_with_new_feature_current_request
end
it_behaves_like 'defers the job'
end
end
end
end
context 'with worker opted for database health check' do
let(:health_signal_attrs) { { gitlab_schema: :gitlab_main, tables: [:users], delay: 1.minute } }
around do |example|
with_sidekiq_server_middleware do |chain|
chain.add described_class
Sidekiq::Testing.inline! { example.run }
end
end
before do
TestWorker.defer_on_database_health_signal(*health_signal_attrs.values)
end
context 'without any stop signal from database health check' do
it 'runs the job normally' do
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
end
end
context 'with stop signal from database health check' do
before do
stop_signal = instance_double("Gitlab::Database::HealthStatus::Signals::Stop", stop?: true)
allow(Gitlab::Database::HealthStatus).to receive(:evaluate).and_return([stop_signal])
end
it 'defers the job by set time' do
expect(TestWorker).to receive(:perform_in).with(health_signal_attrs[:delay], *job['args'])
TestWorker.perform_async(*job['args'])
end
end
context 'when a block is provided' do
before do
TestWorker.defer_on_database_health_signal(*health_signal_attrs.values) do
[:gitlab_ci, [:ci_pipelines]]
end
end
it 'uses the lazy evaluated schema and tables returned by the block' do
expect(Gitlab::Database::HealthStatus::Context).to receive(:new)
.with(anything, anything, [:ci_pipelines], :gitlab_ci).and_call_original
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
end
end
end
end
end