diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 20:02:30 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 20:02:30 +0000 |
commit | 41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch) | |
tree | 9c8d89a8624828992f06d892cd2f43818ff5dcc8 /spec/finders | |
parent | 0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff) | |
download | gitlab-ce-41fe97390ceddf945f3d967b8fdb3de4c66b7dea.tar.gz |
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'spec/finders')
-rw-r--r-- | spec/finders/issues_finder_spec.rb | 45 | ||||
-rw-r--r-- | spec/finders/pending_todos_finder_spec.rb | 10 | ||||
-rw-r--r-- | spec/finders/personal_access_tokens_finder_spec.rb | 21 | ||||
-rw-r--r-- | spec/finders/projects/members/effective_access_level_finder_spec.rb | 41 | ||||
-rw-r--r-- | spec/finders/projects/topics_finder_spec.rb | 6 | ||||
-rw-r--r-- | spec/finders/releases/group_releases_finder_spec.rb | 204 | ||||
-rw-r--r-- | spec/finders/releases_finder_spec.rb | 13 |
7 files changed, 297 insertions, 43 deletions
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index c22e56c3b9e..aa9357a686a 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -588,10 +588,37 @@ RSpec.describe IssuesFinder do end context 'filtering by issue term' do - let(:params) { { search: 'git' } } + let(:params) { { search: search_term } } - it 'returns issues with title and description match for search term' do - expect(issues).to contain_exactly(issue1, issue2) + let_it_be(:english) { create(:issue, project: project1, title: 'title', description: 'something english') } + let_it_be(:japanese) { create(:issue, project: project1, title: '日本語 title', description: 'another english description') } + + context 'with latin search term' do + let(:search_term) { 'title english' } + + it 'returns matching issues' do + expect(issues).to contain_exactly(english, japanese) + end + end + + context 'with non-latin search term' do + let(:search_term) { '日本語' } + + it 'returns matching issues' do + expect(issues).to contain_exactly(japanese) + end + end + + context 'when full-text search is disabled' do + let(:search_term) { 'somet' } + + before do + stub_feature_flags(issues_full_text_search: false) + end + + it 'allows partial word matches' do + expect(issues).to contain_exactly(english) + end end context 'with anonymous user' do @@ -1257,7 +1284,7 @@ RSpec.describe IssuesFinder do end context 'when the force_cte param is falsey' do - let(:params) { { search: 'foo' } } + let(:params) { { search: '日本語' } } it 'returns false' do expect(finder.use_cte_for_search?).to be_falsey @@ -1265,7 +1292,7 @@ RSpec.describe IssuesFinder do end context 'when a non-simple sort is given' do - let(:params) { { search: 'foo', attempt_project_search_optimizations: true, sort: 'popularity' } } + let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: 'popularity' } } it 'returns false' do expect(finder.use_cte_for_search?).to be_falsey @@ -1274,7 +1301,7 @@ RSpec.describe IssuesFinder do context 'when all conditions are met' do context "uses group search optimization" do - let(:params) { { search: 'foo', attempt_group_search_optimizations: true } } + let(:params) { { search: '日本語', attempt_group_search_optimizations: true } } it 'returns true' do expect(finder.use_cte_for_search?).to be_truthy @@ -1283,7 +1310,7 @@ RSpec.describe IssuesFinder do end context "uses project search optimization" do - let(:params) { { search: 'foo', attempt_project_search_optimizations: true } } + let(:params) { { search: '日本語', attempt_project_search_optimizations: true } } it 'returns true' do expect(finder.use_cte_for_search?).to be_truthy @@ -1292,7 +1319,7 @@ RSpec.describe IssuesFinder do end context 'with simple sort' do - let(:params) { { search: 'foo', attempt_project_search_optimizations: true, sort: 'updated_desc' } } + let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: 'updated_desc' } } it 'returns true' do expect(finder.use_cte_for_search?).to be_truthy @@ -1301,7 +1328,7 @@ RSpec.describe IssuesFinder do end context 'with simple sort as a symbol' do - let(:params) { { search: 'foo', attempt_project_search_optimizations: true, sort: :updated_desc } } + let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: :updated_desc } } it 'returns true' do expect(finder.use_cte_for_search?).to be_truthy diff --git a/spec/finders/pending_todos_finder_spec.rb b/spec/finders/pending_todos_finder_spec.rb index f317d8b1633..4f4862852f4 100644 --- a/spec/finders/pending_todos_finder_spec.rb +++ b/spec/finders/pending_todos_finder_spec.rb @@ -75,5 +75,15 @@ RSpec.describe PendingTodosFinder do expect(todos).to contain_exactly(todo1, todo2) end + + it 'supports retrieving of todos for a specific action' do + todo = create(:todo, :pending, user: user, target: issue, action: Todo::MENTIONED) + + create(:todo, :pending, user: user, target: issue, action: Todo::ASSIGNED) + + todos = described_class.new(users, action: Todo::MENTIONED).execute + + expect(todos).to contain_exactly(todo) + end end end diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb index cece80047e1..7607d08dc64 100644 --- a/spec/finders/personal_access_tokens_finder_spec.rb +++ b/spec/finders/personal_access_tokens_finder_spec.rb @@ -17,6 +17,9 @@ RSpec.describe PersonalAccessTokensFinder do let!(:active_impersonation_token) { create(:personal_access_token, :impersonation, user: user) } let!(:expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user) } let!(:revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user) } + let!(:project_bot) { create(:user, :project_bot) } + let!(:project_member) { create(:project_member, user: project_bot) } + let!(:project_access_token) { create(:personal_access_token, user: project_bot) } subject { finder(params, current_user).execute } @@ -44,7 +47,7 @@ RSpec.describe PersonalAccessTokensFinder do it do 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) + revoked_impersonation_token, expired_impersonation_token, project_access_token) end context 'when current_user is not an administrator' do @@ -59,7 +62,7 @@ RSpec.describe PersonalAccessTokensFinder do it do 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) + revoked_impersonation_token, expired_impersonation_token, project_access_token) end describe 'with users' do @@ -98,14 +101,14 @@ RSpec.describe PersonalAccessTokensFinder do params[:impersonation] = false end - it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) } + it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token, project_access_token) } describe 'with active state' do before do params[:state] = 'active' end - it { is_expected.to contain_exactly(active_personal_access_token) } + it { is_expected.to contain_exactly(active_personal_access_token, project_access_token) } end describe 'with inactive state' do @@ -146,7 +149,7 @@ RSpec.describe PersonalAccessTokensFinder do params[:state] = 'active' end - it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) } + it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token, project_access_token) } end describe 'with inactive state' do @@ -208,6 +211,14 @@ RSpec.describe PersonalAccessTokensFinder do revoked_impersonation_token, expired_impersonation_token) end + describe 'filtering human tokens' do + before do + params[:owner_type] = 'human' + end + + it { is_expected.not_to include(project_access_token) } + end + describe 'without impersonation' do before do params[:impersonation] = false diff --git a/spec/finders/projects/members/effective_access_level_finder_spec.rb b/spec/finders/projects/members/effective_access_level_finder_spec.rb index 33fbb5aca30..bec327835f6 100644 --- a/spec/finders/projects/members/effective_access_level_finder_spec.rb +++ b/spec/finders/projects/members/effective_access_level_finder_spec.rb @@ -11,13 +11,13 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do context 'for a personal project' do let_it_be(:project) { create(:project) } - shared_examples_for 'includes access level of the owner of the project as Maintainer' do - it 'includes access level of the owner of the project as Maintainer' do + shared_examples_for 'includes access level of the owner of the project' do + it 'includes access level of the owner of the project as Owner' do expect(subject).to( contain_exactly( hash_including( 'user_id' => project.namespace.owner.id, - 'access_level' => Gitlab::Access::MAINTAINER + 'access_level' => Gitlab::Access::OWNER ) ) ) @@ -25,7 +25,7 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do end context 'when the project owner is a member of the project' do - it_behaves_like 'includes access level of the owner of the project as Maintainer' + it_behaves_like 'includes access level of the owner of the project' end context 'when the project owner is not explicitly a member of the project' do @@ -33,7 +33,7 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do project.members.find_by(user_id: project.namespace.owner.id).destroy! end - it_behaves_like 'includes access level of the owner of the project as Maintainer' + it_behaves_like 'includes access level of the owner of the project' end end @@ -84,17 +84,32 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do context 'for a project within a group' do context 'project in a root group' do - it 'includes access levels of users who are direct members of the parent group' do - group_member = create(:group_member, :developer, source: group) + context 'includes access levels of users who are direct members of the parent group' do + it 'when access level is developer' do + group_member = create(:group_member, :developer, source: group) - expect(subject).to( - include( - hash_including( - 'user_id' => group_member.user.id, - 'access_level' => Gitlab::Access::DEVELOPER + expect(subject).to( + include( + hash_including( + 'user_id' => group_member.user.id, + 'access_level' => Gitlab::Access::DEVELOPER + ) ) ) - ) + end + + it 'when access level is owner' do + group_member = create(:group_member, :owner, source: group) + + expect(subject).to( + include( + hash_including( + 'user_id' => group_member.user.id, + 'access_level' => Gitlab::Access::OWNER + ) + ) + ) + end end end diff --git a/spec/finders/projects/topics_finder_spec.rb b/spec/finders/projects/topics_finder_spec.rb index 28802c5d49e..3812f0757bc 100644 --- a/spec/finders/projects/topics_finder_spec.rb +++ b/spec/finders/projects/topics_finder_spec.rb @@ -9,9 +9,9 @@ RSpec.describe Projects::TopicsFinder do let!(:topic2) { create(:topic, name: 'topicC') } let!(:topic3) { create(:topic, name: 'topicA') } - let!(:project1) { create(:project, namespace: user.namespace, topic_list: 'topicC, topicA, topicB') } - let!(:project2) { create(:project, namespace: user.namespace, topic_list: 'topicC, topicA') } - let!(:project3) { create(:project, namespace: user.namespace, topic_list: 'topicC') } + let!(:project1) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA, topicB') } + let!(:project2) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA') } + let!(:project3) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC') } describe '#execute' do it 'returns topics' do diff --git a/spec/finders/releases/group_releases_finder_spec.rb b/spec/finders/releases/group_releases_finder_spec.rb new file mode 100644 index 00000000000..b8899a8ee40 --- /dev/null +++ b/spec/finders/releases/group_releases_finder_spec.rb @@ -0,0 +1,204 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Releases::GroupReleasesFinder do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:project) { create(:project, :repository, group: group) } + let(:params) { {} } + let(:args) { {} } + let(:repository) { project.repository } + let(:v1_0_0) { create(:release, project: project, tag: 'v1.0.0') } + let(:v1_1_0) { create(:release, project: project, tag: 'v1.1.0') } + let(:v1_1_1) { create(:release, project: project, tag: 'v1.1.1') } + + before do + v1_0_0.update_attribute(:released_at, 2.days.ago) + v1_1_0.update_attribute(:released_at, 1.day.ago) + v1_1_1.update_attribute(:released_at, 0.5.days.ago) + end + + shared_examples_for 'when the user is not part of the project' do + it 'returns no releases' do + is_expected.to be_empty + end + end + + shared_examples_for 'when the user is not part of the group' do + before do + allow(Ability).to receive(:allowed?).with(user, :read_release, group).and_return(false) + end + + it 'returns no releases' do + is_expected.to be_empty + end + end + + shared_examples_for 'preload' do + before do + allow(Ability).to receive(:allowed?).with(user, :read_release, group).and_return(true) + end + + it 'preloads associations' do + expect(Release).to receive(:preloaded).once.and_call_original + + releases + end + + context 'when preload is false' do + let(:args) { { preload: false } } + + it 'does not preload associations' do + expect(Release).not_to receive(:preloaded) + + releases + end + end + end + + describe 'when parent is a group' do + context 'without subgroups' do + let(:project2) { create(:project, :repository, namespace: group) } + let!(:v6) { create(:release, project: project2, tag: 'v6') } + + subject(:releases) { described_class.new(group, user, params).execute(**args) } + + it_behaves_like 'preload' + it_behaves_like 'when the user is not part of the group' + + context 'when the user is a project guest on one sibling project' do + before do + project.add_guest(user) + end + + it 'does not return any releases' do + expect(releases.size).to eq(0) + expect(releases).to eq([]) + end + end + + context 'when the user is a guest on the group' do + before do + group.add_guest(user) + v1_0_0.update_attribute(:released_at, 3.days.ago) + v6.update_attribute(:released_at, 2.days.ago) + v1_1_0.update_attribute(:released_at, 1.day.ago) + v1_1_1.update_attribute(:released_at, v1_1_0.released_at) + end + + it 'sorts by release date and id' do + expect(releases.size).to eq(4) + expect(releases).to eq([v1_1_1, v1_1_0, v6, v1_0_0]) + end + end + end + + describe 'with subgroups' do + let(:params) { { include_subgroups: true } } + + subject(:releases) { described_class.new(group, user, params).execute(**args) } + + context 'with a single-level subgroup' do + let(:subgroup) { create(:group, parent: group) } + let(:project2) { create(:project, :repository, namespace: subgroup) } + let!(:v6) { create(:release, project: project2, tag: 'v6') } + + it_behaves_like 'when the user is not part of the group' + + context 'when the user a project guest in the subgroup project' do + before do + project2.add_guest(user) + end + + it 'does not return any releases' do + expect(releases).to match_array([]) + end + end + + context 'when the user is a guest on the group' do + before do + group.add_guest(user) + v6.update_attribute(:released_at, 2.days.ago) + end + + it 'returns all releases' do + expect(releases).to match_array([v1_1_1, v1_1_0, v1_0_0, v6]) + end + end + end + + context 'with a multi-level subgroup' do + let(:subgroup) { create(:group, parent: group) } + let(:subsubgroup) { create(:group, parent: subgroup) } + let(:project2) { create(:project, :repository, namespace: subgroup) } + let(:project3) { create(:project, :repository, namespace: subsubgroup) } + let!(:v6) { create(:release, project: project2, tag: 'v6') } + let!(:p3) { create(:release, project: project3, tag: 'p3') } + + before do + v6.update_attribute(:released_at, 2.days.ago) + p3.update_attribute(:released_at, 3.days.ago) + end + + it_behaves_like 'when the user is not part of the group' + + context 'when the user a project guest in the subgroup and subsubgroup project' do + before do + project2.add_guest(user) + project3.add_guest(user) + end + + it 'does not return any releases' do + expect(releases).to match_array([]) + end + end + + context 'when the user a project guest in the subsubgroup project' do + before do + project3.add_guest(user) + end + + it 'does not return any releases' do + expect(releases).to match_array([]) + end + end + + context 'when the user a guest on the group' do + before do + group.add_guest(user) + end + + it 'returns all releases' do + expect(releases).to match_array([v1_1_1, v1_1_0, v6, v1_0_0, p3]) + end + end + + context 'performance testing' do + shared_examples 'avoids N+1 queries' do |query_params = {}| + context 'with subgroups' do + let(:params) { query_params } + + it 'include_subgroups avoids N+1 queries' do + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do + releases + end.count + + subgroups = create_list(:group, 10, parent: group) + projects = create_list(:project, 10, namespace: subgroups[0]) + create_list(:release, 10, project: projects[0], author: user) + + expect do + releases + end.not_to exceed_all_query_limit(control_count) + end + end + end + + it_behaves_like 'avoids N+1 queries' + it_behaves_like 'avoids N+1 queries', { simple: true } + end + end + end + end +end diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb index 5ddb5c33fad..b0fa1177245 100644 --- a/spec/finders/releases_finder_spec.rb +++ b/spec/finders/releases_finder_spec.rb @@ -33,18 +33,6 @@ RSpec.describe ReleasesFinder do end end - # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27716 - shared_examples_for 'when tag is nil' do - before do - v1_0_0.update_column(:tag, nil) - end - - it 'ignores rows with a nil tag' do - expect(subject.size).to eq(1) - expect(subject).to eq([v1_1_0]) - end - end - shared_examples_for 'when a tag parameter is passed' do let(:params) { { tag: 'v1.0.0' } } @@ -116,7 +104,6 @@ RSpec.describe ReleasesFinder do end it_behaves_like 'preload' - it_behaves_like 'when tag is nil' it_behaves_like 'when a tag parameter is passed' end end |