Commit 62aaaa1b authored by Micael Bergeron's avatar Micael Bergeron

Optimize the ES Query for confidentiality check

Previously, we would do separate checks for project membership and
confidentiality checks.

This commit adds an optimization that will limit the confidentiality
check to be within the limited projects, if such a limit exists.
parent 1e5cc59b
---
title: Optimize the Advanced Search query for Issues and Notes.
merge_request: 38095
author:
type: performance
...@@ -171,7 +171,7 @@ module Elastic ...@@ -171,7 +171,7 @@ module Elastic
limit = limit =
{ terms: { "#{feature}_access_level" => [::ProjectFeature::ENABLED, ::ProjectFeature::PRIVATE] } } { terms: { "#{feature}_access_level" => [::ProjectFeature::ENABLED, ::ProjectFeature::PRIVATE] } }
{ bool: { filter: [condition, limit].compact } } { bool: { filter: [condition, limit] } }
end end
end end
...@@ -226,11 +226,24 @@ module Elastic ...@@ -226,11 +226,24 @@ module Elastic
# When reading cross project is not allowed, only allow searching a # When reading cross project is not allowed, only allow searching a
# a single project, so the `:read_*` ability is only checked once. # a single project, so the `:read_*` ability is only checked once.
unless Ability.allowed?(current_user, :read_cross_project) unless Ability.allowed?(current_user, :read_cross_project)
project_ids = [] if project_ids.size > 1 return [] if project_ids.size > 1
end end
project_ids project_ids
end end
def authorized_project_ids(current_user, options = {})
return [] unless current_user
scoped_project_ids = scoped_project_ids(current_user, options[:project_ids])
authorized_project_ids = current_user.authorized_projects(Gitlab::Access::REPORTER).pluck_primary_key.to_set
# if the current search is limited to a subset of projects, we should do
# confidentiality check for these projects.
authorized_project_ids &= scoped_project_ids.to_set unless scoped_project_ids == :any
authorized_project_ids.to_a
end
end end
end end
end end
...@@ -13,29 +13,32 @@ module Elastic ...@@ -13,29 +13,32 @@ module Elastic
options[:features] = 'issues' options[:features] = 'issues'
query_hash = project_ids_filter(query_hash, options) query_hash = project_ids_filter(query_hash, options)
query_hash = confidentiality_filter(query_hash, options[:current_user], options[:project_ids]) query_hash = confidentiality_filter(query_hash, options)
search(query_hash, options) search(query_hash, options)
end end
private private
def user_has_access_to_confidential_issues?(authorized_project_ids, project_ids) def confidentiality_filter(query_hash, options)
# is_a?(Array) is needed because we might receive project_ids: :any current_user = options[:current_user]
return false unless authorized_project_ids && project_ids.is_a?(Array) project_ids = options[:project_ids]
(project_ids - authorized_project_ids).empty?
end
def confidentiality_filter(query_hash, current_user, project_ids)
return query_hash if current_user&.can_read_all_resources? return query_hash if current_user&.can_read_all_resources?
authorized_project_ids = current_user&.authorized_projects(Gitlab::Access::REPORTER)&.pluck_primary_key scoped_project_ids = scoped_project_ids(current_user, project_ids)
return query_hash if user_has_access_to_confidential_issues?(authorized_project_ids, project_ids) authorized_project_ids = authorized_project_ids(current_user, options)
# we can shortcut the filter if the user is authorized to see
# all the projects for which this query is scoped on
unless scoped_project_ids == :any || scoped_project_ids.empty?
return query_hash if authorized_project_ids.to_set == scoped_project_ids.to_set
end
filter = { term: { confidential: false } }
filter =
if current_user if current_user
{ filter = {
bool: { bool: {
should: [ should: [
{ term: { confidential: false } }, { term: { confidential: false } },
...@@ -58,8 +61,6 @@ module Elastic ...@@ -58,8 +61,6 @@ module Elastic
] ]
} }
} }
else
{ term: { confidential: false } }
end end
query_hash[:query][:bool][:filter] << filter query_hash[:query][:bool][:filter] << filter
......
...@@ -14,7 +14,7 @@ module Elastic ...@@ -14,7 +14,7 @@ module Elastic
query_hash = basic_query_hash(%w[note], query) query_hash = basic_query_hash(%w[note], query)
query_hash = project_ids_filter(query_hash, options) query_hash = project_ids_filter(query_hash, options)
query_hash = confidentiality_filter(query_hash, options[:current_user]) query_hash = confidentiality_filter(query_hash, options)
query_hash[:highlight] = highlight_options(options[:in]) query_hash[:highlight] = highlight_options(options[:in])
...@@ -23,7 +23,9 @@ module Elastic ...@@ -23,7 +23,9 @@ module Elastic
private private
def confidentiality_filter(query_hash, current_user) def confidentiality_filter(query_hash, options)
current_user = options[:current_user]
return query_hash if current_user&.can_read_all_resources? return query_hash if current_user&.can_read_all_resources?
filter = { filter = {
...@@ -43,7 +45,7 @@ module Elastic ...@@ -43,7 +45,7 @@ module Elastic
bool: { bool: {
should: [ should: [
{ bool: { must_not: [{ exists: { field: :confidential } }] } }, { bool: { must_not: [{ exists: { field: :confidential } }] } },
{ term: { "confidential" => false } } { term: { confidential: false } }
] ]
} }
} }
...@@ -61,7 +63,7 @@ module Elastic ...@@ -61,7 +63,7 @@ module Elastic
bool: { bool: {
should: [ should: [
{ term: { "issue.confidential" => true } }, { term: { "issue.confidential" => true } },
{ term: { "confidential" => true } } { term: { confidential: true } }
] ]
} }
}, },
...@@ -70,7 +72,7 @@ module Elastic ...@@ -70,7 +72,7 @@ module Elastic
should: [ should: [
{ term: { "issue.author_id" => current_user.id } }, { term: { "issue.author_id" => current_user.id } },
{ term: { "issue.assignee_id" => current_user.id } }, { term: { "issue.assignee_id" => current_user.id } },
{ terms: { "project_id" => current_user.authorized_projects(Gitlab::Access::REPORTER).pluck_primary_key } } { terms: { project_id: authorized_project_ids(current_user, options) } }
] ]
} }
} }
......
...@@ -10,12 +10,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -10,12 +10,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project_1) { create(:project, :public, :repository, :wiki_repo) } let(:project_1) { create(:project, :public, :repository, :wiki_repo) }
let(:project_2) { create(:project, :public, :repository, :wiki_repo) } let(:project_2) { create(:project, :public, :repository, :wiki_repo) }
let(:limit_project_ids) { [project_1.id] } let(:limit_projects) { [project_1] }
describe '#formatted_count' do describe '#formatted_count' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:results) { described_class.new(user, 'hello world', limit_project_ids) } let(:results) { described_class.new(user, 'hello world', limit_projects) }
where(:scope, :count_method, :expected) do where(:scope, :count_method, :expected) do
'projects' | :projects_count | '1234' 'projects' | :projects_count | '1234'
...@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
shared_examples_for 'a paginated object' do |object_type| shared_examples_for 'a paginated object' do |object_type|
let(:results) { described_class.new(user, 'hello world', limit_project_ids) } let(:results) { described_class.new(user, 'hello world', limit_projects) }
it 'does not explode when given a page as a string' do it 'does not explode when given a page as a string' do
expect { results.objects(object_type, page: "2") }.not_to raise_error expect { results.objects(object_type, page: "2") }.not_to raise_error
...@@ -135,7 +135,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -135,7 +135,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'issues' it_behaves_like 'a paginated object', 'issues'
it 'lists found issues' do it 'lists found issues' do
results = described_class.new(user, 'hello world', limit_project_ids) results = described_class.new(user, 'hello world', limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue_1 expect(issues).to include @issue_1
...@@ -145,14 +145,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -145,14 +145,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'returns empty list when issues are not found' do it 'returns empty list when issues are not found' do
results = described_class.new(user, 'security', limit_project_ids) results = described_class.new(user, 'security', limit_projects)
expect(results.objects('issues')).to be_empty expect(results.objects('issues')).to be_empty
expect(results.issues_count).to eq 0 expect(results.issues_count).to eq 0
end end
it 'lists issue when search by a valid iid' do it 'lists issue when search by a valid iid' do
results = described_class.new(user, '#2', limit_project_ids, public_and_internal_projects: false) results = described_class.new(user, '#2', limit_projects, public_and_internal_projects: false)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).not_to include @issue_1 expect(issues).not_to include @issue_1
...@@ -162,7 +162,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -162,7 +162,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'returns empty list when search by invalid iid' do it 'returns empty list when search by invalid iid' do
results = described_class.new(user, '#222', limit_project_ids) results = described_class.new(user, '#222', limit_projects)
expect(results.objects('issues')).to be_empty expect(results.objects('issues')).to be_empty
expect(results.issues_count).to eq 0 expect(results.issues_count).to eq 0
...@@ -198,7 +198,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -198,7 +198,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'notes' it_behaves_like 'a paginated object', 'notes'
it 'lists found notes' do it 'lists found notes' do
results = described_class.new(user, 'foo', limit_project_ids) results = described_class.new(user, 'foo', limit_projects)
notes = results.objects('notes') notes = results.objects('notes')
expect(notes).to include @note_1 expect(notes).to include @note_1
...@@ -208,7 +208,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -208,7 +208,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'returns empty list when notes are not found' do it 'returns empty list when notes are not found' do
results = described_class.new(user, 'security', limit_project_ids) results = described_class.new(user, 'security', limit_projects)
expect(results.objects('notes')).to be_empty expect(results.objects('notes')).to be_empty
expect(results.notes_count).to eq 0 expect(results.notes_count).to eq 0
...@@ -218,7 +218,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -218,7 +218,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
describe 'confidential issues' do describe 'confidential issues' do
let(:project_3) { create(:project, :public) } let(:project_3) { create(:project, :public) }
let(:project_4) { create(:project, :public) } let(:project_4) { create(:project, :public) }
let(:limit_project_ids) { [project_1.id, project_2.id, project_3.id] } let(:limit_projects) { [project_1, project_2, project_3] }
let(:author) { create(:user) } let(:author) { create(:user) }
let(:assignee) { create(:user) } let(:assignee) { create(:user) }
let(:non_member) { create(:user) } let(:non_member) { create(:user) }
...@@ -240,7 +240,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -240,7 +240,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:query) { 'issue' } let(:query) { 'issue' }
it 'does not list confidential issues for guests' do it 'does not list confidential issues for guests' do
results = described_class.new(nil, query, limit_project_ids) results = described_class.new(nil, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -253,7 +253,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -253,7 +253,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'does not list confidential issues for non project members' do it 'does not list confidential issues for non project members' do
results = described_class.new(non_member, query, limit_project_ids) results = described_class.new(non_member, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -266,7 +266,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -266,7 +266,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists confidential issues for author' do it 'lists confidential issues for author' do
results = described_class.new(author, query, limit_project_ids) results = described_class.new(author, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -279,7 +279,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -279,7 +279,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists confidential issues for assignee' do it 'lists confidential issues for assignee' do
results = described_class.new(assignee, query, limit_project_ids) results = described_class.new(assignee, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -295,7 +295,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -295,7 +295,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_1.add_developer(member) project_1.add_developer(member)
project_2.add_developer(member) project_2.add_developer(member)
results = described_class.new(member, query, limit_project_ids) results = described_class.new(member, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -308,7 +308,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -308,7 +308,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists all issues for admin' do it 'lists all issues for admin' do
results = described_class.new(admin, query, limit_project_ids) results = described_class.new(admin, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -325,7 +325,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -325,7 +325,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:query) { '#1' } let(:query) { '#1' }
it 'does not list confidential issues for guests' do it 'does not list confidential issues for guests' do
results = described_class.new(nil, query, limit_project_ids) results = described_class.new(nil, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -338,7 +338,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -338,7 +338,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'does not list confidential issues for non project members' do it 'does not list confidential issues for non project members' do
results = described_class.new(non_member, query, limit_project_ids) results = described_class.new(non_member, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -351,7 +351,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -351,7 +351,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists confidential issues for author' do it 'lists confidential issues for author' do
results = described_class.new(author, query, limit_project_ids) results = described_class.new(author, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -364,7 +364,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -364,7 +364,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists confidential issues for assignee' do it 'lists confidential issues for assignee' do
results = described_class.new(assignee, query, limit_project_ids) results = described_class.new(assignee, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -380,7 +380,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -380,7 +380,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_developer(member) project_2.add_developer(member)
project_3.add_developer(member) project_3.add_developer(member)
results = described_class.new(member, query, limit_project_ids) results = described_class.new(member, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -393,7 +393,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -393,7 +393,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'lists all issues for admin' do it 'lists all issues for admin' do
results = described_class.new(admin, query, limit_project_ids) results = described_class.new(admin, query, limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include @issue expect(issues).to include @issue
...@@ -439,7 +439,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -439,7 +439,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'merge_requests' it_behaves_like 'a paginated object', 'merge_requests'
it 'lists found merge requests' do it 'lists found merge requests' do
results = described_class.new(user, 'hello world', limit_project_ids) results = described_class.new(user, 'hello world', limit_projects)
merge_requests = results.objects('merge_requests') merge_requests = results.objects('merge_requests')
expect(merge_requests).to include @merge_request_1 expect(merge_requests).to include @merge_request_1
...@@ -449,14 +449,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -449,14 +449,14 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'returns empty list when merge requests are not found' do it 'returns empty list when merge requests are not found' do
results = described_class.new(user, 'security', limit_project_ids) results = described_class.new(user, 'security', limit_projects)
expect(results.objects('merge_requests')).to be_empty expect(results.objects('merge_requests')).to be_empty
expect(results.merge_requests_count).to eq 0 expect(results.merge_requests_count).to eq 0
end end
it 'lists merge request when search by a valid iid' do it 'lists merge request when search by a valid iid' do
results = described_class.new(user, '#2', limit_project_ids) results = described_class.new(user, '#2', limit_projects)
merge_requests = results.objects('merge_requests') merge_requests = results.objects('merge_requests')
expect(merge_requests).not_to include @merge_request_1 expect(merge_requests).not_to include @merge_request_1
...@@ -466,7 +466,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -466,7 +466,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'returns empty list when search by invalid iid' do it 'returns empty list when search by invalid iid' do
results = described_class.new(user, '#222', limit_project_ids) results = described_class.new(user, '#222', limit_projects)
expect(results.objects('merge_requests')).to be_empty expect(results.objects('merge_requests')).to be_empty
expect(results.merge_requests_count).to eq 0 expect(results.merge_requests_count).to eq 0
...@@ -500,7 +500,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -500,7 +500,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
result = described_class.new(user, 'term', [project.id]) result = described_class.new(user, 'term', [project])
expect(result.issues_count).to eq(2) expect(result.issues_count).to eq(2)
expect(result.merge_requests_count).to eq(2) expect(result.merge_requests_count).to eq(2)
...@@ -517,13 +517,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -517,13 +517,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
def search_for(term) def search_for(term)
described_class.new(user, term, [project_1.id]).objects('blobs').map(&:path) described_class.new(user, term, [project_1]).objects('blobs').map(&:path)
end end
it_behaves_like 'a paginated object', 'blobs' it_behaves_like 'a paginated object', 'blobs'
it 'finds blobs' do it 'finds blobs' do
results = described_class.new(user, 'def', limit_project_ids) results = described_class.new(user, 'def', limit_projects)
blobs = results.objects('blobs') blobs = results.objects('blobs')
expect(blobs.first.data).to include('def') expect(blobs.first.data).to include('def')
...@@ -531,7 +531,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -531,7 +531,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
it 'finds blobs by prefix search' do it 'finds blobs by prefix search' do
results = described_class.new(user, 'defau*', limit_project_ids) results = described_class.new(user, 'defau*', limit_projects)
blobs = results.objects('blobs') blobs = results.objects('blobs')
expect(blobs.first.data).to include('default') expect(blobs.first.data).to include('default')
...@@ -544,18 +544,18 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -544,18 +544,18 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_reporter(user) project_2.add_reporter(user)
ensure_elasticsearch_index! ensure_elasticsearch_index!
results = described_class.new(user, 'def', [project_1.id]) results = described_class.new(user, 'def', [project_1])
expect(results.blobs_count).to eq 5 expect(results.blobs_count).to eq 5
result_project_ids = results.objects('blobs').map(&:project_id) result_project_ids = results.objects('blobs').map(&:project_id)
expect(result_project_ids.uniq).to eq([project_1.id]) expect(result_project_ids.uniq).to eq([project_1.id])
results = described_class.new(user, 'def', [project_1.id, project_2.id]) results = described_class.new(user, 'def', [project_1, project_2])
expect(results.blobs_count).to eq 10 expect(results.blobs_count).to eq 10
end end
it 'returns zero when blobs are not found' do it 'returns zero when blobs are not found' do
results = described_class.new(user, 'asdfg', limit_project_ids) results = described_class.new(user, 'asdfg', limit_projects)
expect(results.blobs_count).to eq 0 expect(results.blobs_count).to eq 0
end end
...@@ -720,7 +720,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -720,7 +720,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
describe 'Wikis' do describe 'Wikis' do
let(:results) { described_class.new(user, 'term', limit_project_ids) } let(:results) { described_class.new(user, 'term', limit_projects) }
subject(:wiki_blobs) { results.objects('wiki_blobs') } subject(:wiki_blobs) { results.objects('wiki_blobs') }
...@@ -759,12 +759,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -759,12 +759,12 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
expect(results.wiki_blobs_count).to eq 1 expect(results.wiki_blobs_count).to eq 1
results = described_class.new(user, 'term', [project_1.id, project_2.id]) results = described_class.new(user, 'term', [project_1, project_2])
expect(results.wiki_blobs_count).to eq 2 expect(results.wiki_blobs_count).to eq 2
end end
it 'returns zero when wiki blobs are not found' do it 'returns zero when wiki blobs are not found' do
results = described_class.new(user, 'asdfg', limit_project_ids) results = described_class.new(user, 'asdfg', limit_projects)
expect(results.wiki_blobs_count).to eq 0 expect(results.wiki_blobs_count).to eq 0
end end
...@@ -773,13 +773,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -773,13 +773,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:project_1) { create(:project, :public, :repository, :wiki_disabled) } let(:project_1) { create(:project, :public, :repository, :wiki_disabled) }
context 'search by member' do context 'search by member' do
let(:limit_project_ids) { [project_1.id] } let(:limit_projects) { [project_1] }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end end
context 'search by non-member' do context 'search by non-member' do
let(:limit_project_ids) { [] } let(:limit_projects) { [] }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end end
...@@ -789,7 +789,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -789,7 +789,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:project_1) { create(:project, :public, :repository, :wiki_private, :wiki_repo) } let(:project_1) { create(:project, :public, :repository, :wiki_private, :wiki_repo) }
context 'search by member' do context 'search by member' do
let(:limit_project_ids) { [project_1.id] } let(:limit_projects) { [project_1] }
before do before do
project_1.add_guest(user) project_1.add_guest(user)
...@@ -799,7 +799,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -799,7 +799,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
context 'search by non-member' do context 'search by non-member' do
let(:limit_project_ids) { [] } let(:limit_projects) { [] }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end end
...@@ -815,7 +815,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -815,7 +815,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it_behaves_like 'a paginated object', 'commits' it_behaves_like 'a paginated object', 'commits'
it 'finds commits' do it 'finds commits' do
results = described_class.new(user, 'add', limit_project_ids) results = described_class.new(user, 'add', limit_projects)
commits = results.objects('commits') commits = results.objects('commits')
expect(commits.first.message.downcase).to include("add") expect(commits.first.message.downcase).to include("add")
...@@ -828,15 +828,15 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -828,15 +828,15 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
project_2.add_reporter(user) project_2.add_reporter(user)
ensure_elasticsearch_index! ensure_elasticsearch_index!
results = described_class.new(user, 'add', [project_1.id]) results = described_class.new(user, 'add', [project_1])
expect(results.commits_count).to eq 24 expect(results.commits_count).to eq 24
results = described_class.new(user, 'add', [project_1.id, project_2.id]) results = described_class.new(user, 'add', [project_1, project_2])
expect(results.commits_count).to eq 48 expect(results.commits_count).to eq 48
end end
it 'returns zero when commits are not found' do it 'returns zero when commits are not found' do
results = described_class.new(user, 'asdfg', limit_project_ids) results = described_class.new(user, 'asdfg', limit_projects)
expect(results.commits_count).to eq 0 expect(results.commits_count).to eq 0
end end
...@@ -847,7 +847,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -847,7 +847,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_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(: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(:public_project) { create(:project, :public, :repository, :wiki_repo, description: "Public project") }
let(:limit_project_ids) { [private_project2.id] } let(:limit_projects) { [private_project2] }
before do before do
private_project2.project_members.create(user: user, access_level: ProjectMember::DEVELOPER) private_project2.project_members.create(user: user, access_level: ProjectMember::DEVELOPER)
...@@ -863,7 +863,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -863,7 +863,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_projects)
issues = results.objects('issues') issues = results.objects('issues')
expect(issues).to include issue_1 expect(issues).to include issue_1
...@@ -903,8 +903,8 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -903,8 +903,8 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
internal_project.project_feature.update!(issues_access_level: ProjectFeature::DISABLED) internal_project.project_feature.update!(issues_access_level: ProjectFeature::DISABLED)
ensure_elasticsearch_index! ensure_elasticsearch_index!
project_ids = user.authorized_projects.pluck(:id) projects = user.authorized_projects
results = described_class.new(user, 'project', project_ids) results = described_class.new(user, 'project', projects)
milestones = results.objects('milestones') milestones = results.objects('milestones')
expect(milestones).to match_array([milestone_1, milestone_3]) expect(milestones).to match_array([milestone_1, milestone_3])
...@@ -930,8 +930,8 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -930,8 +930,8 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
context 'when user can read milestones' do context 'when user can read milestones' do
it 'returns right set of milestones' do it 'returns right set of milestones' do
# Authenticated search # Authenticated search
project_ids = user.authorized_projects.pluck(:id) projects = user.authorized_projects
results = described_class.new(user, 'project', project_ids) results = described_class.new(user, 'project', projects)
milestones = results.objects('milestones') milestones = results.objects('milestones')
expect(milestones).to match_array([milestone_1, milestone_3, milestone_4]) expect(milestones).to match_array([milestone_1, milestone_3, milestone_4])
...@@ -1012,7 +1012,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1012,7 +1012,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_projects)
milestones = results.objects('projects') milestones = results.objects('projects')
expect(milestones).to include internal_project expect(milestones).to include internal_project
...@@ -1039,7 +1039,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1039,7 +1039,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_projects)
merge_requests = results.objects('merge_requests') merge_requests = results.objects('merge_requests')
expect(merge_requests).to include merge_request_1 expect(merge_requests).to include merge_request_1
...@@ -1068,7 +1068,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1068,7 +1068,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
it 'finds the right set of wiki blobs' do it 'finds the right set of wiki blobs' do
# Authenticated search # Authenticated search
results = described_class.new(user, 'term', limit_project_ids) results = described_class.new(user, 'term', limit_projects)
blobs = results.objects('wiki_blobs') blobs = results.objects('wiki_blobs')
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project] expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
...@@ -1100,7 +1100,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1100,7 +1100,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Authenticated search # Authenticated search
results = described_class.new(user, 'search', limit_project_ids) results = described_class.new(user, 'search', limit_projects)
commits = results.objects('commits') commits = results.objects('commits')
expect(commits.map(&:project)).to match_array [internal_project, private_project2, public_project] expect(commits.map(&:project)).to match_array [internal_project, private_project2, public_project]
...@@ -1132,7 +1132,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1132,7 +1132,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Authenticated search # Authenticated search
results = described_class.new(user, 'tesla', limit_project_ids) results = described_class.new(user, 'tesla', limit_projects)
blobs = results.objects('blobs') blobs = results.objects('blobs')
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project] expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
...@@ -1149,7 +1149,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need ...@@ -1149,7 +1149,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
end end
context 'query performance' do context 'query performance' do
let(:results) { described_class.new(user, 'hello world', limit_project_ids) } let(:results) { described_class.new(user, 'hello world', limit_projects) }
include_examples 'does not hit Elasticsearch twice for objects and counts', %w|projects notes blobs wiki_blobs commits issues merge_requests milestones| include_examples 'does not hit Elasticsearch twice for objects and counts', %w|projects notes blobs wiki_blobs commits issues merge_requests milestones|
end end
......
...@@ -261,6 +261,7 @@ RSpec.configure do |config| ...@@ -261,6 +261,7 @@ RSpec.configure do |config|
./spec/support/protected_tags ./spec/support/protected_tags
./spec/support/shared_examples/features ./spec/support/shared_examples/features
./spec/support/shared_examples/requests ./spec/support/shared_examples/requests
./spec/support/shared_examples/lib/gitlab
./spec/views ./spec/views
./spec/workers ./spec/workers
) )
......
...@@ -10,10 +10,6 @@ RSpec.shared_examples 'access restricted confidential issues' do ...@@ -10,10 +10,6 @@ RSpec.shared_examples 'access restricted confidential issues' do
let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) } let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignees: [assignee]) } let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignees: [assignee]) }
before do
stub_feature_flags(user_mode_in_session: false)
end
subject(:objects) do subject(:objects) do
described_class.new(user, query, project: project).objects('issues') described_class.new(user, query, project: project).objects('issues')
end end
......
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