spec/finders/ci/jobs_finder_spec.rb (357 lines of code) (raw):
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::JobsFinder, '#execute', feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:project) { create(:project, :private, public_builds: false) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:pending_job) { create(:ci_build, :pending) }
let_it_be(:running_job) { create(:ci_build, :running) }
let_it_be(:successful_job) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
let(:params) { {} }
context 'when project, pipeline, and runner are blank' do
subject(:finder_execute) { described_class.new(current_user: current_user, params: params).execute }
context 'with admin' do
let(:current_user) { admin }
context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do
it { is_expected.to match_array([pending_job, running_job, successful_job]) }
end
context 'when admin mode setting is enabled' do
context 'when in admin mode', :enable_admin_mode do
it { is_expected.to match_array([pending_job, running_job, successful_job]) }
end
context 'when not in admin mode' do
it { is_expected.to be_empty }
end
end
end
context 'with admin and admin mode enabled', :enable_admin_mode do
let(:current_user) { admin }
context 'with param `scope`' do
using RSpec::Parameterized::TableSyntax
where(:scope, :expected_jobs) do
'pending' | lazy { [pending_job] }
'running' | lazy { [running_job] }
'finished' | lazy { [successful_job] }
%w[running success] | lazy { [running_job, successful_job] }
end
with_them do
let(:params) { { scope: scope } }
it { is_expected.to match_array(expected_jobs) }
end
end
context 'with param `runner_type`' do
let_it_be(:job_with_instance_runner) { create(:ci_build, :success, runner: create(:ci_runner, :instance)) }
let_it_be(:job_with_group_runner) do
create(:ci_build, :success, runner: create(:ci_runner, :group, groups: [project.parent]))
end
let_it_be(:job_with_project_runner) do
create(:ci_build, :success, runner: create(:ci_runner, :project, projects: [project]))
end
context 'with feature flag :admin_jobs_filter_runner_type enabled' do
using RSpec::Parameterized::TableSyntax
where(:runner_type, :expected_jobs) do
'group_type' | lazy { [job_with_group_runner] }
'instance_type' | lazy { [job_with_instance_runner] }
'project_type' | lazy { [job_with_project_runner] }
%w[instance_type project_type] | lazy { [job_with_instance_runner, job_with_project_runner] }
end
with_them do
let(:params) { { runner_type: runner_type } }
it { is_expected.to match_array(expected_jobs) }
end
end
context 'with feature flag :admin_jobs_filter_runner_type disabled' do
let(:params) { { runner_type: 'instance_type' } }
let(:expected_jobs) do
[
job_with_group_runner,
job_with_instance_runner,
job_with_project_runner,
pending_job,
running_job,
successful_job
]
end
before do
stub_feature_flags(admin_jobs_filter_runner_type: false)
end
it { is_expected.to match_array(expected_jobs) }
end
end
context "with params" do
let_it_be(:job_with_running_status_and_group_runner) do
create(:ci_build, :running, runner: create(:ci_runner, :group, groups: [project.parent]))
end
let_it_be(:job_with_instance_runner) { create(:ci_build, :success, runner: create(:ci_runner, :instance)) }
let_it_be(:job_with_project_runner) do
create(:ci_build, :success, runner: create(:ci_runner, :project, projects: [project]))
end
context 'with feature flag :admin_jobs_filter_runner_type enabled' do
using RSpec::Parameterized::TableSyntax
where(:param_runner_type, :param_scope, :expected_jobs) do
'group_type' | 'running' | lazy { [job_with_running_status_and_group_runner] }
%w[instance_type project_type] | 'finished' | lazy { [job_with_instance_runner, job_with_project_runner] }
%w[instance_type project_type] | 'pending' | lazy { [] }
end
with_them do
let(:params) { { runner_type: param_runner_type, scope: param_scope } }
it { is_expected.to match_array(expected_jobs) }
end
end
context 'with feature flag :admin_jobs_filter_runner_type disabled' do
before do
stub_feature_flags(admin_jobs_filter_runner_type: false)
end
using RSpec::Parameterized::TableSyntax
where(:param_runner_type, :param_scope, :expected_jobs) do
'group_type' | 'running' | lazy do
[job_with_running_status_and_group_runner, running_job]
end
%w[instance_type project_type] | 'finished' | lazy do
[
job_with_instance_runner,
job_with_project_runner,
successful_job
]
end
%w[instance_type project_type] | 'pending' | lazy { [pending_job] }
end
with_them do
let(:params) { { runner_type: param_runner_type, scope: param_scope } }
it { is_expected.to match_array(expected_jobs) }
end
end
end
end
context 'with user not being project member' do
let(:current_user) { user }
it { is_expected.to be_empty }
end
context 'without user' do
let(:current_user) { nil }
it { is_expected.to be_empty }
end
end
context 'when project is present' do
subject { described_class.new(current_user: user, project: project, params: params).execute }
context 'with user being project maintainer' do
before do
project.add_maintainer(user)
end
it 'returns jobs for the specified project' do
expect(subject).to match_array([successful_job])
end
context 'when artifacts are present for some jobs' do
let_it_be(:job_with_artifacts) { create(:ci_build, :success, pipeline: pipeline, name: 'test') }
let_it_be(:artifact) { create(:ci_job_artifact, job: job_with_artifacts) }
context 'when with_artifacts is true' do
let(:params) { { with_artifacts: true } }
it 'returns only jobs with artifacts' do
expect(subject).to match_array([job_with_artifacts])
end
end
context 'when with_artifacts is false' do
let(:params) { { with_artifacts: false } }
it 'returns all jobs' do
expect(subject).to match_array([successful_job, job_with_artifacts])
end
end
context "with param `scope" do
using RSpec::Parameterized::TableSyntax
where(:param_scope, :expected_jobs) do
'success' | lazy { [successful_job, job_with_artifacts] }
'[success pending]' | lazy { [successful_job, job_with_artifacts] }
'pending' | lazy { [] }
nil | lazy { [successful_job, job_with_artifacts] }
end
with_them do
let(:params) { { with_artifacts: false, scope: param_scope } }
it { is_expected.to match_array(expected_jobs) }
end
end
end
end
context 'with user being project guest' do
before do
project.add_guest(user)
end
it 'returns no jobs' do
expect(subject).to be_empty
end
end
context 'without user' do
let(:user) { nil }
it 'returns no jobs' do
expect(subject).to be_empty
end
end
end
context 'when pipeline is present' do
subject { described_class.new(current_user: user, pipeline: pipeline, params: params).execute }
context 'with user being project maintainer' do
before_all do
project.add_maintainer(user)
successful_job.update!(retried: true)
end
let_it_be(:job_4) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
it 'does not return retried jobs by default' do
expect(subject).to match_array([job_4])
end
context 'when include_retried is false' do
let(:params) { { include_retried: false } }
it 'does not return retried jobs' do
expect(subject).to match_array([job_4])
end
end
context 'when include_retried is true' do
let(:params) { { include_retried: true } }
it 'returns retried jobs' do
expect(subject).to match_array([successful_job, job_4])
end
end
end
context 'without user' do
let(:user) { nil }
it 'returns no jobs' do
expect(subject).to be_empty
end
end
end
context 'when runner is present' do
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let_it_be(:job_4) { create(:ci_build, :success, runner: runner) }
subject(:execute) { described_class.new(current_user: user, runner: runner, params: params).execute }
context 'when current user is an admin' do
let(:user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it 'returns jobs for the specified project' do
expect(subject).to contain_exactly job_4
end
context 'with params' do
using RSpec::Parameterized::TableSyntax
where(:param_runner_type, :param_scope, :expected_jobs) do
'project_type' | 'success' | lazy { [job_4] }
'instance_type' | nil | lazy { [] }
nil | 'pending' | lazy { [] }
end
with_them do
let(:params) { { runner_type: param_runner_type, scope: param_scope } }
it { is_expected.to match_array(expected_jobs) }
end
end
end
end
context 'with user being project guest' do
let_it_be(:guest) { create(:user) }
let(:user) { guest }
before do
project.add_guest(guest)
end
it 'returns no jobs' do
expect(subject).to be_empty
end
end
context 'without user' do
let(:user) { nil }
it 'returns no jobs' do
expect(subject).to be_empty
end
end
describe 'when match_compatible_runner_only is true' do
let_it_be(:owner) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:groups) { create_list(:group, 2, owners: owner, maintainers: maintainer, developers: developer) }
let_it_be(:projects) { groups.map { |group| create(:project, group: group) } }
let_it_be(:runner_matching_tags) { %w[tag1 tag2 tag3] }
let_it_be(:job) do
create(:ci_build, :pending, name: 'pending_job', project: projects.first,
tag_list: runner_matching_tags.sample(2))
end
let_it_be(:pending_job) { create(:ci_pending_build, project: projects.first, build: job) }
let_it_be(:different_project_job) do
create(:ci_build, :pending, project: projects.second, tag_list: runner_matching_tags)
end
let_it_be(:different_project_pending_job) do
create(:ci_pending_build, project: projects.second, build: different_project_job)
end
let_it_be(:instance_runner) { create(:ci_runner, tag_list: runner_matching_tags, run_untagged: false) }
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [groups.first], tag_list: runner_matching_tags) }
let_it_be(:project_runner) do
create(:ci_runner, :project, projects: [projects.first], tag_list: runner_matching_tags)
end
let(:params) do
{ match_compatible_runner_only: true }
end
before_all do
# Add job with non-matching tags to check for this does not return unrelated jobs
create(:ci_pending_build, project: projects.first,
build: create(:ci_build, :pending, project: projects.first, tag_list: %w[tag1 tag4]))
end
context 'with instance runner' do
let(:runner) { instance_runner }
context 'when user has access to runner' do
context 'when current user is an admin', :enable_admin_mode do
let(:user) { admin }
it 'returns the pending jobs' do
expect(execute).to contain_exactly(job, different_project_job)
end
end
end
context 'without user' do
let(:user) { nil }
it { is_expected.to be_empty }
end
end
context 'with group runner' do
let(:runner) { group_runner }
context 'when user has access to runner' do
context 'when current user is an admin', :enable_admin_mode do
let(:user) { admin }
it 'returns the pending job' do
expect(execute).to contain_exactly(job)
end
end
context 'when current user is an owner of group' do
let(:user) { owner }
it 'returns the pending job' do
expect(execute).to contain_exactly(job)
end
end
context 'when current user is a maintainer of group' do
let(:user) { maintainer }
it { is_expected.to be_empty }
end
end
context 'without user' do
let(:user) { nil }
it { is_expected.to be_empty }
end
end
context 'with project runner' do
let(:runner) { project_runner }
context 'when user has access to runner' do
context 'when current user is an admin', :enable_admin_mode do
let(:user) { admin }
it 'returns the pending job' do
expect(execute).to contain_exactly(job)
end
end
context 'when current user is an maintainer of group' do
let(:user) { maintainer }
it 'returns the pending job' do
expect(execute).to contain_exactly(job)
end
end
context 'when current user is a developer of group' do
let(:user) { developer }
it { is_expected.to be_empty }
end
end
context 'without user' do
let(:user) { nil }
it { is_expected.to be_empty }
end
end
end
end
end