summaryrefslogtreecommitdiff
path: root/spec/finders
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
commit7e9c479f7de77702622631cff2628a9c8dcbc627 (patch)
treec8f718a08e110ad7e1894510980d2155a6549197 /spec/finders
parente852b0ae16db4052c1c567d9efa4facc81146e88 (diff)
downloadgitlab-ce-7e9c479f7de77702622631cff2628a9c8dcbc627.tar.gz
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'spec/finders')
-rw-r--r--spec/finders/alert_management/http_integrations_finder_spec.rb70
-rw-r--r--spec/finders/ci/commit_statuses_finder_spec.rb178
-rw-r--r--spec/finders/ci/jobs_finder_spec.rb141
-rw-r--r--spec/finders/environment_names_finder_spec.rb180
-rw-r--r--spec/finders/feature_flags_user_lists_finder_spec.rb31
-rw-r--r--spec/finders/group_descendants_finder_spec.rb37
-rw-r--r--spec/finders/issues_finder_spec.rb44
-rw-r--r--spec/finders/merge_requests/by_approvals_finder_spec.rb1
-rw-r--r--spec/finders/packages/group_packages_finder_spec.rb146
-rw-r--r--spec/finders/packages/npm/package_finder_spec.rb6
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb21
-rw-r--r--spec/finders/security/jobs_finder_spec.rb21
-rw-r--r--spec/finders/security/license_compliance_jobs_finder_spec.rb24
-rw-r--r--spec/finders/security/security_jobs_finder_spec.rb47
-rw-r--r--spec/finders/user_groups_counter_spec.rb45
15 files changed, 796 insertions, 196 deletions
diff --git a/spec/finders/alert_management/http_integrations_finder_spec.rb b/spec/finders/alert_management/http_integrations_finder_spec.rb
new file mode 100644
index 00000000000..d65de2cdbbd
--- /dev/null
+++ b/spec/finders/alert_management/http_integrations_finder_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AlertManagement::HttpIntegrationsFinder do
+ let_it_be(:project) { create(:project) }
+ let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project ) }
+ let_it_be(:extra_integration) { create(:alert_management_http_integration, project: project ) }
+ let_it_be(:alt_project_integration) { create(:alert_management_http_integration) }
+
+ let(:params) { {} }
+
+ describe '#execute' do
+ subject(:execute) { described_class.new(project, params).execute }
+
+ context 'empty params' do
+ it { is_expected.to contain_exactly(integration) }
+ end
+
+ context 'endpoint_identifier param given' do
+ let(:params) { { endpoint_identifier: integration.endpoint_identifier } }
+
+ it { is_expected.to contain_exactly(integration) }
+
+ context 'matches an unavailable integration' do
+ let(:params) { { endpoint_identifier: extra_integration.endpoint_identifier } }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'but unknown' do
+ let(:params) { { endpoint_identifier: 'unknown' } }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'but blank' do
+ let(:params) { { endpoint_identifier: nil } }
+
+ it { is_expected.to contain_exactly(integration) }
+ end
+ end
+
+ context 'active param given' do
+ let(:params) { { active: true } }
+
+ it { is_expected.to contain_exactly(integration) }
+
+ context 'when integration is disabled' do
+ before do
+ integration.update!(active: false)
+ end
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'but blank' do
+ let(:params) { { active: nil } }
+
+ it { is_expected.to contain_exactly(integration) }
+ end
+ end
+
+ context 'project has no integrations' do
+ subject(:execute) { described_class.new(create(:project), params).execute }
+
+ it { is_expected.to be_empty }
+ end
+ end
+end
diff --git a/spec/finders/ci/commit_statuses_finder_spec.rb b/spec/finders/ci/commit_statuses_finder_spec.rb
new file mode 100644
index 00000000000..1aa9cb12432
--- /dev/null
+++ b/spec/finders/ci/commit_statuses_finder_spec.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CommitStatusesFinder, '#execute' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:release) { create(:release, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ context 'tag refs' do
+ let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
+ let(:subject) { described_class.new(project, project.repository, user, tags).execute }
+
+ context 'no pipelines' do
+ it 'returns nil' do
+ expect(subject).to be_blank
+ end
+ end
+
+ context 'when multiple tags exist' do
+ before do
+ create(:ci_pipeline,
+ project: project,
+ ref: 'v1.1.0',
+ sha: project.commit('v1.1.0').sha,
+ status: :running)
+ create(:ci_pipeline,
+ project: project,
+ ref: 'v1.0.0',
+ sha: project.commit('v1.0.0').sha,
+ status: :success)
+ end
+
+ it 'all relevant commit statuses are received' do
+ expect(subject['v1.1.0'].group).to eq("running")
+ expect(subject['v1.0.0'].group).to eq("success")
+ end
+ end
+
+ context 'when a tag has multiple pipelines' do
+ before do
+ create(:ci_pipeline,
+ project: project,
+ ref: 'v1.0.0',
+ sha: project.commit('v1.0.0').sha,
+ status: :running,
+ created_at: 6.months.ago)
+ create(:ci_pipeline,
+ project: project,
+ ref: 'v1.0.0',
+ sha: project.commit('v1.0.0').sha,
+ status: :success,
+ created_at: 2.months.ago)
+ end
+
+ it 'chooses the latest to determine status' do
+ expect(subject['v1.0.0'].group).to eq("success")
+ end
+ end
+ end
+
+ context 'branch refs' do
+ let(:subject) { described_class.new(project, project.repository, user, branches).execute }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'no pipelines' do
+ let(:branches) { BranchesFinder.new(project.repository, {}).execute }
+
+ it 'returns nil' do
+ expect(subject).to be_blank
+ end
+ end
+
+ context 'when a branch has multiple pipelines' do
+ let(:branches) { BranchesFinder.new(project.repository, {}).execute }
+
+ before do
+ sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'master')
+ create(:ci_pipeline,
+ project: project,
+ user: user,
+ ref: "master",
+ sha: sha,
+ status: :running,
+ created_at: 6.months.ago)
+ create(:ci_pipeline,
+ project: project,
+ user: user,
+ ref: "master",
+ sha: sha,
+ status: :success,
+ created_at: 2.months.ago)
+ end
+
+ it 'chooses the latest to determine status' do
+ expect(subject["master"].group).to eq("success")
+ end
+ end
+
+ context 'when multiple branches exist' do
+ let(:branches) { BranchesFinder.new(project.repository, {}).execute }
+
+ before do
+ master_sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'master')
+ create(:ci_pipeline,
+ project: project,
+ user: user,
+ ref: "master",
+ sha: master_sha,
+ status: :running,
+ created_at: 6.months.ago)
+ test_sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'test')
+ create(:ci_pipeline,
+ project: project,
+ user: user,
+ ref: "test",
+ sha: test_sha,
+ status: :success,
+ created_at: 2.months.ago)
+ end
+
+ it 'all relevant commit statuses are received' do
+ expect(subject["master"].group).to eq("running")
+ expect(subject["test"].group).to eq("success")
+ end
+ end
+ end
+
+ context 'CI pipelines visible to' do
+ let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
+ let(:subject) { described_class.new(project, project.repository, user, tags).execute }
+
+ before do
+ create(:ci_pipeline,
+ project: project,
+ ref: 'v1.1.0',
+ sha: project.commit('v1.1.0').sha,
+ status: :running)
+ end
+
+ context 'everyone' do
+ it 'returns something' do
+ expect(subject).not_to be_blank
+ end
+ end
+
+ context 'project members only' do
+ before do
+ project.project_feature.update!(builds_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'returns nil' do
+ expect(subject).to be_empty
+ end
+ end
+
+ context 'when not a member of a private project' do
+ let(:private_project) { create(:project, :private, :repository) }
+ let(:private_tags) { TagsFinder.new(private_tags.repository, {}).execute }
+ let(:private_subject) { described_class.new(private_project, private_project.repository, user, tags).execute }
+
+ before do
+ create(:ci_pipeline,
+ project: private_project,
+ ref: 'v1.1.0',
+ sha: private_project.commit('v1.1.0').sha,
+ status: :running)
+ end
+
+ it 'returns nil' do
+ expect(private_subject).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/finders/ci/jobs_finder_spec.rb b/spec/finders/ci/jobs_finder_spec.rb
index a6a41c36489..4a6585e3f2b 100644
--- a/spec/finders/ci/jobs_finder_spec.rb
+++ b/spec/finders/ci/jobs_finder_spec.rb
@@ -36,135 +36,62 @@ RSpec.describe Ci::JobsFinder, '#execute' do
end
end
- context 'with ci_jobs_finder_refactor ff enabled' do
- before do
- stub_feature_flags(ci_jobs_finder_refactor: true)
- end
-
- context 'scope is present' do
- let(:jobs) { [job_1, job_2, job_3] }
-
- where(:scope, :index) do
- [
- ['pending', 0],
- ['running', 1],
- ['finished', 2]
- ]
- end
-
- with_them do
- let(:params) { { scope: scope } }
-
- it { expect(subject).to match_array([jobs[index]]) }
- end
+ context 'scope is present' do
+ let(:jobs) { [job_1, job_2, job_3] }
+
+ where(:scope, :index) do
+ [
+ ['pending', 0],
+ ['running', 1],
+ ['finished', 2]
+ ]
end
- context 'scope is an array' do
- let(:jobs) { [job_1, job_2, job_3] }
- let(:params) {{ scope: ['running'] }}
+ with_them do
+ let(:params) { { scope: scope } }
- it 'filters by the job statuses in the scope' do
- expect(subject).to match_array([job_2])
- end
+ it { expect(subject).to match_array([jobs[index]]) }
end
end
- context 'with ci_jobs_finder_refactor ff disabled' do
- before do
- stub_feature_flags(ci_jobs_finder_refactor: false)
- end
-
- context 'scope is present' do
- let(:jobs) { [job_1, job_2, job_3] }
-
- where(:scope, :index) do
- [
- ['pending', 0],
- ['running', 1],
- ['finished', 2]
- ]
- end
+ context 'scope is an array' do
+ let(:jobs) { [job_1, job_2, job_3] }
+ let(:params) {{ scope: ['running'] }}
- with_them do
- let(:params) { { scope: scope } }
-
- it { expect(subject).to match_array([jobs[index]]) }
- end
+ it 'filters by the job statuses in the scope' do
+ expect(subject).to match_array([job_2])
end
end
end
- context 'with ci_jobs_finder_refactor ff enabled' do
- before do
- stub_feature_flags(ci_jobs_finder_refactor: true)
- end
-
- context 'a project is present' do
- subject { described_class.new(current_user: user, project: project, params: params).execute }
-
- context 'user has access to the project' do
- before do
- project.add_maintainer(user)
- end
-
- it 'returns jobs for the specified project' do
- expect(subject).to match_array([job_3])
- end
- end
+ context 'a project is present' do
+ subject { described_class.new(current_user: user, project: project, params: params).execute }
- context 'user has no access to project builds' do
- before do
- project.add_guest(user)
- end
-
- it 'returns no jobs' do
- expect(subject).to be_empty
- end
+ context 'user has access to the project' do
+ before do
+ project.add_maintainer(user)
end
- context 'without user' do
- let(:user) { nil }
-
- it 'returns no jobs' do
- expect(subject).to be_empty
- end
+ it 'returns jobs for the specified project' do
+ expect(subject).to match_array([job_3])
end
end
- end
-
- context 'with ci_jobs_finder_refactor ff disabled' do
- before do
- stub_feature_flags(ci_jobs_finder_refactor: false)
- end
- context 'a project is present' do
- subject { described_class.new(current_user: user, project: project, params: params).execute }
- context 'user has access to the project' do
- before do
- project.add_maintainer(user)
- end
-
- it 'returns jobs for the specified project' do
- expect(subject).to match_array([job_3])
- end
+ context 'user has no access to project builds' do
+ before do
+ project.add_guest(user)
end
- context 'user has no access to project builds' do
- before do
- project.add_guest(user)
- end
-
- it 'returns no jobs' do
- expect(subject).to be_empty
- end
+ it 'returns no jobs' do
+ expect(subject).to be_empty
end
+ end
- context 'without user' do
- let(:user) { nil }
+ context 'without user' do
+ let(:user) { nil }
- it 'returns no jobs' do
- expect(subject).to be_empty
- end
+ it 'returns no jobs' do
+ expect(subject).to be_empty
end
end
end
diff --git a/spec/finders/environment_names_finder_spec.rb b/spec/finders/environment_names_finder_spec.rb
index 9244e4fb369..fe00c800f0a 100644
--- a/spec/finders/environment_names_finder_spec.rb
+++ b/spec/finders/environment_names_finder_spec.rb
@@ -5,58 +5,178 @@ require 'spec_helper'
RSpec.describe EnvironmentNamesFinder do
describe '#execute' do
let!(:group) { create(:group) }
- let!(:project1) { create(:project, :public, namespace: group) }
- let!(:project2) { create(:project, :private, namespace: group) }
+ let!(:public_project) { create(:project, :public, namespace: group) }
+ let!(:private_project) { create(:project, :private, namespace: group) }
let!(:user) { create(:user) }
before do
- create(:environment, name: 'gstg', project: project1)
- create(:environment, name: 'gprd', project: project1)
- create(:environment, name: 'gprd', project: project2)
- create(:environment, name: 'gcny', project: project2)
+ create(:environment, name: 'gstg', project: public_project)
+ create(:environment, name: 'gprd', project: public_project)
+ create(:environment, name: 'gprd', project: private_project)
+ create(:environment, name: 'gcny', project: private_project)
end
- context 'using a group and a group member' do
- it 'returns environment names for all projects' do
- group.add_developer(user)
+ context 'using a group' do
+ context 'with a group developer' do
+ it 'returns environment names for all projects' do
+ group.add_developer(user)
- names = described_class.new(group, user).execute
+ names = described_class.new(group, user).execute
- expect(names).to eq(%w[gcny gprd gstg])
+ expect(names).to eq(%w[gcny gprd gstg])
+ end
end
- end
- context 'using a group and a guest' do
- it 'returns environment names for all public projects' do
- names = described_class.new(group, user).execute
+ context 'with a group reporter' do
+ it 'returns environment names for all projects' do
+ group.add_reporter(user)
+
+ names = described_class.new(group, user).execute
- expect(names).to eq(%w[gprd gstg])
+ expect(names).to eq(%w[gcny gprd gstg])
+ end
end
- end
- context 'using a public project and a project member' do
- it 'returns all the unique environment names' do
- project1.team.add_developer(user)
+ context 'with a public project reporter' do
+ it 'returns environment names for all public projects' do
+ public_project.add_reporter(user)
+
+ names = described_class.new(group, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'with a private project reporter' do
+ it 'returns environment names for all public projects' do
+ private_project.add_reporter(user)
+
+ names = described_class.new(group, user).execute
+
+ expect(names).to eq(%w[gcny gprd gstg])
+ end
+ end
+
+ context 'with a group guest' do
+ it 'returns environment names for all public projects' do
+ group.add_guest(user)
+
+ names = described_class.new(group, user).execute
- names = described_class.new(project1, user).execute
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'with a non-member' do
+ it 'returns environment names for all public projects' do
+ names = described_class.new(group, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'without a user' do
+ it 'returns environment names for all public projects' do
+ names = described_class.new(group).execute
- expect(names).to eq(%w[gprd gstg])
+ expect(names).to eq(%w[gprd gstg])
+ end
end
end
- context 'using a public project and a guest' do
- it 'returns all the unique environment names' do
- names = described_class.new(project1, user).execute
+ context 'using a public project' do
+ context 'with a project developer' do
+ it 'returns all the unique environment names' do
+ public_project.add_developer(user)
+
+ names = described_class.new(public_project, user).execute
- expect(names).to eq(%w[gprd gstg])
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'with a project reporter' do
+ it 'returns all the unique environment names' do
+ public_project.add_reporter(user)
+
+ names = described_class.new(public_project, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'with a project guest' do
+ it 'returns all the unique environment names' do
+ public_project.add_guest(user)
+
+ names = described_class.new(public_project, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'with a non-member' do
+ it 'returns all the unique environment names' do
+ names = described_class.new(public_project, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'without a user' do
+ it 'returns all the unique environment names' do
+ names = described_class.new(public_project).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
end
end
- context 'using a private project and a guest' do
- it 'returns all the unique environment names' do
- names = described_class.new(project2, user).execute
+ context 'using a private project' do
+ context 'with a project developer' do
+ it 'returns all the unique environment names' do
+ private_project.add_developer(user)
+
+ names = described_class.new(private_project, user).execute
+
+ expect(names).to eq(%w[gcny gprd])
+ end
+ end
+
+ context 'with a project reporter' do
+ it 'returns all the unique environment names' do
+ private_project.add_reporter(user)
+
+ names = described_class.new(private_project, user).execute
+
+ expect(names).to eq(%w[gcny gprd])
+ end
+ end
+
+ context 'with a project guest' do
+ it 'does not return any environment names' do
+ private_project.add_guest(user)
+
+ names = described_class.new(private_project, user).execute
+
+ expect(names).to be_empty
+ end
+ end
+
+ context 'with a non-member' do
+ it 'does not return any environment names' do
+ names = described_class.new(private_project, user).execute
+
+ expect(names).to be_empty
+ end
+ end
+
+ context 'without a user' do
+ it 'does not return any environment names' do
+ names = described_class.new(private_project).execute
- expect(names).to be_empty
+ expect(names).to be_empty
+ end
end
end
end
diff --git a/spec/finders/feature_flags_user_lists_finder_spec.rb b/spec/finders/feature_flags_user_lists_finder_spec.rb
new file mode 100644
index 00000000000..fc904a174d7
--- /dev/null
+++ b/spec/finders/feature_flags_user_lists_finder_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagsUserListsFinder do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ describe '#execute' do
+ it 'returns user lists' do
+ finder = described_class.new(project, user, {})
+ user_list = create(:operations_feature_flag_user_list, project: project)
+
+ expect(finder.execute).to contain_exactly(user_list)
+ end
+
+ context 'with search' do
+ it 'returns only matching user lists' do
+ create(:operations_feature_flag_user_list, name: 'do not find', project: project)
+ user_list = create(:operations_feature_flag_user_list, name: 'testing', project: project)
+ finder = described_class.new(project, user, { search: "test" })
+
+ expect(finder.execute).to contain_exactly(user_list)
+ end
+ end
+ end
+end
diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb
index 2f9303606b1..b66d0ffce87 100644
--- a/spec/finders/group_descendants_finder_spec.rb
+++ b/spec/finders/group_descendants_finder_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe GroupDescendantsFinder do
- let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
let(:params) { {} }
subject(:finder) do
@@ -129,6 +129,39 @@ RSpec.describe GroupDescendantsFinder do
end
end
+ context 'with shared groups' do
+ let_it_be(:other_group) { create(:group) }
+ let_it_be(:shared_group_link) do
+ create(:group_group_link,
+ shared_group: group,
+ shared_with_group: other_group)
+ end
+
+ context 'without common ancestor' do
+ it { expect(finder.execute).to be_empty }
+ end
+
+ context 'with common ancestor' do
+ let_it_be(:common_ancestor) { create(:group) }
+ let_it_be(:other_group) { create(:group, parent: common_ancestor) }
+ let_it_be(:group) { create(:group, parent: common_ancestor) }
+
+ context 'querying under the common ancestor' do
+ it { expect(finder.execute).to be_empty }
+ end
+
+ context 'querying the common ancestor' do
+ subject(:finder) do
+ described_class.new(current_user: user, parent_group: common_ancestor, params: params)
+ end
+
+ it 'contains shared subgroups' do
+ expect(finder.execute).to contain_exactly(group, other_group)
+ end
+ end
+ end
+ end
+
context 'with nested groups' do
let!(:project) { create(:project, namespace: group) }
let!(:subgroup) { create(:group, :private, parent: group) }
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 21bc03011c3..3c3bf1a8870 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -472,6 +472,10 @@ RSpec.describe IssuesFinder do
it 'returns issues with title and description match for search term' do
expect(issues).to contain_exactly(issue1, issue2)
end
+
+ it 'uses optimizer hints' do
+ expect(issues.to_sql).to match(/BitmapScan/)
+ end
end
context 'filtering by issue term in title' do
@@ -827,6 +831,46 @@ RSpec.describe IssuesFinder do
let(:project_params) { { project_id: project.id } }
end
end
+
+ context 'filtering by due date' do
+ let_it_be(:issue_overdue) { create(:issue, project: project1, due_date: 2.days.ago) }
+ let_it_be(:issue_due_soon) { create(:issue, project: project1, due_date: 2.days.from_now) }
+
+ let(:scope) { 'all' }
+ let(:base_params) { { project_id: project1.id } }
+
+ context 'with param set to no due date' do
+ let(:params) { base_params.merge(due_date: Issue::NoDueDate.name) }
+
+ it 'returns issues with no due date' do
+ expect(issues).to contain_exactly(issue1)
+ end
+ end
+
+ context 'with param set to overdue' do
+ let(:params) { base_params.merge(due_date: Issue::Overdue.name) }
+
+ it 'returns overdue issues' do
+ expect(issues).to contain_exactly(issue_overdue)
+ end
+ end
+
+ context 'with param set to next month and previous two weeks' do
+ let(:params) { base_params.merge(due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name) }
+
+ it 'returns issues from the previous two weeks and next month' do
+ expect(issues).to contain_exactly(issue_overdue, issue_due_soon)
+ end
+ end
+
+ context 'with invalid param' do
+ let(:params) { base_params.merge(due_date: 'foo') }
+
+ it 'returns no issues' do
+ expect(issues).to be_empty
+ end
+ end
+ end
end
describe '#row_count', :request_store do
diff --git a/spec/finders/merge_requests/by_approvals_finder_spec.rb b/spec/finders/merge_requests/by_approvals_finder_spec.rb
index 0e1856879f1..5c56e610c0b 100644
--- a/spec/finders/merge_requests/by_approvals_finder_spec.rb
+++ b/spec/finders/merge_requests/by_approvals_finder_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe MergeRequests::ByApprovalsFinder do
create(:approval, merge_request: mr, user: first_user)
end
end
+
let_it_be(:merge_request_with_both_approvals) do
create(:merge_request).tap do |mr|
create(:approval, merge_request: mr, user: first_user)
diff --git a/spec/finders/packages/group_packages_finder_spec.rb b/spec/finders/packages/group_packages_finder_spec.rb
index 163c920f621..0db69de65a5 100644
--- a/spec/finders/packages/group_packages_finder_spec.rb
+++ b/spec/finders/packages/group_packages_finder_spec.rb
@@ -2,13 +2,16 @@
require 'spec_helper'
RSpec.describe Packages::GroupPackagesFinder do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, namespace: group) }
- let(:another_group) { create(:group) }
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:group) { create(:group) }
+ let_it_be_with_reload(:project) { create(:project, namespace: group, builds_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE) }
+
+ let(:add_user_to_group) { true }
before do
- group.add_developer(user)
+ group.add_developer(user) if add_user_to_group
end
describe '#execute' do
@@ -27,16 +30,16 @@ RSpec.describe Packages::GroupPackagesFinder do
end
context 'group has packages' do
- let!(:package1) { create(:maven_package, project: project) }
- let!(:package2) { create(:maven_package, project: project) }
- let!(:package3) { create(:maven_package) }
+ let_it_be(:package1) { create(:maven_package, project: project) }
+ let_it_be(:package2) { create(:maven_package, project: project) }
+ let_it_be(:package3) { create(:maven_package) }
it { is_expected.to match_array([package1, package2]) }
context 'subgroup has packages' do
- let(:subgroup) { create(:group, parent: group) }
- let(:subproject) { create(:project, namespace: subgroup) }
- let!(:package4) { create(:npm_package, project: subproject) }
+ let_it_be_with_reload(:subgroup) { create(:group, parent: group) }
+ let_it_be_with_reload(:subproject) { create(:project, namespace: subgroup, builds_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE) }
+ let_it_be(:package4) { create(:npm_package, project: subproject) }
it { is_expected.to match_array([package1, package2, package4]) }
@@ -45,16 +48,87 @@ RSpec.describe Packages::GroupPackagesFinder do
it { is_expected.to match_array([package1, package2]) }
end
+
+ context 'permissions' do
+ let(:add_user_to_group) { false }
+
+ where(:role, :project_visibility, :repository_visibility, :packages_returned) do
+ :anonymous | :public | :enabled | :all
+ :guest | :public | :enabled | :all
+ :reporter | :public | :enabled | :all
+ :developer | :public | :enabled | :all
+ :maintainer | :public | :enabled | :all
+ :anonymous | :public | :private | :none
+ :guest | :public | :private | :all
+ :reporter | :public | :private | :all
+ :developer | :public | :private | :all
+ :maintainer | :public | :private | :all
+ :anonymous | :private | :enabled | :none
+ :guest | :private | :enabled | :none
+ :reporter | :private | :enabled | :all
+ :developer | :private | :enabled | :all
+ :maintainer | :private | :enabled | :all
+ :anonymous | :private | :private | :none
+ :guest | :private | :private | :none
+ :reporter | :private | :private | :all
+ :developer | :private | :private | :all
+ :maintainer | :private | :private | :all
+ end
+
+ with_them do
+ let(:expected_packages) do
+ case packages_returned
+ when :all
+ [package1, package2, package4]
+ when :none
+ []
+ end
+ end
+
+ before do
+ subgroup.update!(visibility: project_visibility.to_s)
+ group.update!(visibility: project_visibility.to_s)
+ project.update!(
+ visibility: project_visibility.to_s,
+ repository_access_level: repository_visibility.to_s
+ )
+ subproject.update!(
+ visibility: project_visibility.to_s,
+ repository_access_level: repository_visibility.to_s
+ )
+
+ unless role == :anonymous
+ project.add_user(user, role)
+ subproject.add_user(user, role)
+ end
+ end
+
+ it { is_expected.to match_array(expected_packages) }
+ end
+ end
+
+ context 'avoid N+1 query' do
+ it 'avoids N+1 database queries' do
+ count = ActiveRecord::QueryRecorder.new { subject }
+ .count
+
+ Packages::Package.package_types.keys.each do |package_type|
+ create("#{package_type}_package", project: create(:project, namespace: subgroup))
+ end
+
+ expect { described_class.new(user, group, params).execute }.not_to exceed_query_limit(count)
+ end
+ end
end
context 'when there are processing packages' do
- let!(:package4) { create(:nuget_package, project: project, name: Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) }
+ let_it_be(:package4) { create(:nuget_package, project: project, name: Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) }
it { is_expected.to match_array([package1, package2]) }
end
context 'does not include packages without version number' do
- let!(:package_without_version) { create(:maven_package, project: project, version: nil) }
+ let_it_be(:package_without_version) { create(:maven_package, project: project, version: nil) }
it { is_expected.not_to include(package_without_version) }
end
@@ -80,7 +154,7 @@ RSpec.describe Packages::GroupPackagesFinder do
end
context 'group has package of all types' do
- package_types.each { |pt| let!("package_#{pt}") { create("#{pt}_package", project: project) } }
+ package_types.each { |pt| let_it_be("package_#{pt}") { create("#{pt}_package", project: project) } }
package_types.each do |package_type|
it_behaves_like 'with package type', package_type
@@ -98,7 +172,7 @@ RSpec.describe Packages::GroupPackagesFinder do
end
context 'package type is nil' do
- let!(:package1) { create(:maven_package, project: project) }
+ let_it_be(:package1) { create(:maven_package, project: project) }
subject { described_class.new(user, group, package_type: nil).execute }
@@ -110,47 +184,5 @@ RSpec.describe Packages::GroupPackagesFinder do
it { expect { subject }.to raise_exception(described_class::InvalidPackageTypeError) }
end
-
- context 'when project is public' do
- let_it_be(:other_user) { create(:user) }
- let(:finder) { described_class.new(other_user, group) }
-
- before do
- project.update!(visibility_level: ProjectFeature::ENABLED)
- end
-
- context 'when packages are public' do
- before do
- project.project_feature.update!(
- builds_access_level: ProjectFeature::PRIVATE,
- merge_requests_access_level: ProjectFeature::PRIVATE,
- repository_access_level: ProjectFeature::ENABLED)
- end
-
- it 'returns group packages' do
- package1 = create(:maven_package, project: project)
- package2 = create(:maven_package, project: project)
- create(:maven_package)
-
- expect(finder.execute).to match_array([package1, package2])
- end
- end
-
- context 'packages are members only' do
- before do
- project.project_feature.update!(
- builds_access_level: ProjectFeature::PRIVATE,
- merge_requests_access_level: ProjectFeature::PRIVATE,
- repository_access_level: ProjectFeature::PRIVATE)
-
- create(:maven_package, project: project)
- create(:maven_package)
- end
-
- it 'filters out the project if the user doesn\'t have permission' do
- expect(finder.execute).to be_empty
- end
- end
- end
end
end
diff --git a/spec/finders/packages/npm/package_finder_spec.rb b/spec/finders/packages/npm/package_finder_spec.rb
index be54b1f8b18..78c23971f92 100644
--- a/spec/finders/packages/npm/package_finder_spec.rb
+++ b/spec/finders/packages/npm/package_finder_spec.rb
@@ -16,6 +16,12 @@ RSpec.describe ::Packages::Npm::PackageFinder do
it { is_expected.to be_empty }
end
+
+ context 'with nil project' do
+ let(:project) { nil }
+
+ it { is_expected.to be_empty }
+ end
end
describe '#find_by_version' do
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
index c8913329839..cece80047e1 100644
--- a/spec/finders/personal_access_tokens_finder_spec.rb
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -62,6 +62,27 @@ RSpec.describe PersonalAccessTokensFinder do
revoked_impersonation_token, expired_impersonation_token)
end
+ describe 'with users' do
+ let(:user2) { create(:user) }
+
+ before do
+ create(:personal_access_token, user: user2)
+ create(:personal_access_token, :expired, user: user2)
+ create(:personal_access_token, :revoked, user: user2)
+ create(:personal_access_token, :impersonation, user: user2)
+ create(:personal_access_token, :expired, :impersonation, user: user2)
+ create(:personal_access_token, :revoked, :impersonation, user: user2)
+
+ params[:users] = [user]
+ end
+
+ it {
+ is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token,
+ revoked_personal_access_token, expired_personal_access_token,
+ revoked_impersonation_token, expired_impersonation_token)
+ }
+ end
+
describe 'with sort order' do
before do
params[:sort] = 'id_asc'
diff --git a/spec/finders/security/jobs_finder_spec.rb b/spec/finders/security/jobs_finder_spec.rb
new file mode 100644
index 00000000000..9badf9c38cf
--- /dev/null
+++ b/spec/finders/security/jobs_finder_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Security::JobsFinder do
+ it 'is an abstract class that does not permit instantiation' do
+ expect { described_class.new(pipeline: nil) }.to raise_error(
+ NotImplementedError,
+ 'This is an abstract class, please instantiate its descendants'
+ )
+ end
+
+ describe '.allowed_job_types' do
+ it 'must be implemented by child classes' do
+ expect { described_class.allowed_job_types }.to raise_error(
+ NotImplementedError,
+ 'allowed_job_types must be overwritten to return an array of job types'
+ )
+ end
+ end
+end
diff --git a/spec/finders/security/license_compliance_jobs_finder_spec.rb b/spec/finders/security/license_compliance_jobs_finder_spec.rb
new file mode 100644
index 00000000000..3066912df12
--- /dev/null
+++ b/spec/finders/security/license_compliance_jobs_finder_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Security::LicenseComplianceJobsFinder do
+ it_behaves_like ::Security::JobsFinder, described_class.allowed_job_types
+
+ describe "#execute" do
+ subject { finder.execute }
+
+ let(:pipeline) { create(:ci_pipeline) }
+ let(:finder) { described_class.new(pipeline: pipeline) }
+
+ let!(:sast_build) { create(:ci_build, :sast, pipeline: pipeline) }
+ let!(:container_scanning_build) { create(:ci_build, :container_scanning, pipeline: pipeline) }
+ let!(:dast_build) { create(:ci_build, :dast, pipeline: pipeline) }
+ let!(:license_scanning_build) { create(:ci_build, :license_scanning, pipeline: pipeline) }
+ let!(:license_management_build) { create(:ci_build, :license_management, pipeline: pipeline) }
+
+ it 'returns only the license_scanning jobs' do
+ is_expected.to contain_exactly(license_scanning_build, license_management_build)
+ end
+ end
+end
diff --git a/spec/finders/security/security_jobs_finder_spec.rb b/spec/finders/security/security_jobs_finder_spec.rb
new file mode 100644
index 00000000000..fa8253b96b5
--- /dev/null
+++ b/spec/finders/security/security_jobs_finder_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Security::SecurityJobsFinder do
+ it_behaves_like ::Security::JobsFinder, described_class.allowed_job_types
+
+ describe "#execute" do
+ let(:pipeline) { create(:ci_pipeline) }
+ let(:finder) { described_class.new(pipeline: pipeline) }
+
+ subject { finder.execute }
+
+ context 'with specific secure job types' do
+ let!(:sast_build) { create(:ci_build, :sast, pipeline: pipeline) }
+ let!(:container_scanning_build) { create(:ci_build, :container_scanning, pipeline: pipeline) }
+ let!(:dast_build) { create(:ci_build, :dast, pipeline: pipeline) }
+ let!(:secret_detection_build) { create(:ci_build, :secret_detection, pipeline: pipeline) }
+
+ let(:finder) { described_class.new(pipeline: pipeline, job_types: [:sast, :container_scanning, :secret_detection]) }
+
+ it 'returns only those requested' do
+ is_expected.to include(sast_build)
+ is_expected.to include(container_scanning_build)
+ is_expected.to include(secret_detection_build)
+
+ is_expected.not_to include(dast_build)
+ end
+ end
+
+ context 'with combination of security jobs and license management jobs' do
+ let!(:sast_build) { create(:ci_build, :sast, pipeline: pipeline) }
+ let!(:container_scanning_build) { create(:ci_build, :container_scanning, pipeline: pipeline) }
+ let!(:dast_build) { create(:ci_build, :dast, pipeline: pipeline) }
+ let!(:secret_detection_build) { create(:ci_build, :secret_detection, pipeline: pipeline) }
+ let!(:license_management_build) { create(:ci_build, :license_management, pipeline: pipeline) }
+
+ it 'returns only the security jobs' do
+ is_expected.to include(sast_build)
+ is_expected.to include(container_scanning_build)
+ is_expected.to include(dast_build)
+ is_expected.to include(secret_detection_build)
+ is_expected.not_to include(license_management_build)
+ end
+ end
+ end
+end
diff --git a/spec/finders/user_groups_counter_spec.rb b/spec/finders/user_groups_counter_spec.rb
new file mode 100644
index 00000000000..49587e6dada
--- /dev/null
+++ b/spec/finders/user_groups_counter_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe UserGroupsCounter do
+ subject { described_class.new(user_ids).execute }
+
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group1) { create(:group) }
+ let_it_be(:group_member1) { create(:group_member, source: group1, user_id: user.id, access_level: Gitlab::Access::OWNER) }
+ let_it_be(:user_ids) { [user.id] }
+
+ it 'returns authorized group count for the user' do
+ expect(subject[user.id]).to eq(1)
+ end
+
+ context 'when request to join group is pending' do
+ let_it_be(:pending_group) { create(:group) }
+ let_it_be(:pending_group_member) { create(:group_member, requested_at: Time.current.utc, source: pending_group, user_id: user.id) }
+
+ it 'does not include pending group in the count' do
+ expect(subject[user.id]).to eq(1)
+ end
+ end
+
+ context 'when user is part of sub group' do
+ let_it_be(:sub_group) { create(:group, parent: create(:group)) }
+ let_it_be(:sub_group_member1) { create(:group_member, source: sub_group, user_id: user.id, access_level: Gitlab::Access::DEVELOPER) }
+
+ it 'includes sub group in the count' do
+ expect(subject[user.id]).to eq(2)
+ end
+ end
+
+ context 'when user is part of namespaced project' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let_it_be(:project_member) { create(:project_member, source: project, user_id: user.id, access_level: Gitlab::Access::REPORTER) }
+
+ it 'includes the project group' do
+ expect(subject[user.id]).to eq(2)
+ end
+ end
+ end
+end