2020-03-09 13:42:32 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'fast_spec_helper'
|
|
|
|
require 'rspec-parameterized'
|
|
|
|
|
|
|
|
describe Gitlab::SidekiqConfig::CliMethods do
|
|
|
|
let(:dummy_root) { '/tmp/' }
|
|
|
|
|
|
|
|
describe '.worker_queues' do
|
|
|
|
def expand_path(path)
|
|
|
|
File.join(dummy_root, path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub_exists(exists: true)
|
|
|
|
['app/workers/all_queues.yml', 'ee/app/workers/all_queues.yml'].each do |path|
|
|
|
|
allow(File).to receive(:exist?).with(expand_path(path)).and_return(exists)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub_contents(foss_queues, ee_queues)
|
|
|
|
allow(YAML).to receive(:load_file)
|
|
|
|
.with(expand_path('app/workers/all_queues.yml'))
|
|
|
|
.and_return(foss_queues)
|
|
|
|
|
|
|
|
allow(YAML).to receive(:load_file)
|
|
|
|
.with(expand_path('ee/app/workers/all_queues.yml'))
|
|
|
|
.and_return(ee_queues)
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
described_class.clear_memoization!
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the file exists' do
|
|
|
|
before do
|
|
|
|
stub_exists(exists: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples 'valid file contents' do
|
|
|
|
it 'memoizes the result' do
|
|
|
|
result = described_class.worker_queues(dummy_root)
|
|
|
|
|
|
|
|
stub_exists(exists: false)
|
|
|
|
|
|
|
|
expect(described_class.worker_queues(dummy_root)).to eq(result)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'flattens and joins the contents' do
|
|
|
|
expected_queues = %w[queue_a queue_b]
|
|
|
|
expected_queues = expected_queues.first(1) unless Gitlab.ee?
|
|
|
|
|
|
|
|
expect(described_class.worker_queues(dummy_root))
|
|
|
|
.to match_array(expected_queues)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the file contains an array of strings' do
|
|
|
|
before do
|
|
|
|
stub_contents(['queue_a'], ['queue_b'])
|
|
|
|
end
|
|
|
|
|
|
|
|
include_examples 'valid file contents'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the file contains an array of hashes' do
|
|
|
|
before do
|
|
|
|
stub_contents([{ name: 'queue_a' }], [{ name: 'queue_b' }])
|
|
|
|
end
|
|
|
|
|
|
|
|
include_examples 'valid file contents'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the file does not exist' do
|
|
|
|
before do
|
|
|
|
stub_exists(exists: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns an empty array' do
|
|
|
|
expect(described_class.worker_queues(dummy_root)).to be_empty
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.expand_queues' do
|
|
|
|
let(:worker_queues) do
|
|
|
|
['cronjob:stuck_import_jobs', 'cronjob:stuck_merge_jobs', 'post_receive']
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'defaults the value of the second argument to .worker_queues' do
|
|
|
|
allow(described_class).to receive(:worker_queues).and_return([])
|
|
|
|
|
|
|
|
expect(described_class.expand_queues(['cronjob']))
|
|
|
|
.to contain_exactly('cronjob')
|
|
|
|
|
|
|
|
allow(described_class).to receive(:worker_queues).and_return(worker_queues)
|
|
|
|
|
|
|
|
expect(described_class.expand_queues(['cronjob']))
|
|
|
|
.to contain_exactly('cronjob', 'cronjob:stuck_import_jobs', 'cronjob:stuck_merge_jobs')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expands queue namespaces to concrete queue names' do
|
|
|
|
expect(described_class.expand_queues(['cronjob'], worker_queues))
|
|
|
|
.to contain_exactly('cronjob', 'cronjob:stuck_import_jobs', 'cronjob:stuck_merge_jobs')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'lets concrete queue names pass through' do
|
|
|
|
expect(described_class.expand_queues(['post_receive'], worker_queues))
|
|
|
|
.to contain_exactly('post_receive')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'lets unknown queues pass through' do
|
|
|
|
expect(described_class.expand_queues(['unknown'], worker_queues))
|
|
|
|
.to contain_exactly('unknown')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.query_workers' do
|
|
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
|
|
|
|
let(:queues) do
|
|
|
|
[
|
|
|
|
{
|
|
|
|
name: 'a',
|
|
|
|
feature_category: :category_a,
|
|
|
|
has_external_dependencies: false,
|
2020-04-08 14:13:33 +05:30
|
|
|
urgency: :low,
|
2020-03-09 13:42:32 +05:30
|
|
|
resource_boundary: :cpu
|
|
|
|
},
|
|
|
|
{
|
2020-04-08 14:13:33 +05:30
|
|
|
name: 'a:2',
|
2020-03-09 13:42:32 +05:30
|
|
|
feature_category: :category_a,
|
|
|
|
has_external_dependencies: false,
|
2020-04-08 14:13:33 +05:30
|
|
|
urgency: :high,
|
2020-03-09 13:42:32 +05:30
|
|
|
resource_boundary: :none
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'b',
|
|
|
|
feature_category: :category_b,
|
|
|
|
has_external_dependencies: true,
|
2020-04-08 14:13:33 +05:30
|
|
|
urgency: :high,
|
2020-03-09 13:42:32 +05:30
|
|
|
resource_boundary: :memory
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'c',
|
|
|
|
feature_category: :category_c,
|
|
|
|
has_external_dependencies: false,
|
2020-04-08 14:13:33 +05:30
|
|
|
urgency: :throttled,
|
2020-03-09 13:42:32 +05:30
|
|
|
resource_boundary: :memory
|
|
|
|
}
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with valid input' do
|
|
|
|
where(:query, :selected_queues) do
|
|
|
|
# feature_category
|
2020-04-08 14:13:33 +05:30
|
|
|
'feature_category=category_a' | %w(a a:2)
|
|
|
|
'feature_category=category_a,category_c' | %w(a a:2 c)
|
|
|
|
'feature_category=category_a|feature_category=category_c' | %w(a a:2 c)
|
2020-03-09 13:42:32 +05:30
|
|
|
'feature_category!=category_a' | %w(b c)
|
|
|
|
|
|
|
|
# has_external_dependencies
|
|
|
|
'has_external_dependencies=true' | %w(b)
|
2020-04-08 14:13:33 +05:30
|
|
|
'has_external_dependencies=false' | %w(a a:2 c)
|
|
|
|
'has_external_dependencies=true,false' | %w(a a:2 b c)
|
|
|
|
'has_external_dependencies=true|has_external_dependencies=false' | %w(a a:2 b c)
|
|
|
|
'has_external_dependencies!=true' | %w(a a:2 c)
|
|
|
|
|
|
|
|
# urgency
|
|
|
|
'urgency=high' | %w(a:2 b)
|
|
|
|
'urgency=low' | %w(a)
|
|
|
|
'urgency=high,low,throttled' | %w(a a:2 b c)
|
|
|
|
'urgency=low|urgency=throttled' | %w(a c)
|
|
|
|
'urgency!=high' | %w(a c)
|
2020-03-09 13:42:32 +05:30
|
|
|
|
|
|
|
# name
|
|
|
|
'name=a' | %w(a)
|
|
|
|
'name=a,b' | %w(a b)
|
2020-04-08 14:13:33 +05:30
|
|
|
'name=a,a:2|name=b' | %w(a a:2 b)
|
|
|
|
'name!=a,a:2' | %w(b c)
|
2020-03-09 13:42:32 +05:30
|
|
|
|
|
|
|
# resource_boundary
|
|
|
|
'resource_boundary=memory' | %w(b c)
|
|
|
|
'resource_boundary=memory,cpu' | %w(a b c)
|
|
|
|
'resource_boundary=memory|resource_boundary=cpu' | %w(a b c)
|
2020-04-08 14:13:33 +05:30
|
|
|
'resource_boundary!=memory,cpu' | %w(a:2)
|
2020-03-09 13:42:32 +05:30
|
|
|
|
|
|
|
# combinations
|
2020-04-08 14:13:33 +05:30
|
|
|
'feature_category=category_a&urgency=high' | %w(a:2)
|
|
|
|
'feature_category=category_a&urgency=high|feature_category=category_c' | %w(a:2 c)
|
2020-03-09 13:42:32 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
it do
|
|
|
|
expect(described_class.query_workers(query, queues))
|
|
|
|
.to match_array(selected_queues)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with invalid input' do
|
|
|
|
where(:query, :error) do
|
|
|
|
'feature_category="category_a"' | described_class::InvalidTerm
|
|
|
|
'feature_category=' | described_class::InvalidTerm
|
|
|
|
'feature_category~category_a' | described_class::InvalidTerm
|
|
|
|
'worker_name=a' | described_class::UnknownPredicate
|
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
it do
|
|
|
|
expect { described_class.query_workers(query, queues) }
|
|
|
|
.to raise_error(error)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|