diff options
Diffstat (limited to 'spec/finders/ci/runners_finder_spec.rb')
-rw-r--r-- | spec/finders/ci/runners_finder_spec.rb | 447 |
1 files changed, 308 insertions, 139 deletions
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb index 18eecd0f073..a8ef99eeaec 100644 --- a/spec/finders/ci/runners_finder_spec.rb +++ b/spec/finders/ci/runners_finder_spec.rb @@ -7,219 +7,221 @@ RSpec.describe Ci::RunnersFinder do let_it_be(:admin) { create(:user, :admin) } describe '#execute' do - context 'with 2 runners' do - let_it_be(:runner1) { create(:ci_runner, active: true) } - let_it_be(:runner2) { create(:ci_runner, active: false) } - - context 'with empty params' do - it 'returns all runners' do - expect(Ci::Runner).to receive(:with_tags).and_call_original - expect(described_class.new(current_user: admin, params: {}).execute).to match_array [runner1, runner2] + shared_examples 'executes as admin' do + context 'with 2 runners' do + let_it_be(:runner1) { create(:ci_runner, active: true) } + let_it_be(:runner2) { create(:ci_runner, active: false) } + + context 'with empty params' do + it 'returns all runners' do + expect(Ci::Runner).to receive(:with_tags).and_call_original + expect(described_class.new(current_user: admin, params: {}).execute).to match_array [runner1, runner2] + end end - end - context 'with nil group' do - it 'returns all runners' do - expect(Ci::Runner).to receive(:with_tags).and_call_original - expect(described_class.new(current_user: admin, params: { group: nil }).execute).to match_array [runner1, runner2] + context 'with nil group' do + it 'returns all runners' do + expect(Ci::Runner).to receive(:with_tags).and_call_original + expect(described_class.new(current_user: admin, params: { group: nil }).execute).to match_array [runner1, runner2] + end end - end - context 'with preload param set to :tag_name true' do - it 'requests tags' do - expect(Ci::Runner).to receive(:with_tags).and_call_original - expect(described_class.new(current_user: admin, params: { preload: { tag_name: true } }).execute).to match_array [runner1, runner2] + context 'with preload param set to :tag_name true' do + it 'requests tags' do + expect(Ci::Runner).to receive(:with_tags).and_call_original + expect(described_class.new(current_user: admin, params: { preload: { tag_name: true } }).execute).to match_array [runner1, runner2] + end end - end - context 'with preload param set to :tag_name false' do - it 'does not request tags' do - expect(Ci::Runner).not_to receive(:with_tags) - expect(described_class.new(current_user: admin, params: { preload: { tag_name: false } }).execute).to match_array [runner1, runner2] + context 'with preload param set to :tag_name false' do + it 'does not request tags' do + expect(Ci::Runner).not_to receive(:with_tags) + expect(described_class.new(current_user: admin, params: { preload: { tag_name: false } }).execute).to match_array [runner1, runner2] + end end end - end - context 'filtering' do - context 'by search term' do - it 'calls Ci::Runner.search' do - expect(Ci::Runner).to receive(:search).with('term').and_call_original + context 'filtering' do + context 'by search term' do + it 'calls Ci::Runner.search' do + expect(Ci::Runner).to receive(:search).with('term').and_call_original - described_class.new(current_user: admin, params: { search: 'term' }).execute + described_class.new(current_user: admin, params: { search: 'term' }).execute + end end - end - context 'by upgrade status' do - let(:upgrade_status) {} + context 'by upgrade status' do + let(:upgrade_status) {} - let_it_be(:runner1) { create(:ci_runner, version: 'a') } - let_it_be(:runner2) { create(:ci_runner, version: 'b') } - let_it_be(:runner3) { create(:ci_runner, version: 'c') } - let_it_be(:runner_version_recommended) do - create(:ci_runner_version, version: 'a', status: :recommended) - end + let_it_be(:runner1) { create(:ci_runner, version: 'a') } + let_it_be(:runner2) { create(:ci_runner, version: 'b') } + let_it_be(:runner3) { create(:ci_runner, version: 'c') } + let_it_be(:runner_version_recommended) do + create(:ci_runner_version, version: 'a', status: :recommended) + end - let_it_be(:runner_version_not_available) do - create(:ci_runner_version, version: 'b', status: :not_available) - end + let_it_be(:runner_version_not_available) do + create(:ci_runner_version, version: 'b', status: :not_available) + end - let_it_be(:runner_version_available) do - create(:ci_runner_version, version: 'c', status: :available) - end + let_it_be(:runner_version_available) do + create(:ci_runner_version, version: 'c', status: :available) + end - def execute - described_class.new(current_user: admin, params: { upgrade_status: upgrade_status }).execute - end + def execute + described_class.new(current_user: admin, params: { upgrade_status: upgrade_status }).execute + end - Ci::RunnerVersion.statuses.keys.map(&:to_sym).each do |status| - context "set to :#{status}" do - let(:upgrade_status) { status } + Ci::RunnerVersion.statuses.keys.map(&:to_sym).each do |status| + context "set to :#{status}" do + let(:upgrade_status) { status } - it "calls with_upgrade_status scope with corresponding :#{status} status" do - if [:available, :not_available, :recommended].include?(status) - expected_result = Ci::Runner.with_upgrade_status(status) - end + it "calls with_upgrade_status scope with corresponding :#{status} status" do + if [:available, :not_available, :recommended].include?(status) + expected_result = Ci::Runner.with_upgrade_status(status) + end - expect(Ci::Runner).to receive(:with_upgrade_status).with(status).and_call_original + expect(Ci::Runner).to receive(:with_upgrade_status).with(status).and_call_original - result = execute + result = execute - expect(result).to match_array(expected_result) if expected_result + expect(result).to match_array(expected_result) if expected_result + end end end - end - context 'set to an invalid value' do - let(:upgrade_status) { :some_invalid_status } + context 'set to an invalid value' do + let(:upgrade_status) { :some_invalid_status } - it 'raises ArgumentError' do - expect { execute }.to raise_error(ArgumentError) + it 'raises ArgumentError' do + expect { execute }.to raise_error(ArgumentError) + end end - end - context 'set to nil' do - let(:upgrade_status) { nil } + context 'set to nil' do + let(:upgrade_status) { nil } - it 'does not call with_upgrade_status' do - expect(Ci::Runner).not_to receive(:with_upgrade_status) + it 'does not call with_upgrade_status' do + expect(Ci::Runner).not_to receive(:with_upgrade_status) - expect(execute).to match_array(Ci::Runner.all) + expect(execute).to match_array(Ci::Runner.all) + end end end - end - context 'by status' do - Ci::Runner::AVAILABLE_STATUSES.each do |status| - it "calls the corresponding :#{status} scope on Ci::Runner" do - expect(Ci::Runner).to receive(status.to_sym).and_call_original + context 'by status' do + Ci::Runner::AVAILABLE_STATUSES.each do |status| + it "calls the corresponding :#{status} scope on Ci::Runner" do + expect(Ci::Runner).to receive(status.to_sym).and_call_original - described_class.new(current_user: admin, params: { status_status: status }).execute + described_class.new(current_user: admin, params: { status_status: status }).execute + end end end - end - context 'by active status' do - it 'with active set as false calls the corresponding scope on Ci::Runner with false' do - expect(Ci::Runner).to receive(:active).with(false).and_call_original + context 'by active status' do + it 'with active set as false calls the corresponding scope on Ci::Runner with false' do + expect(Ci::Runner).to receive(:active).with(false).and_call_original - described_class.new(current_user: admin, params: { active: false }).execute - end + described_class.new(current_user: admin, params: { active: false }).execute + end - it 'with active set as true calls the corresponding scope on Ci::Runner with true' do - expect(Ci::Runner).to receive(:active).with(true).and_call_original + it 'with active set as true calls the corresponding scope on Ci::Runner with true' do + expect(Ci::Runner).to receive(:active).with(true).and_call_original - described_class.new(current_user: admin, params: { active: true }).execute + described_class.new(current_user: admin, params: { active: true }).execute + end end - end - context 'by runner type' do - it 'calls the corresponding scope on Ci::Runner' do - expect(Ci::Runner).to receive(:project_type).and_call_original + context 'by runner type' do + it 'calls the corresponding scope on Ci::Runner' do + expect(Ci::Runner).to receive(:project_type).and_call_original - described_class.new(current_user: admin, params: { type_type: 'project_type' }).execute + described_class.new(current_user: admin, params: { type_type: 'project_type' }).execute + end end - end - context 'by tag_name' do - it 'calls the corresponding scope on Ci::Runner' do - expect(Ci::Runner).to receive(:tagged_with).with(%w[tag1 tag2]).and_call_original + context 'by tag_name' do + it 'calls the corresponding scope on Ci::Runner' do + expect(Ci::Runner).to receive(:tagged_with).with(%w[tag1 tag2]).and_call_original - described_class.new(current_user: admin, params: { tag_name: %w[tag1 tag2] }).execute + described_class.new(current_user: admin, params: { tag_name: %w[tag1 tag2] }).execute + end end end - end - context 'sorting' do - let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago, token_expires_at: '2022-02-15 07:00' } - let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago, token_expires_at: '2022-02-15 06:00' } - let_it_be(:runner3) { create :ci_runner, created_at: '2018-07-12 09:00', contacted_at: 2.minutes.ago } + context 'sorting' do + let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago, token_expires_at: '2022-02-15 07:00' } + let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago, token_expires_at: '2022-02-15 06:00' } + let_it_be(:runner3) { create :ci_runner, created_at: '2018-07-12 09:00', contacted_at: 2.minutes.ago } - subject do - described_class.new(current_user: admin, params: params).execute - end + subject do + described_class.new(current_user: admin, params: params).execute + end - shared_examples 'sorts by created_at descending' do - it 'sorts by created_at descending' do - is_expected.to eq [runner3, runner2, runner1] + shared_examples 'sorts by created_at descending' do + it 'sorts by created_at descending' do + is_expected.to eq [runner3, runner2, runner1] + end end - end - context 'without sort param' do - let(:params) { {} } + context 'without sort param' do + let(:params) { {} } - it_behaves_like 'sorts by created_at descending' - end + it_behaves_like 'sorts by created_at descending' + end - %w(created_date created_at_desc).each do |sort| - context "with sort param equal to #{sort}" do - let(:params) { { sort: sort } } + %w(created_date created_at_desc).each do |sort| + context "with sort param equal to #{sort}" do + let(:params) { { sort: sort } } - it_behaves_like 'sorts by created_at descending' + it_behaves_like 'sorts by created_at descending' + end end - end - context 'with sort param equal to created_at_asc' do - let(:params) { { sort: 'created_at_asc' } } + context 'with sort param equal to created_at_asc' do + let(:params) { { sort: 'created_at_asc' } } - it 'sorts by created_at ascending' do - is_expected.to eq [runner1, runner2, runner3] + it 'sorts by created_at ascending' do + is_expected.to eq [runner1, runner2, runner3] + end end - end - context 'with sort param equal to contacted_asc' do - let(:params) { { sort: 'contacted_asc' } } + context 'with sort param equal to contacted_asc' do + let(:params) { { sort: 'contacted_asc' } } - it 'sorts by contacted_at ascending' do - is_expected.to eq [runner2, runner3, runner1] + it 'sorts by contacted_at ascending' do + is_expected.to eq [runner2, runner3, runner1] + end end - end - context 'with sort param equal to contacted_desc' do - let(:params) { { sort: 'contacted_desc' } } + context 'with sort param equal to contacted_desc' do + let(:params) { { sort: 'contacted_desc' } } - it 'sorts by contacted_at descending' do - is_expected.to eq [runner1, runner3, runner2] + it 'sorts by contacted_at descending' do + is_expected.to eq [runner1, runner3, runner2] + end end - end - context 'with sort param equal to token_expires_at_asc' do - let(:params) { { sort: 'token_expires_at_asc' } } + context 'with sort param equal to token_expires_at_asc' do + let(:params) { { sort: 'token_expires_at_asc' } } - it 'sorts by contacted_at ascending' do - is_expected.to eq [runner2, runner1, runner3] + it 'sorts by contacted_at ascending' do + is_expected.to eq [runner2, runner1, runner3] + end end - end - context 'with sort param equal to token_expires_at_desc' do - let(:params) { { sort: 'token_expires_at_desc' } } + context 'with sort param equal to token_expires_at_desc' do + let(:params) { { sort: 'token_expires_at_desc' } } - it 'sorts by contacted_at descending' do - is_expected.to eq [runner3, runner1, runner2] + it 'sorts by contacted_at descending' do + is_expected.to eq [runner3, runner1, runner2] + end end end end - context 'by non admin user' do + shared_examples 'executes as normal user' do it 'returns no runners' do user = create :user create :ci_runner, active: true @@ -229,6 +231,24 @@ RSpec.describe Ci::RunnersFinder do end end + context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do + it_behaves_like 'executes as admin' + end + + context 'when admin mode setting is enabled' do + context 'when in admin mode', :enable_admin_mode do + it_behaves_like 'executes as admin' + end + + context 'when not in admin mode' do + it_behaves_like 'executes as normal user' + end + end + + context 'by non admin user' do + it_behaves_like 'executes as normal user' + end + context 'when user is nil' do it 'returns no runners' do user = nil @@ -473,4 +493,153 @@ RSpec.describe Ci::RunnersFinder do end end end + + context 'project' do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + let_it_be(:other_project) { create(:project) } + + let(:extra_params) { {} } + let(:params) { { project: project }.merge(extra_params).reject { |_, v| v.nil? } } + + describe '#execute' do + subject { described_class.new(current_user: user, params: params).execute } + + context 'with user as project admin' do + before do + project.add_maintainer(user) + end + + context 'with project runners' do + let_it_be(:runner_project) { create(:ci_runner, :project, contacted_at: 7.minutes.ago, projects: [project]) } + + it 'returns runners available to project' do + expect(subject).to match_array([runner_project]) + end + end + + context 'with ancestor group runners' do + let_it_be(:runner_instance) { create(:ci_runner, contacted_at: 13.minutes.ago) } + let_it_be(:runner_group) { create(:ci_runner, :group, contacted_at: 12.minutes.ago, groups: [group]) } + + it 'returns runners available to project' do + expect(subject).to match_array([runner_instance, runner_group]) + end + end + + context 'with allowed shared runners' do + let_it_be(:runner_instance) { create(:ci_runner, :instance, contacted_at: 13.minutes.ago) } + + it 'returns runners available to project' do + expect(subject).to match_array([runner_instance]) + end + end + + context 'with project, ancestor group, and allowed shared runners' do + let_it_be(:runner_project) { create(:ci_runner, :project, contacted_at: 7.minutes.ago, projects: [project]) } + let_it_be(:runner_group) { create(:ci_runner, :group, contacted_at: 12.minutes.ago, groups: [group]) } + let_it_be(:runner_instance) { create(:ci_runner, :instance, contacted_at: 13.minutes.ago) } + + it 'returns runners available to project' do + expect(subject).to match_array([runner_project, runner_group, runner_instance]) + end + end + + context 'filtering' do + let_it_be(:runner_instance_inactive) { create(:ci_runner, :instance, active: false, contacted_at: 13.minutes.ago) } + let_it_be(:runner_instance_active) { create(:ci_runner, :instance, active: true, contacted_at: 13.minutes.ago) } + let_it_be(:runner_project_active) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, active: true, projects: [project]) } + let_it_be(:runner_project_inactive) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, active: false, projects: [project]) } + let_it_be(:runner_other_project_inactive) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, active: false, projects: [other_project]) } + + context 'by search term' do + let_it_be(:runner_project_1) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, description: 'runner_project_search', projects: [project]) } + let_it_be(:runner_project_2) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, description: 'runner_project', projects: [project]) } + let_it_be(:runner_another_project) { create(:ci_runner, :project, contacted_at: 5.minutes.ago, description: 'runner_project_search', projects: [other_project]) } + + let(:extra_params) { { search: 'runner_project_search' } } + + it 'returns the correct runner' do + expect(subject).to match_array([runner_project_1]) + end + end + + context 'by active status' do + let(:extra_params) { { active: false } } + + it 'returns the correct runners' do + expect(subject).to match_array([runner_instance_inactive, runner_project_inactive]) + end + end + + context 'by status' do + let(:extra_params) { { status_status: 'paused' } } + + it 'returns correct runner' do + expect(subject).to match_array([runner_instance_inactive, runner_project_inactive]) + end + end + + context 'by tag_name' do + let_it_be(:runner_project_1) { create(:ci_runner, :project, contacted_at: 3.minutes.ago, tag_list: %w[runner_tag], projects: [project]) } + let_it_be(:runner_project_2) { create(:ci_runner, :project, contacted_at: 3.minutes.ago, tag_list: %w[other_tag], projects: [project]) } + let_it_be(:runner_other_project) { create(:ci_runner, :project, contacted_at: 3.minutes.ago, tag_list: %w[runner_tag], projects: [other_project]) } + + let(:extra_params) { { tag_name: %w[runner_tag] } } + + it 'returns correct runner' do + expect(subject).to match_array([runner_project_1]) + end + end + + context 'by runner type' do + let(:extra_params) { { type_type: 'project_type' } } + + it 'returns correct runners' do + expect(subject).to match_array([runner_project_active, runner_project_inactive]) + end + end + end + end + + context 'with user as project developer' do + let(:user) { create(:user) } + + before do + project.add_developer(user) + end + + it 'returns no runners' do + expect(subject).to be_empty + end + end + + context 'when user is nil' do + let_it_be(:user) { nil } + + it 'returns no runners' do + expect(subject).to be_empty + end + end + + context 'with nil project_full_path' do + let(:project_full_path) { nil } + + it 'returns no runners' do + expect(subject).to be_empty + end + end + + context 'when on_demand_scans_runner_tags feature flag is disabled' do + before do + stub_feature_flags(on_demand_scans_runner_tags: false) + end + + it 'returns no runners' do + expect(subject).to be_empty + end + end + end + end end |