summaryrefslogtreecommitdiff
path: root/spec/finders
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 13:18:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 13:18:24 +0000
commit0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch)
tree4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /spec/finders
parent744144d28e3e7fddc117924fef88de5d9674fe4c (diff)
downloadgitlab-ce-0653e08efd039a5905f3fa4f6e9cef9f5d2f799c.tar.gz
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'spec/finders')
-rw-r--r--spec/finders/branches_finder_spec.rb7
-rw-r--r--spec/finders/ci/pipelines_finder_spec.rb37
-rw-r--r--spec/finders/ci/runners_finder_spec.rb126
-rw-r--r--spec/finders/error_tracking/errors_finder_spec.rb18
-rw-r--r--spec/finders/feature_flags_finder_spec.rb8
-rw-r--r--spec/finders/groups/user_groups_finder_spec.rb106
-rw-r--r--spec/finders/issues_finder/params_spec.rb49
-rw-r--r--spec/finders/issues_finder_spec.rb429
-rw-r--r--spec/finders/merge_requests_finder_spec.rb96
-rw-r--r--spec/finders/packages/helm/package_files_finder_spec.rb35
-rw-r--r--spec/finders/packages/helm/packages_finder_spec.rb74
-rw-r--r--spec/finders/packages/npm/package_finder_spec.rb61
-rw-r--r--spec/finders/projects_finder_spec.rb28
-rw-r--r--spec/finders/repositories/tree_finder_spec.rb95
14 files changed, 773 insertions, 396 deletions
diff --git a/spec/finders/branches_finder_spec.rb b/spec/finders/branches_finder_spec.rb
index a62dd3842db..f9d525c33a4 100644
--- a/spec/finders/branches_finder_spec.rb
+++ b/spec/finders/branches_finder_spec.rb
@@ -259,4 +259,11 @@ RSpec.describe BranchesFinder do
end
end
end
+
+ describe '#total' do
+ subject { branch_finder.total }
+
+ it { is_expected.to be_an(Integer) }
+ it { is_expected.to eq(repository.branch_count) }
+ end
end
diff --git a/spec/finders/ci/pipelines_finder_spec.rb b/spec/finders/ci/pipelines_finder_spec.rb
index c7bd52576e8..908210e0296 100644
--- a/spec/finders/ci/pipelines_finder_spec.rb
+++ b/spec/finders/ci/pipelines_finder_spec.rb
@@ -113,27 +113,6 @@ RSpec.describe Ci::PipelinesFinder do
end
end
- context 'when name is specified' do
- let(:user) { create(:user) }
- let!(:pipeline) { create(:ci_pipeline, project: project, user: user) }
-
- context 'when name exists' do
- let(:params) { { name: user.name } }
-
- it 'returns matched pipelines' do
- is_expected.to eq([pipeline])
- end
- end
-
- context 'when name does not exist' do
- let(:params) { { name: 'invalid-name' } }
-
- it 'returns empty' do
- is_expected.to be_empty
- end
- end
- end
-
context 'when username is specified' do
let(:user) { create(:user) }
let!(:pipeline) { create(:ci_pipeline, project: project, user: user) }
@@ -258,20 +237,8 @@ RSpec.describe Ci::PipelinesFinder do
let!(:push_pipeline) { create(:ci_pipeline, project: project, source: 'push') }
let!(:api_pipeline) { create(:ci_pipeline, project: project, source: 'api') }
- context 'when `pipeline_source_filter` feature flag is disabled' do
- before do
- stub_feature_flags(pipeline_source_filter: false)
- end
-
- it 'returns all the pipelines' do
- is_expected.to contain_exactly(web_pipeline, push_pipeline, api_pipeline)
- end
- end
-
- context 'when `pipeline_source_filter` feature flag is enabled' do
- it 'returns only the matched pipeline' do
- is_expected.to eq([web_pipeline])
- end
+ it 'returns only the matched pipeline' do
+ is_expected.to eq([web_pipeline])
end
end
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb
index 599b4ffb804..10d3f641e02 100644
--- a/spec/finders/ci/runners_finder_spec.rb
+++ b/spec/finders/ci/runners_finder_spec.rb
@@ -18,6 +18,13 @@ RSpec.describe Ci::RunnersFinder do
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]
+ 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
@@ -158,6 +165,7 @@ RSpec.describe Ci::RunnersFinder do
let_it_be(:project_4) { create(:project, group: sub_group_2) }
let_it_be(:project_5) { create(:project, group: sub_group_3) }
let_it_be(:project_6) { create(:project, group: sub_group_4) }
+ let_it_be(:runner_instance) { create(:ci_runner, :instance, contacted_at: 13.minutes.ago) }
let_it_be(:runner_group) { create(:ci_runner, :group, contacted_at: 12.minutes.ago) }
let_it_be(:runner_sub_group_1) { create(:ci_runner, :group, active: false, contacted_at: 11.minutes.ago) }
let_it_be(:runner_sub_group_2) { create(:ci_runner, :group, contacted_at: 10.minutes.ago) }
@@ -171,7 +179,10 @@ RSpec.describe Ci::RunnersFinder do
let_it_be(:runner_project_6) { create(:ci_runner, :project, contacted_at: 2.minutes.ago, projects: [project_5])}
let_it_be(:runner_project_7) { create(:ci_runner, :project, contacted_at: 1.minute.ago, projects: [project_6])}
- let(:params) { {} }
+ let(:target_group) { nil }
+ let(:membership) { nil }
+ let(:extra_params) { {} }
+ let(:params) { { group: target_group, membership: membership }.merge(extra_params).reject { |_, v| v.nil? } }
before do
group.runners << runner_group
@@ -182,65 +193,104 @@ RSpec.describe Ci::RunnersFinder do
end
describe '#execute' do
- subject { described_class.new(current_user: user, group: group, params: params).execute }
+ subject { described_class.new(current_user: user, params: params).execute }
+
+ shared_examples 'membership equal to :descendants' do
+ it 'returns all descendant runners' do
+ expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
+ runner_project_4, runner_project_3, runner_project_2,
+ runner_project_1, runner_sub_group_4, runner_sub_group_3,
+ runner_sub_group_2, runner_sub_group_1, runner_group])
+ end
+ end
context 'with user as group owner' do
before do
group.add_owner(user)
end
- context 'passing no params' do
- it 'returns all descendant runners' do
- expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
- runner_project_4, runner_project_3, runner_project_2,
- runner_project_1, runner_sub_group_4, runner_sub_group_3,
- runner_sub_group_2, runner_sub_group_1, runner_group])
+ context 'with :group as target group' do
+ let(:target_group) { group }
+
+ context 'passing no params' do
+ it_behaves_like 'membership equal to :descendants'
end
- end
- context 'with sort param' do
- let(:params) { { sort: 'contacted_asc' } }
+ context 'with :descendants membership' do
+ let(:membership) { :descendants }
- it 'sorts by specified attribute' do
- expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
- runner_sub_group_3, runner_sub_group_4, runner_project_1,
- runner_project_2, runner_project_3, runner_project_4,
- runner_project_5, runner_project_6, runner_project_7])
+ it_behaves_like 'membership equal to :descendants'
end
- end
- context 'filtering' do
- context 'by search term' do
- let(:params) { { search: 'runner_project_search' } }
+ context 'with :direct membership' do
+ let(:membership) { :direct }
+
+ it 'returns runners belonging to group' do
+ expect(subject).to eq([runner_group])
+ end
+ end
+
+ context 'with unknown membership' do
+ let(:membership) { :unsupported }
- it 'returns correct runner' do
- expect(subject).to eq([runner_project_3])
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, 'Invalid membership filter')
end
end
- context 'by status' do
- let(:params) { { status_status: 'paused' } }
+ context 'with nil group' do
+ let(:target_group) { nil }
- it 'returns correct runner' do
- expect(subject).to eq([runner_sub_group_1])
+ it 'returns no runners' do
+ # Query should run against all runners, however since user is not admin, query returns no results
+ expect(subject).to eq([])
end
end
- context 'by tag_name' do
- let(:params) { { tag_name: %w[runner_tag] } }
+ context 'with sort param' do
+ let(:extra_params) { { sort: 'contacted_asc' } }
- it 'returns correct runner' do
- expect(subject).to eq([runner_project_5])
+ it 'sorts by specified attribute' do
+ expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
+ runner_sub_group_3, runner_sub_group_4, runner_project_1,
+ runner_project_2, runner_project_3, runner_project_4,
+ runner_project_5, runner_project_6, runner_project_7])
end
end
- context 'by runner type' do
- let(:params) { { type_type: 'project_type' } }
+ context 'filtering' do
+ context 'by search term' do
+ let(:extra_params) { { search: 'runner_project_search' } }
+
+ it 'returns correct runner' do
+ expect(subject).to eq([runner_project_3])
+ end
+ end
+
+ context 'by status' do
+ let(:extra_params) { { status_status: 'paused' } }
+
+ it 'returns correct runner' do
+ expect(subject).to eq([runner_sub_group_1])
+ end
+ end
+
+ context 'by tag_name' do
+ let(:extra_params) { { tag_name: %w[runner_tag] } }
+
+ it 'returns correct runner' do
+ expect(subject).to eq([runner_project_5])
+ end
+ end
+
+ context 'by runner type' do
+ let(:extra_params) { { type_type: 'project_type' } }
- it 'returns correct runners' do
- expect(subject).to eq([runner_project_7, runner_project_6,
- runner_project_5, runner_project_4,
- runner_project_3, runner_project_2, runner_project_1])
+ it 'returns correct runners' do
+ expect(subject).to eq([runner_project_7, runner_project_6,
+ runner_project_5, runner_project_4,
+ runner_project_3, runner_project_2, runner_project_1])
+ end
end
end
end
@@ -278,7 +328,7 @@ RSpec.describe Ci::RunnersFinder do
end
describe '#sort_key' do
- subject { described_class.new(current_user: user, group: group, params: params).sort_key }
+ subject { described_class.new(current_user: user, params: params.merge(group: group)).sort_key }
context 'without params' do
it 'returns created_at_desc' do
@@ -287,7 +337,7 @@ RSpec.describe Ci::RunnersFinder do
end
context 'with params' do
- let(:params) { { sort: 'contacted_asc' } }
+ let(:extra_params) { { sort: 'contacted_asc' } }
it 'returns contacted_asc' do
expect(subject).to eq('contacted_asc')
diff --git a/spec/finders/error_tracking/errors_finder_spec.rb b/spec/finders/error_tracking/errors_finder_spec.rb
index 2df5f1653e0..29053054f9d 100644
--- a/spec/finders/error_tracking/errors_finder_spec.rb
+++ b/spec/finders/error_tracking/errors_finder_spec.rb
@@ -6,7 +6,8 @@ RSpec.describe ErrorTracking::ErrorsFinder do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.creator }
let_it_be(:error) { create(:error_tracking_error, project: project) }
- let_it_be(:error_resolved) { create(:error_tracking_error, :resolved, project: project) }
+ let_it_be(:error_resolved) { create(:error_tracking_error, :resolved, project: project, first_seen_at: 2.hours.ago) }
+ let_it_be(:error_yesterday) { create(:error_tracking_error, project: project, first_seen_at: Time.zone.now.yesterday) }
before do
project.add_maintainer(user)
@@ -17,12 +18,25 @@ RSpec.describe ErrorTracking::ErrorsFinder do
subject { described_class.new(user, project, params).execute }
- it { is_expected.to contain_exactly(error, error_resolved) }
+ it { is_expected.to contain_exactly(error, error_resolved, error_yesterday) }
context 'with status parameter' do
let(:params) { { status: 'resolved' } }
it { is_expected.to contain_exactly(error_resolved) }
end
+
+ context 'with sort parameter' do
+ let(:params) { { status: 'unresolved', sort: 'first_seen' } }
+
+ it { is_expected.to eq([error, error_yesterday]) }
+ end
+
+ context 'with limit parameter' do
+ let(:params) { { limit: '1', sort: 'first_seen' } }
+
+ # Sort by first_seen is DESC by default, so the most recent error is `error`
+ it { is_expected.to contain_exactly(error) }
+ end
end
end
diff --git a/spec/finders/feature_flags_finder_spec.rb b/spec/finders/feature_flags_finder_spec.rb
index 4faa6a62a1f..1b3c71b143f 100644
--- a/spec/finders/feature_flags_finder_spec.rb
+++ b/spec/finders/feature_flags_finder_spec.rb
@@ -72,13 +72,5 @@ RSpec.describe FeatureFlagsFinder do
subject
end
end
-
- context 'with a legacy flag' do
- let!(:feature_flag_3) { create(:operations_feature_flag, :legacy_flag, name: 'flag-c', project: project) }
-
- it 'returns new flags' do
- is_expected.to eq([feature_flag_1, feature_flag_2])
- end
- end
end
end
diff --git a/spec/finders/groups/user_groups_finder_spec.rb b/spec/finders/groups/user_groups_finder_spec.rb
new file mode 100644
index 00000000000..4cce3ab72eb
--- /dev/null
+++ b/spec/finders/groups/user_groups_finder_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Groups::UserGroupsFinder do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
+ let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
+ let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
+ let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+
+ subject { described_class.new(current_user, target_user, arguments).execute }
+
+ let(:arguments) { {} }
+ let(:current_user) { user }
+ let(:target_user) { user }
+
+ before_all do
+ guest_group.add_guest(user)
+ private_maintainer_group.add_maintainer(user)
+ public_developer_group.add_developer(user)
+ public_maintainer_group.add_maintainer(user)
+ end
+
+ it 'returns all groups where the user is a direct member' do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+
+ context 'when target_user is nil' do
+ let(:target_user) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when current_user is nil' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when permission is :create_projects' do
+ let(:arguments) { { permission_scope: :create_projects } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group
+ ]
+ )
+ end
+
+ context 'when paginatable_namespace_drop_down_for_project_creation feature flag is disabled' do
+ before do
+ stub_feature_flags(paginatable_namespace_drop_down_for_project_creation: false)
+ end
+
+ it 'ignores project creation scope and returns all groups where the user is a direct member' do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+ end
+
+ context 'when search is provided' do
+ let(:arguments) { { permission_scope: :create_projects, search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+ end
+
+ context 'when search is provided' do
+ let(:arguments) { { search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+ end
+end
diff --git a/spec/finders/issues_finder/params_spec.rb b/spec/finders/issues_finder/params_spec.rb
new file mode 100644
index 00000000000..879ecc364a2
--- /dev/null
+++ b/spec/finders/issues_finder/params_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssuesFinder::Params do
+ describe '#include_hidden' do
+ subject { described_class.new(params, user, IssuesFinder) }
+
+ context 'when param is not set' do
+ let(:params) { {} }
+
+ context 'with an admin', :enable_admin_mode do
+ let(:user) { create(:user, :admin) }
+
+ it 'returns true' do
+ expect(subject.include_hidden?).to be_truthy
+ end
+ end
+
+ context 'with a regular user' do
+ let(:user) { create(:user) }
+
+ it 'returns false' do
+ expect(subject.include_hidden?).to be_falsey
+ end
+ end
+ end
+
+ context 'when param is set' do
+ let(:params) { { include_hidden: true } }
+
+ context 'with an admin', :enable_admin_mode do
+ let(:user) { create(:user, :admin) }
+
+ it 'returns true' do
+ expect(subject.include_hidden?).to be_truthy
+ end
+ end
+
+ context 'with a regular user' do
+ let(:user) { create(:user) }
+
+ it 'returns false' do
+ expect(subject.include_hidden?).to be_falsey
+ end
+ end
+ end
+ end
+end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 0cb73f3da6d..ed35d75720c 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -12,8 +12,52 @@ RSpec.describe IssuesFinder do
context 'scope: all' do
let(:scope) { 'all' }
- it 'returns all issues' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5)
+ context 'include_hidden and public_only params' do
+ let_it_be(:banned_user) { create(:user, :banned) }
+ let_it_be(:hidden_issue) { create(:issue, project: project1, author: banned_user) }
+ let_it_be(:confidential_issue) { create(:issue, project: project1, confidential: true) }
+
+ context 'when user is an admin', :enable_admin_mode do
+ let(:user) { create(:user, :admin) }
+
+ it 'returns all issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, hidden_issue, confidential_issue)
+ end
+ end
+
+ context 'when user is not an admin' do
+ context 'when public_only is true' do
+ let(:params) { { public_only: true } }
+
+ it 'returns public issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5)
+ end
+ end
+
+ context 'when public_only is false' do
+ let(:params) { { public_only: false } }
+
+ it 'returns public and confidential issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, confidential_issue)
+ end
+ end
+
+ context 'when public_only is not set' do
+ it 'returns public and confidential issue' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, confidential_issue)
+ end
+ end
+
+ context 'when ban_user_feature_flag is false' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it 'returns all issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, hidden_issue, confidential_issue)
+ end
+ end
+ end
end
context 'user does not have read permissions' do
@@ -426,139 +470,121 @@ RSpec.describe IssuesFinder do
end
end
- shared_examples ':label_name parameter' do
- context 'filtering by label' do
- let(:params) { { label_name: label.title } }
+ context 'filtering by label' do
+ let(:params) { { label_name: label.title } }
- it 'returns issues with that label' do
- expect(issues).to contain_exactly(issue2)
- end
+ it 'returns issues with that label' do
+ expect(issues).to contain_exactly(issue2)
+ end
- context 'using NOT' do
- let(:params) { { not: { label_name: label.title } } }
+ context 'using NOT' do
+ let(:params) { { not: { label_name: label.title } } }
- it 'returns issues that do not have that label' do
- expect(issues).to contain_exactly(issue1, issue3, issue4, issue5)
- end
+ it 'returns issues that do not have that label' do
+ expect(issues).to contain_exactly(issue1, issue3, issue4, issue5)
+ end
- # IssuableFinder first filters using the outer params (the ones not inside the `not` key.)
- # Afterwards, it applies the `not` params to that resultset. This means that things inside the `not` param
- # do not take precedence over the outer params with the same name.
- context 'shadowing the same outside param' do
- let(:params) { { label_name: label2.title, not: { label_name: label.title } } }
+ # IssuableFinder first filters using the outer params (the ones not inside the `not` key.)
+ # Afterwards, it applies the `not` params to that resultset. This means that things inside the `not` param
+ # do not take precedence over the outer params with the same name.
+ context 'shadowing the same outside param' do
+ let(:params) { { label_name: label2.title, not: { label_name: label.title } } }
- it 'does not take precedence over labels outside NOT' do
- expect(issues).to contain_exactly(issue3)
- end
+ it 'does not take precedence over labels outside NOT' do
+ expect(issues).to contain_exactly(issue3)
end
+ end
- context 'further filtering outside params' do
- let(:params) { { label_name: label2.title, not: { assignee_username: user2.username } } }
+ context 'further filtering outside params' do
+ let(:params) { { label_name: label2.title, not: { assignee_username: user2.username } } }
- it 'further filters on the returned resultset' do
- expect(issues).to be_empty
- end
+ it 'further filters on the returned resultset' do
+ expect(issues).to be_empty
end
end
end
+ end
- context 'filtering by multiple labels' do
- let(:params) { { label_name: [label.title, label2.title].join(',') } }
- let(:label2) { create(:label, project: project2) }
-
- before do
- create(:label_link, label: label2, target: issue2)
- end
+ context 'filtering by multiple labels' do
+ let(:params) { { label_name: [label.title, label2.title].join(',') } }
+ let(:label2) { create(:label, project: project2) }
- it 'returns the unique issues with all those labels' do
- expect(issues).to contain_exactly(issue2)
- end
-
- context 'using NOT' do
- let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } }
+ before do
+ create(:label_link, label: label2, target: issue2)
+ end
- it 'returns issues that do not have any of the labels provided' do
- expect(issues).to contain_exactly(issue1, issue4, issue5)
- end
- end
+ it 'returns the unique issues with all those labels' do
+ expect(issues).to contain_exactly(issue2)
end
- context 'filtering by a label that includes any or none in the title' do
- let(:params) { { label_name: [label.title, label2.title].join(',') } }
- let(:label) { create(:label, title: 'any foo', project: project2) }
- let(:label2) { create(:label, title: 'bar none', project: project2) }
+ context 'using NOT' do
+ let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } }
- before do
- create(:label_link, label: label2, target: issue2)
+ it 'returns issues that do not have any of the labels provided' do
+ expect(issues).to contain_exactly(issue1, issue4, issue5)
end
+ end
+ end
- it 'returns the unique issues with all those labels' do
- expect(issues).to contain_exactly(issue2)
- end
+ context 'filtering by a label that includes any or none in the title' do
+ let(:params) { { label_name: [label.title, label2.title].join(',') } }
+ let(:label) { create(:label, title: 'any foo', project: project2) }
+ let(:label2) { create(:label, title: 'bar none', project: project2) }
- context 'using NOT' do
- let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } }
+ before do
+ create(:label_link, label: label2, target: issue2)
+ end
- it 'returns issues that do not have ANY ONE of the labels provided' do
- expect(issues).to contain_exactly(issue1, issue4, issue5)
- end
- end
+ it 'returns the unique issues with all those labels' do
+ expect(issues).to contain_exactly(issue2)
end
- context 'filtering by no label' do
- let(:params) { { label_name: described_class::Params::FILTER_NONE } }
+ context 'using NOT' do
+ let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } }
- it 'returns issues with no labels' do
+ it 'returns issues that do not have ANY ONE of the labels provided' do
expect(issues).to contain_exactly(issue1, issue4, issue5)
end
end
+ end
- context 'filtering by any label' do
- let(:params) { { label_name: described_class::Params::FILTER_ANY } }
-
- it 'returns issues that have one or more label' do
- create_list(:label_link, 2, label: create(:label, project: project2), target: issue3)
+ context 'filtering by no label' do
+ let(:params) { { label_name: described_class::Params::FILTER_NONE } }
- expect(issues).to contain_exactly(issue2, issue3)
- end
+ it 'returns issues with no labels' do
+ expect(issues).to contain_exactly(issue1, issue4, issue5)
end
+ end
- context 'when the same label exists on project and group levels' do
- let(:issue1) { create(:issue, project: project1) }
- let(:issue2) { create(:issue, project: project1) }
-
- # Skipping validation to reproduce a "real-word" scenario.
- # We still have legacy labels on PRD that have the same title on the group and project levels, example: `bug`
- let(:project_label) { build(:label, title: 'somelabel', project: project1).tap { |r| r.save!(validate: false) } }
- let(:group_label) { create(:group_label, title: 'somelabel', group: project1.group) }
-
- let(:params) { { label_name: 'somelabel' } }
+ context 'filtering by any label' do
+ let(:params) { { label_name: described_class::Params::FILTER_ANY } }
- before do
- create(:label_link, label: group_label, target: issue1)
- create(:label_link, label: project_label, target: issue2)
- end
+ it 'returns issues that have one or more label' do
+ create_list(:label_link, 2, label: create(:label, project: project2), target: issue3)
- it 'finds both issue records' do
- expect(issues).to contain_exactly(issue1, issue2)
- end
+ expect(issues).to contain_exactly(issue2, issue3)
end
end
- context 'when `optimized_issuable_label_filter` feature flag is off' do
- before do
- stub_feature_flags(optimized_issuable_label_filter: false)
- end
+ context 'when the same label exists on project and group levels' do
+ let(:issue1) { create(:issue, project: project1) }
+ let(:issue2) { create(:issue, project: project1) }
- it_behaves_like ':label_name parameter'
- end
+ # Skipping validation to reproduce a "real-word" scenario.
+ # We still have legacy labels on PRD that have the same title on the group and project levels, example: `bug`
+ let(:project_label) { build(:label, title: 'somelabel', project: project1).tap { |r| r.save!(validate: false) } }
+ let(:group_label) { create(:group_label, title: 'somelabel', group: project1.group) }
+
+ let(:params) { { label_name: 'somelabel' } }
- context 'when `optimized_issuable_label_filter` feature flag is on' do
before do
- stub_feature_flags(optimized_issuable_label_filter: true)
+ create(:label_link, label: group_label, target: issue1)
+ create(:label_link, label: project_label, target: issue2)
end
- it_behaves_like ':label_name parameter'
+ it 'finds both issue records' do
+ expect(issues).to contain_exactly(issue1, issue2)
+ end
end
context 'filtering by issue term' do
@@ -567,6 +593,35 @@ RSpec.describe IssuesFinder do
it 'returns issues with title and description match for search term' do
expect(issues).to contain_exactly(issue1, issue2)
end
+
+ context 'with anonymous user' do
+ let_it_be(:public_project) { create(:project, :public, group: subgroup) }
+ let_it_be(:issue6) { create(:issue, project: public_project, title: 'tanuki') }
+ let_it_be(:issue7) { create(:issue, project: public_project, title: 'ikunat') }
+
+ let(:search_user) { nil }
+ let(:params) { { search: 'tanuki' } }
+
+ context 'with disable_anonymous_search feature flag enabled' do
+ before do
+ stub_feature_flags(disable_anonymous_search: true)
+ end
+
+ it 'does not perform search' do
+ expect(issues).to contain_exactly(issue6, issue7)
+ end
+ end
+
+ context 'with disable_anonymous_search feature flag disabled' do
+ before do
+ stub_feature_flags(disable_anonymous_search: false)
+ end
+
+ it 'finds one public issue' do
+ expect(issues).to contain_exactly(issue6)
+ end
+ end
+ end
end
context 'filtering by issue term in title' do
@@ -1001,132 +1056,64 @@ RSpec.describe IssuesFinder do
end
describe '#with_confidentiality_access_check' do
- let(:guest) { create(:user) }
+ let(:user) { create(:user) }
let_it_be(:authorized_user) { create(:user) }
- let_it_be(:banned_user) { create(:user, :banned) }
let_it_be(:project) { create(:project, namespace: authorized_user.namespace) }
let_it_be(:public_issue) { create(:issue, project: project) }
let_it_be(:confidential_issue) { create(:issue, project: project, confidential: true) }
- let_it_be(:hidden_issue) { create(:issue, project: project, author: banned_user) }
- shared_examples 'returns public, does not return hidden or confidential' do
+ shared_examples 'returns public, does not return confidential' do
it 'returns only public issues' do
expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue, hidden_issue)
+ expect(subject).not_to include(confidential_issue)
end
end
- shared_examples 'returns public and confidential, does not return hidden' do
- it 'returns only public and confidential issues' do
+ shared_examples 'returns public and confidential' do
+ it 'returns public and confidential issues' do
expect(subject).to include(public_issue, confidential_issue)
- expect(subject).not_to include(hidden_issue)
- end
- end
-
- shared_examples 'returns public and hidden, does not return confidential' do
- it 'returns only public and hidden issues' do
- expect(subject).to include(public_issue, hidden_issue)
- expect(subject).not_to include(confidential_issue)
end
end
- shared_examples 'returns public, confidential, and hidden' do
- it 'returns all issues' do
- expect(subject).to include(public_issue, confidential_issue, hidden_issue)
- end
- end
+ subject { described_class.new(user, params).with_confidentiality_access_check }
context 'when no project filter is given' do
let(:params) { {} }
context 'for an anonymous user' do
- subject { described_class.new(nil, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
end
context 'for a user without project membership' do
- subject { described_class.new(user, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
end
context 'for a guest user' do
- subject { described_class.new(guest, params).with_confidentiality_access_check }
-
before do
- project.add_guest(guest)
+ project.add_guest(user)
end
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
end
context 'for a project member with access to view confidential issues' do
- subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public and confidential, does not return hidden'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public, confidential, and hidden'
+ before do
+ project.add_reporter(user)
end
+
+ it_behaves_like 'returns public and confidential'
end
context 'for an admin' do
- let(:admin_user) { create(:user, :admin) }
-
- subject { described_class.new(admin_user, params).with_confidentiality_access_check }
+ let(:user) { create(:user, :admin) }
context 'when admin mode is enabled', :enable_admin_mode do
- it_behaves_like 'returns public, confidential, and hidden'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public, confidential, and hidden'
- end
+ it_behaves_like 'returns public and confidential'
end
context 'when admin mode is disabled' do
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
end
end
end
@@ -1135,17 +1122,9 @@ RSpec.describe IssuesFinder do
let(:params) { { project_id: project.id } }
context 'for an anonymous user' do
- subject { described_class.new(nil, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
+ let(:user) { nil }
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
it 'does not filter by confidentiality' do
expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
@@ -1154,17 +1133,7 @@ RSpec.describe IssuesFinder do
end
context 'for a user without project membership' do
- subject { described_class.new(user, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
it 'filters by confidentiality' do
expect(subject.to_sql).to match("issues.confidential")
@@ -1172,21 +1141,11 @@ RSpec.describe IssuesFinder do
end
context 'for a guest user' do
- subject { described_class.new(guest, params).with_confidentiality_access_check }
-
before do
- project.add_guest(guest)
+ project.add_guest(user)
end
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
+ it_behaves_like 'returns public, does not return confidential'
it 'filters by confidentiality' do
expect(subject.to_sql).to match("issues.confidential")
@@ -1194,40 +1153,18 @@ RSpec.describe IssuesFinder do
end
context 'for a project member with access to view confidential issues' do
- subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
-
- it_behaves_like 'returns public and confidential, does not return hidden'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public, confidential, and hidden'
+ before do
+ project.add_reporter(user)
end
- it 'does not filter by confidentiality' do
- expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
-
- subject
- end
+ it_behaves_like 'returns public and confidential'
end
context 'for an admin' do
- let(:admin_user) { create(:user, :admin) }
-
- subject { described_class.new(admin_user, params).with_confidentiality_access_check }
+ let(:user) { create(:user, :admin) }
context 'when admin mode is enabled', :enable_admin_mode do
- it_behaves_like 'returns public, confidential, and hidden'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public, confidential, and hidden'
- end
+ it_behaves_like 'returns public and confidential'
it 'does not filter by confidentiality' do
expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
@@ -1237,19 +1174,7 @@ RSpec.describe IssuesFinder do
end
context 'when admin mode is disabled' do
- it_behaves_like 'returns public, does not return hidden or confidential'
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it_behaves_like 'returns public and hidden, does not return confidential'
- end
-
- it 'filters by confidentiality' do
- expect(subject.to_sql).to match("issues.confidential")
- end
+ it_behaves_like 'returns public, does not return confidential'
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 49b29cefb9b..42197a6b103 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -227,56 +227,38 @@ RSpec.describe MergeRequestsFinder do
end
end
- shared_examples ':label_name parameter' do
- describe ':label_name parameter' do
- let(:common_labels) { create_list(:label, 3) }
- let(:distinct_labels) { create_list(:label, 3) }
- let(:merge_requests) do
- common_attrs = {
- source_project: project1, target_project: project1, author: user
- }
- distinct_labels.map do |label|
- labels = [label, *common_labels]
- create(:labeled_merge_request, :closed, labels: labels, **common_attrs)
- end
- end
-
- def find(label_name)
- described_class.new(user, label_name: label_name).execute
- end
-
- it 'accepts a single label' do
- found = find(distinct_labels.first.title)
- common = find(common_labels.first.title)
-
- expect(found).to contain_exactly(merge_requests.first)
- expect(common).to match_array(merge_requests)
- end
-
- it 'accepts an array of labels, all of which must match' do
- all_distinct = find(distinct_labels.pluck(:title))
- all_common = find(common_labels.pluck(:title))
-
- expect(all_distinct).to be_empty
- expect(all_common).to match_array(merge_requests)
+ describe ':label_name parameter' do
+ let(:common_labels) { create_list(:label, 3) }
+ let(:distinct_labels) { create_list(:label, 3) }
+ let(:merge_requests) do
+ common_attrs = {
+ source_project: project1, target_project: project1, author: user
+ }
+ distinct_labels.map do |label|
+ labels = [label, *common_labels]
+ create(:labeled_merge_request, :closed, labels: labels, **common_attrs)
end
end
- end
- context 'when `optimized_issuable_label_filter` feature flag is off' do
- before do
- stub_feature_flags(optimized_issuable_label_filter: false)
+ def find(label_name)
+ described_class.new(user, label_name: label_name).execute
end
- it_behaves_like ':label_name parameter'
- end
+ it 'accepts a single label' do
+ found = find(distinct_labels.first.title)
+ common = find(common_labels.first.title)
- context 'when `optimized_issuable_label_filter` feature flag is on' do
- before do
- stub_feature_flags(optimized_issuable_label_filter: true)
+ expect(found).to contain_exactly(merge_requests.first)
+ expect(common).to match_array(merge_requests)
end
- it_behaves_like ':label_name parameter'
+ it 'accepts an array of labels, all of which must match' do
+ all_distinct = find(distinct_labels.pluck(:title))
+ all_common = find(common_labels.pluck(:title))
+
+ expect(all_distinct).to be_empty
+ expect(all_common).to match_array(merge_requests)
+ end
end
it 'filters by source project id' do
@@ -729,6 +711,36 @@ RSpec.describe MergeRequestsFinder do
merge_requests = described_class.new(user, params).execute
expect { merge_requests.load }.not_to raise_error
end
+
+ context 'filtering by search text' do
+ let!(:merge_request6) { create(:merge_request, source_project: project1, target_project: project1, source_branch: 'tanuki-branch', title: 'tanuki') }
+
+ let(:params) { { project_id: project1.id, search: 'tanuki' } }
+
+ context 'with anonymous user' do
+ let(:merge_requests) { described_class.new(nil, params).execute }
+
+ context 'with disable_anonymous_search feature flag enabled' do
+ before do
+ stub_feature_flags(disable_anonymous_search: true)
+ end
+
+ it 'does not perform search' do
+ expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request6)
+ end
+ end
+
+ context 'with disable_anonymous_search feature flag disabled' do
+ before do
+ stub_feature_flags(disable_anonymous_search: false)
+ end
+
+ it 'returns matching merge requests' do
+ expect(merge_requests).to contain_exactly(merge_request6)
+ end
+ end
+ end
+ end
end
describe '#row_count', :request_store do
diff --git a/spec/finders/packages/helm/package_files_finder_spec.rb b/spec/finders/packages/helm/package_files_finder_spec.rb
index 2b84fd2b2d2..5f1378f837d 100644
--- a/spec/finders/packages/helm/package_files_finder_spec.rb
+++ b/spec/finders/packages/helm/package_files_finder_spec.rb
@@ -6,42 +6,51 @@ RSpec.describe ::Packages::Helm::PackageFilesFinder do
let_it_be(:project1) { create(:project) }
let_it_be(:project2) { create(:project) }
let_it_be(:helm_package) { create(:helm_package, project: project1) }
- let_it_be(:helm_package_file) { helm_package.package_files.first }
+ let_it_be(:helm_package_file1) { helm_package.package_files.first }
+ let_it_be(:helm_package_file2) { create(:helm_package_file, package: helm_package) }
let_it_be(:debian_package) { create(:debian_package, project: project1) }
- describe '#execute' do
- let(:project) { project1 }
- let(:channel) { 'stable' }
- let(:params) { {} }
+ let(:project) { project1 }
+ let(:channel) { 'stable' }
+ let(:params) { {} }
+
+ let(:service) { described_class.new(project, channel, params) }
- subject { described_class.new(project, channel, params).execute }
+ describe '#execute' do
+ subject { service.execute }
context 'with empty params' do
- it { is_expected.to match_array([helm_package_file]) }
+ it { is_expected.to eq([helm_package_file2, helm_package_file1]) }
end
context 'with another project' do
let(:project) { project2 }
- it { is_expected.to match_array([]) }
+ it { is_expected.to eq([]) }
end
context 'with another channel' do
let(:channel) { 'staging' }
- it { is_expected.to match_array([]) }
+ it { is_expected.to eq([]) }
end
- context 'with file_name' do
- let(:params) { { file_name: helm_package_file.file_name } }
+ context 'with matching file_name' do
+ let(:params) { { file_name: helm_package_file1.file_name } }
- it { is_expected.to match_array([helm_package_file]) }
+ it { is_expected.to eq([helm_package_file2, helm_package_file1]) }
end
context 'with another file_name' do
let(:params) { { file_name: 'foobar.tgz' } }
- it { is_expected.to match_array([]) }
+ it { is_expected.to eq([]) }
end
end
+
+ describe '#most_recent!' do
+ subject { service.most_recent! }
+
+ it { is_expected.to eq(helm_package_file2) }
+ end
end
diff --git a/spec/finders/packages/helm/packages_finder_spec.rb b/spec/finders/packages/helm/packages_finder_spec.rb
new file mode 100644
index 00000000000..5037a9e6205
--- /dev/null
+++ b/spec/finders/packages/helm/packages_finder_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Packages::Helm::PackagesFinder do
+ let_it_be(:project1) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:helm_package) { create(:helm_package, project: project1) }
+ let_it_be(:npm_package) { create(:npm_package, project: project1) }
+ let_it_be(:npm_package) { create(:npm_package, project: project2) }
+
+ let(:project) { project1 }
+ let(:channel) { 'stable' }
+ let(:finder) { described_class.new(project, channel) }
+
+ describe '#execute' do
+ subject { finder.execute }
+
+ context 'with project' do
+ context 'with channel' do
+ it { is_expected.to eq([helm_package]) }
+
+ context 'ignores duplicate package files' do
+ let_it_be(:package_file1) { create(:helm_package_file, package: helm_package) }
+ let_it_be(:package_file2) { create(:helm_package_file, package: helm_package) }
+
+ it { is_expected.to eq([helm_package]) }
+
+ context 'let clients use select id' do
+ subject { finder.execute.pluck_primary_key }
+
+ it { is_expected.to eq([helm_package.id]) }
+ end
+ end
+ end
+
+ context 'with not existing channel' do
+ let(:channel) { 'alpha' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with no channel' do
+ let(:channel) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with no helm packages' do
+ let(:project) { project2 }
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ context 'with no project' do
+ let(:project) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when the limit is hit' do
+ let_it_be(:helm_package2) { create(:helm_package, project: project1) }
+ let_it_be(:helm_package3) { create(:helm_package, project: project1) }
+ let_it_be(:helm_package4) { create(:helm_package, project: project1) }
+
+ before do
+ stub_const("#{described_class}::MAX_PACKAGES_COUNT", 2)
+ end
+
+ it { is_expected.to eq([helm_package4, helm_package3]) }
+ end
+ end
+end
diff --git a/spec/finders/packages/npm/package_finder_spec.rb b/spec/finders/packages/npm/package_finder_spec.rb
index a995f3b96c4..230d267e508 100644
--- a/spec/finders/packages/npm/package_finder_spec.rb
+++ b/spec/finders/packages/npm/package_finder_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe ::Packages::Npm::PackageFinder do
let(:project) { package.project }
let(:package_name) { package.name }
+ let(:last_of_each_version) { true }
shared_examples 'accepting a namespace for' do |example_name|
before do
@@ -38,6 +39,8 @@ RSpec.describe ::Packages::Npm::PackageFinder do
end
describe '#execute' do
+ subject { finder.execute }
+
shared_examples 'finding packages by name' do
it { is_expected.to eq([package]) }
@@ -56,13 +59,27 @@ RSpec.describe ::Packages::Npm::PackageFinder do
end
end
- subject { finder.execute }
+ shared_examples 'handling last_of_each_version' do
+ include_context 'last_of_each_version setup context'
+
+ context 'disabled' do
+ let(:last_of_each_version) { false }
+
+ it { is_expected.to contain_exactly(package1, package2) }
+ end
+
+ context 'enabled' do
+ it { is_expected.to contain_exactly(package2) }
+ end
+ end
context 'with a project' do
- let(:finder) { described_class.new(package_name, project: project) }
+ let(:finder) { described_class.new(package_name, project: project, last_of_each_version: last_of_each_version) }
it_behaves_like 'finding packages by name'
+ it_behaves_like 'handling last_of_each_version'
+
context 'set to nil' do
let(:project) { nil }
@@ -71,10 +88,12 @@ RSpec.describe ::Packages::Npm::PackageFinder do
end
context 'with a namespace' do
- let(:finder) { described_class.new(package_name, namespace: namespace) }
+ let(:finder) { described_class.new(package_name, namespace: namespace, last_of_each_version: last_of_each_version) }
it_behaves_like 'accepting a namespace for', 'finding packages by name'
+ it_behaves_like 'accepting a namespace for', 'handling last_of_each_version'
+
context 'set to nil' do
let_it_be(:namespace) { nil }
@@ -98,16 +117,28 @@ RSpec.describe ::Packages::Npm::PackageFinder do
end
end
+ shared_examples 'handling last_of_each_version' do
+ include_context 'last_of_each_version setup context'
+
+ context 'enabled' do
+ it { is_expected.to eq(package2) }
+ end
+ end
+
context 'with a project' do
- let(:finder) { described_class.new(package_name, project: project) }
+ let(:finder) { described_class.new(package_name, project: project, last_of_each_version: last_of_each_version) }
it_behaves_like 'finding packages by version'
+
+ it_behaves_like 'handling last_of_each_version'
end
context 'with a namespace' do
- let(:finder) { described_class.new(package_name, namespace: namespace) }
+ let(:finder) { described_class.new(package_name, namespace: namespace, last_of_each_version: last_of_each_version) }
it_behaves_like 'accepting a namespace for', 'finding packages by version'
+
+ it_behaves_like 'accepting a namespace for', 'handling last_of_each_version'
end
end
@@ -118,10 +149,26 @@ RSpec.describe ::Packages::Npm::PackageFinder do
it { is_expected.to eq(package) }
end
+ shared_examples 'handling last_of_each_version' do
+ include_context 'last_of_each_version setup context'
+
+ context 'disabled' do
+ let(:last_of_each_version) { false }
+
+ it { is_expected.to eq(package2) }
+ end
+
+ context 'enabled' do
+ it { is_expected.to eq(package2) }
+ end
+ end
+
context 'with a project' do
- let(:finder) { described_class.new(package_name, project: project) }
+ let(:finder) { described_class.new(package_name, project: project, last_of_each_version: last_of_each_version) }
it_behaves_like 'finding package by last'
+
+ it_behaves_like 'handling last_of_each_version'
end
context 'with a namespace' do
@@ -129,6 +176,8 @@ RSpec.describe ::Packages::Npm::PackageFinder do
it_behaves_like 'accepting a namespace for', 'finding package by last'
+ it_behaves_like 'accepting a namespace for', 'handling last_of_each_version'
+
context 'with duplicate packages' do
let_it_be(:namespace) { create(:group) }
let_it_be(:subgroup1) { create(:group, parent: namespace) }
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 21b5b2f6130..d26180bbf94 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -135,6 +135,7 @@ RSpec.describe ProjectsFinder do
describe 'filter by tags (deprecated)' do
before do
+ public_project.reload
public_project.topic_list = 'foo'
public_project.save!
end
@@ -146,6 +147,7 @@ RSpec.describe ProjectsFinder do
describe 'filter by topics' do
before do
+ public_project.reload
public_project.topic_list = 'foo, bar'
public_project.save!
end
@@ -188,6 +190,32 @@ RSpec.describe ProjectsFinder do
it { is_expected.to eq([public_project]) }
end
+ context 'with anonymous user' do
+ let(:public_project_2) { create(:project, :public, group: group, name: 'E', path: 'E') }
+ let(:current_user) { nil }
+ let(:params) { { search: 'C' } }
+
+ context 'with disable_anonymous_project_search feature flag enabled' do
+ before do
+ stub_feature_flags(disable_anonymous_project_search: true)
+ end
+
+ it 'does not perform search' do
+ is_expected.to eq([public_project_2, public_project])
+ end
+ end
+
+ context 'with disable_anonymous_project_search feature flag disabled' do
+ before do
+ stub_feature_flags(disable_anonymous_project_search: false)
+ end
+
+ it 'finds one public project' do
+ is_expected.to eq([public_project])
+ end
+ end
+ end
+
describe 'filter by name for backward compatibility' do
let(:params) { { name: 'C' } }
diff --git a/spec/finders/repositories/tree_finder_spec.rb b/spec/finders/repositories/tree_finder_spec.rb
new file mode 100644
index 00000000000..0d70d5f92d3
--- /dev/null
+++ b/spec/finders/repositories/tree_finder_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Repositories::TreeFinder do
+ include RepoHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, creator: user) }
+
+ let(:repository) { project.repository }
+ let(:tree_finder) { described_class.new(project, params) }
+ let(:params) { {} }
+ let(:first_page_ids) { tree_finder.execute.map(&:id) }
+ let(:second_page_token) { first_page_ids.last }
+
+ describe "#execute" do
+ subject { tree_finder.execute(gitaly_pagination: true) }
+
+ it "returns an array" do
+ is_expected.to be_an(Array)
+ end
+
+ it "includes 20 items by default" do
+ expect(subject.size).to eq(20)
+ end
+
+ it "accepts a gitaly_pagination argument" do
+ expect(repository).to receive(:tree).with(anything, anything, recursive: nil, pagination_params: { limit: 20, page_token: nil }).and_call_original
+ expect(tree_finder.execute(gitaly_pagination: true)).to be_an(Array)
+
+ expect(repository).to receive(:tree).with(anything, anything, recursive: nil).and_call_original
+ expect(tree_finder.execute(gitaly_pagination: false)).to be_an(Array)
+ end
+
+ context "commit doesn't exist" do
+ let(:params) do
+ { ref: "nonesuchref" }
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(described_class::CommitMissingError)
+ end
+ end
+
+ describe "pagination_params" do
+ let(:params) do
+ { per_page: 5, page_token: nil }
+ end
+
+ it "has the per_page number of items" do
+ expect(subject.size).to eq(5)
+ end
+
+ it "doesn't include any of the first page records" do
+ first_page_ids = subject.map(&:id)
+ second_page = described_class.new(project, { per_page: 5, page_token: first_page_ids.last }).execute(gitaly_pagination: true)
+
+ expect(second_page.map(&:id)).not_to include(*first_page_ids)
+ end
+ end
+ end
+
+ describe "#total", :use_clean_rails_memory_store_caching do
+ subject { tree_finder.total }
+
+ it { is_expected.to be_an(Integer) }
+
+ it "only calculates the total once" do
+ expect(repository).to receive(:tree).once.and_call_original
+
+ 2.times { tree_finder.total }
+ end
+ end
+
+ describe "#commit_exists?" do
+ subject { tree_finder.commit_exists? }
+
+ context "ref exists" do
+ let(:params) do
+ { ref: project.default_branch }
+ end
+
+ it { is_expected.to be(true) }
+ end
+
+ context "ref is missing" do
+ let(:params) do
+ { ref: "nonesuchref" }
+ end
+
+ it { is_expected.to be(false) }
+ end
+ end
+end