Commit 9fad3ac5 authored by Mark Chao's avatar Mark Chao

Merge branch '249515-global-search-admin-should-use-any' into 'master'

Fix performance issue with global search + refactor

Closes #249515

See merge request gitlab-org/gitlab!42437
parents 46a37904 9b58848a
......@@ -4,6 +4,7 @@ module Search
module Elasticsearchable
def use_elasticsearch?
return false if params[:basic_search]
return false if params[:scope] == 'users'
::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: elasticsearchable_scope)
end
......
......@@ -14,7 +14,7 @@ module EE
::Gitlab::Elastic::SearchResults.new(
current_user,
params[:search],
projects,
elastic_projects,
public_and_internal_projects: elastic_global,
filters: { state: params[:state] }
)
......@@ -28,6 +28,25 @@ module EE
true
end
def elastic_projects
# For elasticsearch we need the list of projects to be as small as
# possible since they are loaded from the DB and sent in the
# Elasticsearch query. It should only be strictly the project IDs the
# user has been given authorization for. The Elasticsearch query will
# additionally take care of public projects. This behaves differently
# to the searching Postgres case in which this list of projects is
# intended to be all projects that should appear in the results.
strong_memoize(:elastic_projects) do
if current_user&.can_read_all_resources?
:any
elsif current_user
current_user.authorized_projects.pluck(:id) # rubocop: disable CodeReuse/ActiveRecord
else
[]
end
end
end
override :allowed_scopes
def allowed_scopes
return super unless use_elasticsearch?
......
......@@ -15,6 +15,11 @@ module EE
false
end
override :elastic_projects
def elastic_projects
@elastic_projects ||= projects.pluck_primary_key
end
override :execute
def execute
return super unless use_elasticsearch?
......@@ -22,7 +27,7 @@ module EE
::Gitlab::Elastic::GroupSearchResults.new(
current_user,
params[:search],
projects,
elastic_projects,
group: group,
public_and_internal_projects: elastic_global,
filters: { state: params[:state] }
......
---
title: Fix poor performance with global search across entire instance
merge_request: 42437
author:
type: performance
......@@ -6,27 +6,14 @@ module Gitlab
# superclass inside a module, because autoloading can occur in a
# different order between execution environments.
class GroupSearchResults < Gitlab::Elastic::SearchResults
delegate :users, to: :generic_search_results
delegate :limited_users_count, to: :generic_search_results
attr_reader :group, :default_project_filter, :filters
def initialize(current_user, query, limit_projects = nil, group:, public_and_internal_projects: false, default_project_filter: false, filters: {})
def initialize(current_user, query, limit_project_ids = nil, group:, public_and_internal_projects: false, default_project_filter: false, filters: {})
@group = group
@default_project_filter = default_project_filter
@filters = filters
super(current_user, query, limit_projects, public_and_internal_projects: public_and_internal_projects, filters: filters)
end
def generic_search_results
@generic_search_results ||= Gitlab::GroupSearchResults.new(
current_user,
query,
limit_projects,
group: group,
filters: filters
)
super(current_user, query, limit_project_ids, public_and_internal_projects: public_and_internal_projects, filters: filters)
end
end
end
......
......@@ -8,24 +8,11 @@ module Gitlab
class ProjectSearchResults < Gitlab::Elastic::SearchResults
attr_reader :project, :repository_ref, :filters
delegate :users, to: :generic_search_results
delegate :limited_users_count, to: :generic_search_results
def initialize(current_user, query, project:, repository_ref: nil, filters: {})
@project = project
@repository_ref = repository_ref.presence || project.default_branch
super(current_user, query, [project], public_and_internal_projects: false, filters: filters)
end
def generic_search_results
@generic_search_results ||= Gitlab::ProjectSearchResults.new(
current_user,
query,
project: project,
repository_ref: repository_ref,
filters: filters
)
super(current_user, query, [project.id], public_and_internal_projects: false, filters: filters)
end
private
......
......@@ -11,15 +11,12 @@ module Gitlab
# Limit search results by passed projects
# It allows us to search only for projects user has access to
attr_reader :limit_projects
attr_reader :limit_project_ids
delegate :users, to: :generic_search_results
delegate :limited_users_count, to: :generic_search_results
def initialize(current_user, query, limit_projects = nil, public_and_internal_projects: true, filters: {})
def initialize(current_user, query, limit_project_ids = nil, public_and_internal_projects: true, filters: {})
@current_user = current_user
@query = query
@limit_projects = limit_projects
@limit_project_ids = limit_project_ids
@public_and_internal_projects = public_and_internal_projects
@filters = filters
end
......@@ -44,17 +41,11 @@ module Gitlab
wiki_blobs(page: page, per_page: per_page)
when 'commits'
commits(page: page, per_page: per_page, preload_method: preload_method)
when 'users'
users.page(page).per(per_page)
else
Kaminari.paginate_array([])
end
end
def generic_search_results
@generic_search_results ||= Gitlab::SearchResults.new(current_user, query, limit_projects)
end
def formatted_count(scope)
case scope
when 'projects'
......@@ -73,8 +64,6 @@ module Gitlab
merge_requests_count.to_s
when 'milestones'
milestones_count.to_s
when 'users'
generic_search_results.formatted_count('users')
end
end
......@@ -176,20 +165,6 @@ module Gitlab
private
# Convert the `limit_projects` to a list of ids for Elasticsearch
def limit_project_ids
strong_memoize(:limit_project_ids) do
case limit_projects
when :any then :any
when ActiveRecord::Relation
limit_projects.pluck_primary_key if limit_projects.model == Project
when Array
limit_projects.all? { |x| x.is_a?(Project) } ? limit_projects.map(&:id) : []
else []
end
end
end
# Apply some eager loading to the `records` of an ES result object without
# losing pagination information. Also, take advantage of preload method if
# provided by the caller.
......
......@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Elastic::GroupSearchResults, :elastic do
let(:filters) { {} }
let(:query) { '*' }
subject(:results) { described_class.new(user, query, Project.all, group: group, filters: filters) }
subject(:results) { described_class.new(user, query, Project.all.pluck_primary_key, group: group, filters: filters) }
before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
......@@ -45,32 +45,6 @@ RSpec.describe Gitlab::Elastic::GroupSearchResults, :elastic do
end
end
context 'user search' do
let(:query) { guest.username }
before do
expect(Gitlab::GroupSearchResults).to receive(:new).and_call_original
end
it { expect(results.objects('users')).to contain_exactly(guest) }
it { expect(results.limited_users_count).to eq(1) }
describe 'pagination' do
let(:query) {}
let_it_be(:user2) { create(:user).tap { |u| group.add_user(u, Gitlab::Access::REPORTER) } }
it 'returns the correct page of results' do
expect(results.objects('users', page: 1, per_page: 1)).to contain_exactly(user2)
expect(results.objects('users', page: 2, per_page: 1)).to contain_exactly(guest)
end
it 'returns the correct number of results for one page' do
expect(results.objects('users', page: 1, per_page: 2).count).to eq(2)
end
end
end
context 'query performance' do
include_examples 'does not hit Elasticsearch twice for objects and counts', %w|projects notes blobs wiki_blobs commits issues merge_requests milestones|
end
......
......@@ -167,33 +167,6 @@ RSpec.describe Gitlab::Elastic::ProjectSearchResults, :elastic do
end
end
context 'user search' do
let(:query) { project.owner.username }
before do
expect(Gitlab::ProjectSearchResults).to receive(:new).and_call_original
end
it { expect(results.objects('users')).to eq([project.owner]) }
it { expect(results.limited_users_count).to eq(1) }
describe 'pagination' do
let(:query) { }
let_it_be(:user2) { create(:user).tap { |u| project.add_user(u, Gitlab::Access::REPORTER) } }
it 'returns the correct page of results' do
# UsersFinder defaults to order_id_desc, the newer result will be first
expect(results.objects('users', page: 1, per_page: 1)).to eq([user2])
expect(results.objects('users', page: 2, per_page: 1)).to eq([project.owner])
end
it 'returns the correct number of results for one page' do
expect(results.objects('users', page: 1, per_page: 2).count).to eq(2)
end
end
end
context 'query performance' do
let(:project) { create(:project, :public, :repository, :wiki_repo) }
let(:query) { '*' }
......
......@@ -10,12 +10,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:user) { create(:user) }
let(:project_1) { create(:project, :public, :repository, :wiki_repo) }
let(:project_2) { create(:project, :public, :repository, :wiki_repo) }
let(:limit_projects) { [project_1] }
let(:limit_project_ids) { [project_1.id] }
describe '#formatted_count' do
using RSpec::Parameterized::TableSyntax
let(:results) { described_class.new(user, 'hello world', limit_projects) }
let(:results) { described_class.new(user, 'hello world', limit_project_ids) }
where(:scope, :count_method, :expected) do
'projects' | :projects_count | '1234'
......@@ -35,15 +35,10 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
expect(results.formatted_count(scope)).to eq(expected)
end
end
it 'delegates to generic_search_results for users' do
expect(results.generic_search_results).to receive(:formatted_count).with('users').and_return('1000+')
expect(results.formatted_count('users')).to eq('1000+')
end
end
shared_examples_for 'a paginated object' do |object_type|
let(:results) { described_class.new(user, 'hello world', limit_projects) }
let(:results) { described_class.new(user, 'hello world', limit_project_ids) }
it 'does not explode when given a page as a string' do
expect { results.objects(object_type, page: "2") }.not_to raise_error
......@@ -135,7 +130,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'issues'
it 'lists found issues' do
results = described_class.new(user, 'hello world', limit_projects)
results = described_class.new(user, 'hello world', limit_project_ids)
issues = results.objects('issues')
expect(issues).to contain_exactly(@issue_1, @issue_2)
......@@ -143,14 +138,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'returns empty list when issues are not found' do
results = described_class.new(user, 'security', limit_projects)
results = described_class.new(user, 'security', limit_project_ids)
expect(results.objects('issues')).to be_empty
expect(results.issues_count).to eq 0
end
it 'lists issue when search by a valid iid' do
results = described_class.new(user, '#2', limit_projects, public_and_internal_projects: false)
results = described_class.new(user, '#2', limit_project_ids, public_and_internal_projects: false)
issues = results.objects('issues')
expect(issues).to contain_exactly(@issue_2)
......@@ -158,7 +153,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'can also find an issue by iid without the prefixed #' do
results = described_class.new(user, '2', limit_projects, public_and_internal_projects: false)
results = described_class.new(user, '2', limit_project_ids, public_and_internal_projects: false)
issues = results.objects('issues')
expect(issues).to contain_exactly(@issue_2)
......@@ -166,7 +161,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'returns empty list when search by invalid iid' do
results = described_class.new(user, '#222', limit_projects)
results = described_class.new(user, '#222', limit_project_ids)
expect(results.objects('issues')).to be_empty
expect(results.issues_count).to eq 0
......@@ -217,7 +212,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'notes'
it 'lists found notes' do
results = described_class.new(user, 'foo', limit_projects)
results = described_class.new(user, 'foo', limit_project_ids)
notes = results.objects('notes')
expect(notes).to include @note_1
......@@ -227,7 +222,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'returns empty list when notes are not found' do
results = described_class.new(user, 'security', limit_projects)
results = described_class.new(user, 'security', limit_project_ids)
expect(results.objects('notes')).to be_empty
expect(results.notes_count).to eq 0
......@@ -237,7 +232,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
describe 'confidential issues' do
let(:project_3) { create(:project, :public) }
let(:project_4) { create(:project, :public) }
let(:limit_projects) { [project_1, project_2, project_3] }
let(:limit_project_ids) { [project_1.id, project_2.id, project_3.id] }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:non_member) { create(:user) }
......@@ -259,7 +254,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:query) { 'issue' }
it 'does not list confidential issues for guests' do
results = described_class.new(nil, query, limit_projects)
results = described_class.new(nil, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -272,7 +267,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'does not list confidential issues for non project members' do
results = described_class.new(non_member, query, limit_projects)
results = described_class.new(non_member, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -285,7 +280,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists confidential issues for author' do
results = described_class.new(author, query, limit_projects)
results = described_class.new(author, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -298,7 +293,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists confidential issues for assignee' do
results = described_class.new(assignee, query, limit_projects)
results = described_class.new(assignee, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -314,7 +309,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_1.add_developer(member)
project_2.add_developer(member)
results = described_class.new(member, query, limit_projects)
results = described_class.new(member, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -327,7 +322,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists all issues for admin' do
results = described_class.new(admin, query, limit_projects)
results = described_class.new(admin, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -344,7 +339,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:query) { '#1' }
it 'does not list confidential issues for guests' do
results = described_class.new(nil, query, limit_projects)
results = described_class.new(nil, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -357,7 +352,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'does not list confidential issues for non project members' do
results = described_class.new(non_member, query, limit_projects)
results = described_class.new(non_member, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -370,7 +365,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists confidential issues for author' do
results = described_class.new(author, query, limit_projects)
results = described_class.new(author, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -383,7 +378,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists confidential issues for assignee' do
results = described_class.new(assignee, query, limit_projects)
results = described_class.new(assignee, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -399,7 +394,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_developer(member)
project_3.add_developer(member)
results = described_class.new(member, query, limit_projects)
results = described_class.new(member, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -412,7 +407,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'lists all issues for admin' do
results = described_class.new(admin, query, limit_projects)
results = described_class.new(admin, query, limit_project_ids)
issues = results.objects('issues')
expect(issues).to include @issue
......@@ -458,7 +453,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'merge_requests'
it 'lists found merge requests' do
results = described_class.new(user, 'hello world', limit_projects, public_and_internal_projects: false)
results = described_class.new(user, 'hello world', limit_project_ids, public_and_internal_projects: false)
merge_requests = results.objects('merge_requests')
expect(merge_requests).to contain_exactly(@merge_request_1, @merge_request_2)
......@@ -466,14 +461,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'returns empty list when merge requests are not found' do
results = described_class.new(user, 'security', limit_projects)
results = described_class.new(user, 'security', limit_project_ids)
expect(results.objects('merge_requests')).to be_empty
expect(results.merge_requests_count).to eq 0
end
it 'lists merge request when search by a valid iid' do
results = described_class.new(user, '!2', limit_projects, public_and_internal_projects: false)
results = described_class.new(user, '!2', limit_project_ids, public_and_internal_projects: false)
merge_requests = results.objects('merge_requests')
expect(merge_requests).to contain_exactly(@merge_request_2)
......@@ -481,7 +476,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'can also find an issue by iid without the prefixed !' do
results = described_class.new(user, '2', limit_projects, public_and_internal_projects: false)
results = described_class.new(user, '2', limit_project_ids, public_and_internal_projects: false)
merge_requests = results.objects('merge_requests')
expect(merge_requests).to contain_exactly(@merge_request_2)
......@@ -489,7 +484,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'returns empty list when search by invalid iid' do
results = described_class.new(user, '#222', limit_projects)
results = described_class.new(user, '#222', limit_project_ids)
expect(results.objects('merge_requests')).to be_empty
expect(results.merge_requests_count).to eq 0
......@@ -501,7 +496,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let!(:closed_result) { create(:merge_request, :closed, source_project: project, title: 'foo closed') }
let(:scope) { 'merge_requests' }
let(:results) { described_class.new(user, 'foo', [project], filters: filters) }
let(:results) { described_class.new(user, 'foo', [project.id], filters: filters) }
include_examples 'search results filtered by state' do
before do
......@@ -538,7 +533,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
result = described_class.new(user, 'term', [project])
result = described_class.new(user, 'term', [project.id])
expect(result.issues_count).to eq(2)
expect(result.merge_requests_count).to eq(2)
......@@ -555,13 +550,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
def search_for(term)
described_class.new(user, term, [project_1]).objects('blobs').map(&:path)
described_class.new(user, term, [project_1.id]).objects('blobs').map(&:path)
end
it_behaves_like 'a paginated object', 'blobs'
it 'finds blobs' do
results = described_class.new(user, 'def', limit_projects)
results = described_class.new(user, 'def', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.first.data).to include('def')
......@@ -569,7 +564,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
it 'finds blobs by prefix search' do
results = described_class.new(user, 'defau*', limit_projects)
results = described_class.new(user, 'defau*', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.first.data).to include('default')
......@@ -582,18 +577,18 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_reporter(user)
ensure_elasticsearch_index!
results = described_class.new(user, 'def', [project_1])
results = described_class.new(user, 'def', [project_1.id])
expect(results.blobs_count).to eq 5
result_project_ids = results.objects('blobs').map(&:project_id)
expect(result_project_ids.uniq).to eq([project_1.id])
results = described_class.new(user, 'def', [project_1, project_2])
results = described_class.new(user, 'def', [project_1.id, project_2.id])
expect(results.blobs_count).to eq 10
end
it 'returns zero when blobs are not found' do
results = described_class.new(user, 'asdfg', limit_projects)
results = described_class.new(user, 'asdfg', limit_project_ids)
expect(results.blobs_count).to eq 0
end
......@@ -758,7 +753,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
describe 'Wikis' do
let(:results) { described_class.new(user, 'term', limit_projects) }
let(:results) { described_class.new(user, 'term', limit_project_ids) }
subject(:wiki_blobs) { results.objects('wiki_blobs') }
......@@ -797,12 +792,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
expect(results.wiki_blobs_count).to eq 1
results = described_class.new(user, 'term', [project_1, project_2])
results = described_class.new(user, 'term', [project_1.id, project_2.id])
expect(results.wiki_blobs_count).to eq 2
end
it 'returns zero when wiki blobs are not found' do
results = described_class.new(user, 'asdfg', limit_projects)
results = described_class.new(user, 'asdfg', limit_project_ids)
expect(results.wiki_blobs_count).to eq 0
end
......@@ -811,13 +806,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:project_1) { create(:project, :public, :repository, :wiki_disabled) }
context 'search by member' do
let(:limit_projects) { [project_1] }
let(:limit_project_ids) { [project_1.id] }
it { is_expected.to be_empty }
end
context 'search by non-member' do
let(:limit_projects) { [] }
let(:limit_project_ids) { [] }
it { is_expected.to be_empty }
end
......@@ -827,7 +822,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:project_1) { create(:project, :public, :repository, :wiki_private, :wiki_repo) }
context 'search by member' do
let(:limit_projects) { [project_1] }
let(:limit_project_ids) { [project_1.id] }
before do
project_1.add_guest(user)
......@@ -837,7 +832,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
context 'search by non-member' do
let(:limit_projects) { [] }
let(:limit_project_ids) { [] }
it { is_expected.to be_empty }
end
......@@ -853,7 +848,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'commits'
it 'finds commits' do
results = described_class.new(user, 'add', limit_projects)
results = described_class.new(user, 'add', limit_project_ids)
commits = results.objects('commits')
expect(commits.first.message.downcase).to include("add")
......@@ -866,15 +861,15 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_reporter(user)
ensure_elasticsearch_index!
results = described_class.new(user, 'add', [project_1])
results = described_class.new(user, 'add', [project_1.id])
expect(results.commits_count).to eq 24
results = described_class.new(user, 'add', [project_1, project_2])
results = described_class.new(user, 'add', [project_1.id, project_2.id])
expect(results.commits_count).to eq 48
end
it 'returns zero when commits are not found' do
results = described_class.new(user, 'asdfg', limit_projects)
results = described_class.new(user, 'asdfg', limit_project_ids)
expect(results.commits_count).to eq 0
end
......@@ -885,7 +880,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:private_project1) { create(:project, :private, :repository, :wiki_repo, description: "Private project") }
let(:private_project2) { create(:project, :private, :repository, :wiki_repo, description: "Private project where I'm a member") }
let(:public_project) { create(:project, :public, :repository, :wiki_repo, description: "Public project") }
let(:limit_projects) { [private_project2] }
let(:limit_project_ids) { [private_project2.id] }
before do
private_project2.project_members.create(user: user, access_level: ProjectMember::DEVELOPER)
......@@ -901,7 +896,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
# Authenticated search
results = described_class.new(user, 'project', limit_projects)
results = described_class.new(user, 'project', limit_project_ids)
issues = results.objects('issues')
expect(issues).to include issue_1
......@@ -942,7 +937,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
projects = user.authorized_projects
results = described_class.new(user, 'project', projects)
results = described_class.new(user, 'project', projects.pluck_primary_key)
milestones = results.objects('milestones')
expect(milestones).to match_array([milestone_1, milestone_3])
......@@ -969,7 +964,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it 'returns right set of milestones' do
# Authenticated search
projects = user.authorized_projects
results = described_class.new(user, 'project', projects)
results = described_class.new(user, 'project', projects.pluck_primary_key)
milestones = results.objects('milestones')
expect(milestones).to match_array([milestone_1, milestone_3, milestone_4])
......@@ -1050,7 +1045,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
# Authenticated search
results = described_class.new(user, 'project', limit_projects)
results = described_class.new(user, 'project', limit_project_ids)
milestones = results.objects('projects')
expect(milestones).to include internal_project
......@@ -1077,7 +1072,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
# Authenticated search
results = described_class.new(user, 'project', limit_projects)
results = described_class.new(user, 'project', limit_project_ids)
merge_requests = results.objects('merge_requests')
expect(merge_requests).to include merge_request_1
......@@ -1106,7 +1101,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it 'finds the right set of wiki blobs' do
# Authenticated search
results = described_class.new(user, 'term', limit_projects)
results = described_class.new(user, 'term', limit_project_ids)
blobs = results.objects('wiki_blobs')
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
......@@ -1138,7 +1133,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
# Authenticated search
results = described_class.new(user, 'search', limit_projects)
results = described_class.new(user, 'search', limit_project_ids)
commits = results.objects('commits')
expect(commits.map(&:project)).to match_array [internal_project, private_project2, public_project]
......@@ -1170,7 +1165,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index!
# Authenticated search
results = described_class.new(user, 'tesla', limit_projects)
results = described_class.new(user, 'tesla', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
......@@ -1187,7 +1182,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end
context 'query performance' do
let(:results) { described_class.new(user, 'hello world', limit_projects) }
let(:results) { described_class.new(user, 'hello world', limit_project_ids) }
include_examples 'does not hit Elasticsearch twice for objects and counts', %w|projects notes blobs wiki_blobs commits issues merge_requests milestones|
end
......
......@@ -210,6 +210,41 @@ RSpec.describe Search::GlobalService do
end
end
describe '#elastic_projects' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:another_project) { create(:project) }
let_it_be(:non_admin_user) { create_user_from_membership(project, :developer) }
let_it_be(:admin) { create(:admin) }
let(:service) { described_class.new(user, {}) }
let(:elastic_projects) { service.elastic_projects }
context 'when the user is an admin' do
let(:user) { admin }
it 'returns :any' do
expect(elastic_projects).to eq(:any)
end
end
context 'when the user is not an admin' do
let(:user) { non_admin_user }
it 'returns the projects the user has access to' do
expect(elastic_projects).to eq([project.id])
end
end
context 'when there is no user' do
let(:user) { nil }
it 'returns empty array' do
expect(elastic_projects).to eq([])
end
end
end
context 'confidential notes' do
let(:project) { create(:project, :public) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment