summaryrefslogtreecommitdiff
path: root/spec/models/ci/runner_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/ci/runner_spec.rb')
-rw-r--r--spec/models/ci/runner_spec.rb177
1 files changed, 155 insertions, 22 deletions
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index ffe0b0d0b19..61f80bd43b1 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -75,6 +75,22 @@ RSpec.describe Ci::Runner do
expect { create(:group, runners: [project_runner]) }
.to raise_error(ActiveRecord::RecordInvalid)
end
+
+ context 'when runner has config' do
+ it 'is valid' do
+ runner = build(:ci_runner, config: { gpus: "all" })
+
+ expect(runner).to be_valid
+ end
+ end
+
+ context 'when runner has an invalid config' do
+ it 'is invalid' do
+ runner = build(:ci_runner, config: { test: 1 })
+
+ expect(runner).not_to be_valid
+ end
+ end
end
context 'cost factors validations' do
@@ -257,6 +273,20 @@ RSpec.describe Ci::Runner do
end
end
+ describe '.recent' do
+ subject { described_class.recent }
+
+ before do
+ @runner1 = create(:ci_runner, :instance, contacted_at: nil, created_at: 2.months.ago)
+ @runner2 = create(:ci_runner, :instance, contacted_at: nil, created_at: 3.months.ago)
+ @runner3 = create(:ci_runner, :instance, contacted_at: 1.month.ago, created_at: 2.months.ago)
+ @runner4 = create(:ci_runner, :instance, contacted_at: 1.month.ago, created_at: 3.months.ago)
+ @runner5 = create(:ci_runner, :instance, contacted_at: 3.months.ago, created_at: 5.months.ago)
+ end
+
+ it { is_expected.to eq([@runner1, @runner3, @runner4])}
+ end
+
describe '.online' do
subject { described_class.online }
@@ -349,6 +379,22 @@ RSpec.describe Ci::Runner do
it { is_expected.to eq([@runner1])}
end
+ describe '#tick_runner_queue' do
+ it 'sticks the runner to the primary and calls the original method' do
+ runner = create(:ci_runner)
+
+ allow(Gitlab::Database::LoadBalancing).to receive(:enable?)
+ .and_return(true)
+
+ expect(Gitlab::Database::LoadBalancing::Sticking).to receive(:stick)
+ .with(:runner, runner.id)
+
+ expect(Gitlab::Workhorse).to receive(:set_key_and_notify)
+
+ runner.tick_runner_queue
+ end
+ end
+
describe '#can_pick?' do
using RSpec::Parameterized::TableSyntax
@@ -653,7 +699,7 @@ RSpec.describe Ci::Runner do
describe '#heartbeat' do
let(:runner) { create(:ci_runner, :project) }
- subject { runner.heartbeat(architecture: '18-bit') }
+ subject { runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }) }
context 'when database was updated recently' do
before do
@@ -701,6 +747,7 @@ RSpec.describe Ci::Runner do
def does_db_update
expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
.and change { runner.reload.read_attribute(:architecture) }
+ .and change { runner.reload.read_attribute(:config) }
end
end
@@ -826,12 +873,12 @@ RSpec.describe Ci::Runner do
expect(described_class.search(runner.token)).to eq([runner])
end
- it 'returns runners with a partially matching token' do
- expect(described_class.search(runner.token[0..2])).to eq([runner])
+ it 'does not return runners with a partially matching token' do
+ expect(described_class.search(runner.token[0..2])).to be_empty
end
- it 'returns runners with a matching token regardless of the casing' do
- expect(described_class.search(runner.token.upcase)).to eq([runner])
+ it 'does not return runners with a matching token with different casing' do
+ expect(described_class.search(runner.token.upcase)).to be_empty
end
it 'returns runners with a matching description' do
@@ -919,29 +966,13 @@ RSpec.describe Ci::Runner do
end
end
- context 'build picking improvement enabled' do
- before do
- stub_feature_flags(ci_reduce_queries_when_ticking_runner_queue: true)
- end
-
+ context 'build picking improvement' do
it 'does not check if the build is assignable to a runner' do
expect(runner).not_to receive(:can_pick?)
runner.pick_build!(build)
end
end
-
- context 'build picking improvement disabled' do
- before do
- stub_feature_flags(ci_reduce_queries_when_ticking_runner_queue: false)
- end
-
- it 'checks if the build is assignable to a runner' do
- expect(runner).to receive(:can_pick?).and_call_original
-
- runner.pick_build!(build)
- end
- end
end
describe 'project runner without projects is destroyable' do
@@ -975,6 +1006,108 @@ RSpec.describe Ci::Runner do
end
end
+ describe '.runner_matchers' do
+ subject(:matchers) { described_class.all.runner_matchers }
+
+ context 'deduplicates on runner_type' do
+ before do
+ create_list(:ci_runner, 2, :instance)
+ create_list(:ci_runner, 2, :project)
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:runner_type)).to match_array(%w[instance_type project_type])
+ end
+ end
+
+ context 'deduplicates on public_projects_minutes_cost_factor' do
+ before do
+ create_list(:ci_runner, 2, public_projects_minutes_cost_factor: 5)
+ create_list(:ci_runner, 2, public_projects_minutes_cost_factor: 10)
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:public_projects_minutes_cost_factor)).to match_array([5, 10])
+ end
+ end
+
+ context 'deduplicates on private_projects_minutes_cost_factor' do
+ before do
+ create_list(:ci_runner, 2, private_projects_minutes_cost_factor: 5)
+ create_list(:ci_runner, 2, private_projects_minutes_cost_factor: 10)
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:private_projects_minutes_cost_factor)).to match_array([5, 10])
+ end
+ end
+
+ context 'deduplicates on run_untagged' do
+ before do
+ create_list(:ci_runner, 2, run_untagged: true, tag_list: ['a'])
+ create_list(:ci_runner, 2, run_untagged: false, tag_list: ['a'])
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:run_untagged)).to match_array([true, false])
+ end
+ end
+
+ context 'deduplicates on access_level' do
+ before do
+ create_list(:ci_runner, 2, access_level: :ref_protected)
+ create_list(:ci_runner, 2, access_level: :not_protected)
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:access_level)).to match_array(%w[ref_protected not_protected])
+ end
+ end
+
+ context 'deduplicates on tag_list' do
+ before do
+ create_list(:ci_runner, 2, tag_list: %w[tag1 tag2])
+ create_list(:ci_runner, 2, tag_list: %w[tag3 tag4])
+ end
+
+ it 'creates two matchers' do
+ expect(matchers.size).to eq(2)
+
+ expect(matchers.map(&:tag_list)).to match_array([%w[tag1 tag2], %w[tag3 tag4]])
+ end
+ end
+ end
+
+ describe '#runner_matcher' do
+ let(:runner) do
+ build_stubbed(:ci_runner, :instance_type, tag_list: %w[tag1 tag2])
+ end
+
+ subject(:matcher) { runner.runner_matcher }
+
+ it { expect(matcher.runner_type).to eq(runner.runner_type) }
+
+ it { expect(matcher.public_projects_minutes_cost_factor).to eq(runner.public_projects_minutes_cost_factor) }
+
+ it { expect(matcher.private_projects_minutes_cost_factor).to eq(runner.private_projects_minutes_cost_factor) }
+
+ it { expect(matcher.run_untagged).to eq(runner.run_untagged) }
+
+ it { expect(matcher.access_level).to eq(runner.access_level) }
+
+ it { expect(matcher.tag_list).to match_array(runner.tag_list) }
+ end
+
describe '#uncached_contacted_at' do
let(:contacted_at_stored) { 1.hour.ago.change(usec: 0) }
let(:runner) { create(:ci_runner, contacted_at: contacted_at_stored) }