253 lines
7.5 KiB
Ruby
253 lines
7.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe Gitlab::SidekiqMiddleware::SizeLimiter::Validator do
|
|
let(:worker_class) do
|
|
Class.new do
|
|
def self.name
|
|
"TestSizeLimiterWorker"
|
|
end
|
|
|
|
include ApplicationWorker
|
|
|
|
def perform(*args); end
|
|
end
|
|
end
|
|
|
|
before do
|
|
stub_const("TestSizeLimiterWorker", worker_class)
|
|
end
|
|
|
|
describe '#initialize' do
|
|
context 'when the input mode is valid' do
|
|
it 'does not log a warning message' do
|
|
expect(::Sidekiq.logger).not_to receive(:warn)
|
|
|
|
described_class.new(TestSizeLimiterWorker, {}, mode: 'track')
|
|
described_class.new(TestSizeLimiterWorker, {}, mode: 'raise')
|
|
end
|
|
end
|
|
|
|
context 'when the input mode is invalid' do
|
|
it 'defaults to track mode and logs a warning message' do
|
|
expect(::Sidekiq.logger).to receive(:warn).with('Invalid Sidekiq size limiter mode: invalid. Fallback to track mode.')
|
|
|
|
validator = described_class.new(TestSizeLimiterWorker, {}, mode: 'invalid')
|
|
|
|
expect(validator.mode).to eql('track')
|
|
end
|
|
end
|
|
|
|
context 'when the input mode is empty' do
|
|
it 'defaults to track mode' do
|
|
expect(::Sidekiq.logger).not_to receive(:warn)
|
|
|
|
validator = described_class.new(TestSizeLimiterWorker, {})
|
|
|
|
expect(validator.mode).to eql('track')
|
|
end
|
|
end
|
|
|
|
context 'when the size input is valid' do
|
|
it 'does not log a warning message' do
|
|
expect(::Sidekiq.logger).not_to receive(:warn)
|
|
|
|
described_class.new(TestSizeLimiterWorker, {}, size_limit: 300)
|
|
described_class.new(TestSizeLimiterWorker, {}, size_limit: 0)
|
|
end
|
|
end
|
|
|
|
context 'when the size input is invalid' do
|
|
it 'defaults to 0 and logs a warning message' do
|
|
expect(::Sidekiq.logger).to receive(:warn).with('Invalid Sidekiq size limiter limit: -1')
|
|
|
|
described_class.new(TestSizeLimiterWorker, {}, size_limit: -1)
|
|
end
|
|
end
|
|
|
|
context 'when the size input is empty' do
|
|
it 'defaults to 0' do
|
|
expect(::Sidekiq.logger).not_to receive(:warn)
|
|
|
|
validator = described_class.new(TestSizeLimiterWorker, {})
|
|
|
|
expect(validator.size_limit).to be(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'validate limit job payload size' do
|
|
context 'in track mode' do
|
|
let(:mode) { 'track' }
|
|
|
|
context 'when size limit negative' do
|
|
let(:size_limit) { -1 }
|
|
|
|
it 'does not track jobs' do
|
|
expect(Gitlab::ErrorTracking).not_to receive(:track_exception)
|
|
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' * 300 })
|
|
end
|
|
|
|
it 'does not raise exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
context 'when size limit is 0' do
|
|
let(:size_limit) { 0 }
|
|
|
|
it 'does not track jobs' do
|
|
expect(Gitlab::ErrorTracking).not_to receive(:track_exception)
|
|
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' * 300 })
|
|
end
|
|
|
|
it 'does not raise exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
context 'when job size is bigger than size limit' do
|
|
let(:size_limit) { 50 }
|
|
|
|
it 'tracks job' do
|
|
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
|
|
be_a(Gitlab::SidekiqMiddleware::SizeLimiter::ExceedLimitError)
|
|
)
|
|
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' * 100 })
|
|
end
|
|
|
|
it 'does not raise an exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
|
|
context 'when the worker has big_payload attribute' do
|
|
before do
|
|
worker_class.big_payload!
|
|
end
|
|
|
|
it 'does not track jobs' do
|
|
expect(Gitlab::ErrorTracking).not_to receive(:track_exception)
|
|
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' * 300 })
|
|
validate.call('TestSizeLimiterWorker', { a: 'a' * 300 })
|
|
end
|
|
|
|
it 'does not raise an exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
expect { validate.call('TestSizeLimiterWorker', { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when job size is less than size limit' do
|
|
let(:size_limit) { 50 }
|
|
|
|
it 'does not track job' do
|
|
expect(Gitlab::ErrorTracking).not_to receive(:track_exception)
|
|
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' })
|
|
end
|
|
|
|
it 'does not raise an exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' }) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'in raise mode' do
|
|
let(:mode) { 'raise' }
|
|
|
|
context 'when size limit is negative' do
|
|
let(:size_limit) { -1 }
|
|
|
|
it 'does not raise exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
context 'when size limit is 0' do
|
|
let(:size_limit) { 0 }
|
|
|
|
it 'does not raise exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
context 'when job size is bigger than size limit' do
|
|
let(:size_limit) { 50 }
|
|
|
|
it 'raises an exception' do
|
|
expect do
|
|
validate.call(TestSizeLimiterWorker, { a: 'a' * 300 })
|
|
end.to raise_error(
|
|
Gitlab::SidekiqMiddleware::SizeLimiter::ExceedLimitError,
|
|
/TestSizeLimiterWorker job exceeds payload size limit/i
|
|
)
|
|
end
|
|
|
|
context 'when the worker has big_payload attribute' do
|
|
before do
|
|
worker_class.big_payload!
|
|
end
|
|
|
|
it 'does not raise an exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' * 300 }) }.not_to raise_error
|
|
expect { validate.call('TestSizeLimiterWorker', { a: 'a' * 300 }) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when job size is less than size limit' do
|
|
let(:size_limit) { 50 }
|
|
|
|
it 'does not raise an exception' do
|
|
expect { validate.call(TestSizeLimiterWorker, { a: 'a' }) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#validate!' do
|
|
context 'when calling SizeLimiter.validate!' do
|
|
let(:validate) { ->(worker_clas, job) { described_class.validate!(worker_class, job) } }
|
|
|
|
before do
|
|
stub_env('GITLAB_SIDEKIQ_SIZE_LIMITER_MODE', mode)
|
|
stub_env('GITLAB_SIDEKIQ_SIZE_LIMITER_LIMIT_BYTES', size_limit)
|
|
end
|
|
|
|
it_behaves_like 'validate limit job payload size'
|
|
end
|
|
|
|
context 'when creating an instance with the related ENV variables' do
|
|
let(:validate) do
|
|
->(worker_clas, job) do
|
|
validator = described_class.new(worker_class, job, mode: mode, size_limit: size_limit)
|
|
validator.validate!
|
|
end
|
|
end
|
|
|
|
before do
|
|
stub_env('GITLAB_SIDEKIQ_SIZE_LIMITER_MODE', mode)
|
|
stub_env('GITLAB_SIDEKIQ_SIZE_LIMITER_LIMIT_BYTES', size_limit)
|
|
end
|
|
|
|
it_behaves_like 'validate limit job payload size'
|
|
end
|
|
|
|
context 'when creating an instance with mode and size limit' do
|
|
let(:validate) do
|
|
->(worker_clas, job) do
|
|
validator = described_class.new(worker_class, job, mode: mode, size_limit: size_limit)
|
|
validator.validate!
|
|
end
|
|
end
|
|
|
|
it_behaves_like 'validate limit job payload size'
|
|
end
|
|
end
|
|
end
|