Commit 7c0beb47 authored by Nick Thomas's avatar Nick Thomas

Revert "Avoid loading objects from DB in ES results"

This reverts commit d9cb907c.
parent e48d8c13
...@@ -25,7 +25,6 @@ class SearchController < ApplicationController ...@@ -25,7 +25,6 @@ class SearchController < ApplicationController
@show_snippets = search_service.show_snippets? @show_snippets = search_service.show_snippets?
@search_results = search_service.search_results @search_results = search_service.search_results
@search_objects = search_service.search_objects @search_objects = search_service.search_objects
@display_options = search_service.display_options
render_commits if @scope == 'commits' render_commits if @scope == 'commits'
eager_load_user_status if @scope == 'users' eager_load_user_status if @scope == 'users'
......
...@@ -72,8 +72,6 @@ class ProjectFeature < ApplicationRecord ...@@ -72,8 +72,6 @@ class ProjectFeature < ApplicationRecord
default_value_for :wiki_access_level, value: ENABLED, allows_nil: false default_value_for :wiki_access_level, value: ENABLED, allows_nil: false
default_value_for :repository_access_level, value: ENABLED, allows_nil: false default_value_for :repository_access_level, value: ENABLED, allows_nil: false
scope :for_project_id, -> (project) { where(project: project) }
def feature_available?(feature, user) def feature_available?(feature, user)
# This feature might not be behind a feature flag at all, so default to true # This feature might not be behind a feature flag at all, so default to true
return false unless ::Feature.enabled?(feature, user, default_enabled: true) return false unless ::Feature.enabled?(feature, user, default_enabled: true)
......
...@@ -52,10 +52,6 @@ class SearchService ...@@ -52,10 +52,6 @@ class SearchService
@search_objects ||= search_results.objects(scope, params[:page]) @search_objects ||= search_results.objects(scope, params[:page])
end end
def display_options
@display_options ||= search_results.display_options(scope)
end
private private
def search_service def search_service
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
.search-results .search-results
- if @scope == 'projects' - if @scope == 'projects'
.term .term
= render 'shared/projects/list', { projects: @search_objects, pipeline_status: false }.merge(@display_options) = render 'shared/projects/list', projects: @search_objects, pipeline_status: false
- else - else
- locals = { projects: blob_projects(@search_objects) } if %w[blobs wiki_blobs].include?(@scope) - locals = { projects: blob_projects(@search_objects) } if %w[blobs wiki_blobs].include?(@scope)
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects, locals: locals = render partial: "search/results/#{@scope.singularize}", collection: @search_objects, locals: locals
......
.search-result-row .search-result-row
%h4 %h4
= confidential_icon(issue) = confidential_icon(issue)
= link_to namespace_project_issue_path(issue.project.namespace.becomes(Namespace), issue.project, issue) do = link_to [issue.project.namespace.becomes(Namespace), issue.project, issue] do
%span.term.str-truncated= issue.title %span.term.str-truncated= issue.title
- if issue.closed? - if issue.closed?
%span.badge.badge-danger.prepend-left-5= _("Closed") %span.badge.badge-danger.prepend-left-5= _("Closed")
......
.search-result-row .search-result-row
%h4 %h4
= link_to namespace_project_merge_request_path(merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request) do = link_to [merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request] do
%span.term.str-truncated= merge_request.title %span.term.str-truncated= merge_request.title
- if merge_request.merged? - if merge_request.merged?
%span.badge.badge-primary.prepend-left-5= _("Merged") %span.badge.badge-primary.prepend-left-5= _("Merged")
......
.search-result-row .search-result-row
%h4 %h4
= link_to namespace_project_milestone_path(milestone.project.namespace.becomes(Namespace), milestone.project, milestone) do = link_to [milestone.project.namespace.becomes(Namespace), milestone.project, milestone] do
%span.term.str-truncated= milestone.title %span.term.str-truncated= milestone.title
- if milestone.description.present? - if milestone.description.present?
......
...@@ -331,7 +331,7 @@ module Elastic ...@@ -331,7 +331,7 @@ module Elastic
self.import(options) self.import(options)
end end
def basic_query_hash(fields, query, page: nil, per_page: nil) def basic_query_hash(fields, query)
query_hash = if query.present? query_hash = if query.present?
{ {
query: { query: {
...@@ -360,9 +360,6 @@ module Elastic ...@@ -360,9 +360,6 @@ module Elastic
} }
end end
query_hash[:size] = per_page if per_page
query_hash[:from] = per_page * (page - 1) if per_page && page
query_hash[:sort] = [ query_hash[:sort] = [
{ updated_at: { order: :desc } }, { updated_at: { order: :desc } },
:_score :_score
......
...@@ -30,7 +30,7 @@ module Elastic ...@@ -30,7 +30,7 @@ module Elastic
if query =~ /#(\d+)\z/ if query =~ /#(\d+)\z/
iid_query_hash(Regexp.last_match(1)) iid_query_hash(Regexp.last_match(1))
else else
basic_query_hash(%w(title^2 description), query, page: options[:page], per_page: options[:per_page]) basic_query_hash(%w(title^2 description), query)
end end
options[:features] = 'issues' options[:features] = 'issues'
......
...@@ -46,7 +46,7 @@ module Elastic ...@@ -46,7 +46,7 @@ module Elastic
if query =~ /\!(\d+)\z/ if query =~ /\!(\d+)\z/
iid_query_hash(Regexp.last_match(1)) iid_query_hash(Regexp.last_match(1))
else else
basic_query_hash(%w(title^2 description), query, page: options[:page], per_page: options[:per_page]) basic_query_hash(%w(title^2 description), query)
end end
options[:features] = 'merge_requests' options[:features] = 'merge_requests'
......
...@@ -12,7 +12,7 @@ module Elastic ...@@ -12,7 +12,7 @@ module Elastic
# https://gitlab.com/gitlab-org/gitlab-ee/issues/349 # https://gitlab.com/gitlab-org/gitlab-ee/issues/349
data = {} data = {}
[:id, :iid, :title, :description, :project_id, :created_at, :updated_at].each do |attr| [:id, :title, :description, :project_id, :created_at, :updated_at].each do |attr|
data[attr.to_s] = safely_read_attribute_for_elasticsearch(attr) data[attr.to_s] = safely_read_attribute_for_elasticsearch(attr)
end end
...@@ -26,7 +26,7 @@ module Elastic ...@@ -26,7 +26,7 @@ module Elastic
def self.elastic_search(query, options: {}) def self.elastic_search(query, options: {})
options[:in] = %w(title^2 description) options[:in] = %w(title^2 description)
query_hash = basic_query_hash(options[:in], query, page: options[:page], per_page: options[:per_page]) query_hash = basic_query_hash(options[:in], query)
query_hash = project_ids_filter(query_hash, options) query_hash = project_ids_filter(query_hash, options)
......
...@@ -65,7 +65,7 @@ module Elastic ...@@ -65,7 +65,7 @@ module Elastic
def self.elastic_search(query, options: {}) def self.elastic_search(query, options: {})
options[:in] = %w(name^10 name_with_namespace^2 path_with_namespace path^9 description) options[:in] = %w(name^10 name_with_namespace^2 path_with_namespace path^9 description)
query_hash = basic_query_hash(options[:in], query, page: options[:page], per_page: options[:per_page]) query_hash = basic_query_hash(options[:in], query)
filters = [] filters = []
......
---
title: Avoid loading database objects for Elasticsearch results
merge_request: 12691
author:
type: performance
# frozen_string_literal: true
module Elasticsearch
class LiteProject
include Gitlab::Utils::StrongMemoize
attr_accessor :id, :name, :path, :description, :namespace_id, :create_at, :updated_at, :archived,
:visibility_level, :last_activity_at, :name_with_namespace, :path_with_namespace,
:issues_access_level, :merge_requests_access_level, :snippets_access_level, :wiki_access_level,
:repository_access_level
attr_accessor :pipeline_status, :commit, :creator
alias_attribute :last_activity_date, :last_activity_at
def initialize(raw_project_hash)
raw_project_hash.each do |key, value|
value = value.to_datetime if key =~ /_at$/
self.instance_variable_set(:"@#{key}", value)
end
end
# only used for routing and results display, so we trick Rails here
def namespace
# can't use an OpenStruct because to_param is a defined method on it
Struct.new(:to_param, :human_name).new(
path_with_namespace.sub(/\/#{path}$/, ''),
name_with_namespace.sub(/\s+\/\s+#{name}$/, '')
)
end
def route
# Creates an object that has a `cache_key` attribute set to nil
Struct.new(:cache_key).new(nil)
end
def pending_delete?
false
end
def cache_key
"lite_projects/#{id}-#{updated_at.utc.to_s(:number)}"
end
def to_param
path&.to_s
end
def model_name
OpenStruct.new(param_key: 'project')
end
def banzai_render_context(field)
return unless field == :description
{ pipeline: :description, project: self }
end
def default_issues_tracker?
true
end
# rubocop: disable CodeReuse/ActiveRecord
# This method is required by the OpenMergeRequestsCountService
def merge_requests
strong_memoize(:merge_requests) do
MergeRequest.opened.where(project_id: self.id)
end
end
# rubocop: enable CodeReuse/ActiveRecord
def forks_count
Projects::ForksCountService.new(self).count
end
def open_issues_count(current_user = nil)
Projects::OpenIssuesCountService.new(self, current_user).count
end
def open_merge_requests_count
Projects::OpenMergeRequestsCountService.new(self).count
end
end
end
# frozen_string_literal: true
module Elasticsearch
module ResultObjects
# Here we refine our models to learn how to load from Elasticsearch without hitting the database
# In order to use these methods in another class you first have to `using Elasticsearch::ResultObjects`
# and you can then use the model objects directly
ES_ATTRIBUTES = %i(join_field type).freeze
refine ::Project.singleton_class do
def load_from_elasticsearch(es_response, current_user: nil)
es_response.results.response.map(&:_source).then do |projects|
projects.map do |project|
::Elasticsearch::LiteProject.new(project)
end
end
end
end
refine ::Issue.singleton_class do
def load_from_elasticsearch(es_response, current_user:)
es_response.results.response.map(&:_source).then do |issues|
projects = ::ProjectsFinder.new(
current_user: current_user,
project_ids_relation: issues.map(&:project_id)
).execute.index_by(&:id)
issues.map do |issue|
issue[:project] = projects[issue.delete(:project_id)]
issue[:assignee_ids] = issue.delete(:assignee_id)
issue.except!(*ES_ATTRIBUTES)
new(issue)
end
end
end
end
refine ::MergeRequest.singleton_class do
def load_from_elasticsearch(es_response, current_user:)
es_response.results.response.map(&:_source).then do |merge_requests|
# rubocop: disable CodeReuse/ActiveRecord
projects = ::ProjectsFinder.new(
current_user: current_user,
project_ids_relation: merge_requests.map(&:target_project_id)
).execute.includes(:route, namespace: [:route]).index_by(&:id)
# rubocop: enable CodeReuse/ActiveRecord
merge_requests.map do |merge_request|
merge_request[:target_project] = projects[merge_request.delete(:target_project_id)]
merge_request.except!(*ES_ATTRIBUTES)
new(merge_request)
end
end
end
end
refine ::Milestone.singleton_class do
def load_from_elasticsearch(es_response, current_user:)
es_response.results.response.map(&:_source).then do |milestones|
projects = ::ProjectsFinder.new(
current_user: current_user,
project_ids_relation: milestones.map(&:project_id)
).execute.index_by(&:id)
milestones.map do |milestone|
milestone[:project] = projects[milestone.delete(:project_id)]
milestone.except!(*ES_ATTRIBUTES)
new(milestone)
end
end
end
end
end
end
...@@ -5,8 +5,6 @@ module Gitlab ...@@ -5,8 +5,6 @@ module Gitlab
class SearchResults class SearchResults
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
using Elasticsearch::ResultObjects
attr_reader :current_user, :query, :public_and_internal_projects attr_reader :current_user, :query, :public_and_internal_projects
# Limit search results by passed project ids # Limit search results by passed project ids
...@@ -27,13 +25,13 @@ module Gitlab ...@@ -27,13 +25,13 @@ module Gitlab
def objects(scope, page = nil) def objects(scope, page = nil)
case scope case scope
when 'projects' when 'projects'
projects(page: page, per_page: per_page) projects.page(page).per(per_page).records
when 'issues' when 'issues'
issues(page: page, per_page: per_page) issues.page(page).per(per_page).records
when 'merge_requests' when 'merge_requests'
merge_requests(page: page, per_page: per_page) merge_requests.page(page).per(per_page).records
when 'milestones' when 'milestones'
milestones(page: page, per_page: per_page) milestones.page(page).per(per_page).records
when 'blobs' when 'blobs'
blobs.page(page).per(per_page) blobs.page(page).per(per_page)
when 'wiki_blobs' when 'wiki_blobs'
...@@ -47,17 +45,6 @@ module Gitlab ...@@ -47,17 +45,6 @@ module Gitlab
end end
end end
def display_options(scope)
case scope
when 'projects'
{
stars: false
}
else
{}
end
end
def generic_search_results def generic_search_results
@generic_search_results ||= Gitlab::SearchResults.new(current_user, limit_projects, query) @generic_search_results ||= Gitlab::SearchResults.new(current_user, limit_projects, query)
end end
...@@ -156,40 +143,19 @@ module Gitlab ...@@ -156,40 +143,19 @@ module Gitlab
} }
end end
def paginate_array(collection, total_count, page, per_page) def projects
offset = per_page * (page - 1)
Kaminari.paginate_array(collection, total_count: total_count, limit: per_page, offset: offset)
end
def search(model, query, options, page: 1, per_page: 20)
page = (page || 1).to_i
response = model.elastic_search(
query,
options: options.merge(page: page, per_page: per_page)
)
results = model.load_from_elasticsearch(response, current_user: current_user)
paginate_array(results, response.total_count, page, per_page)
end
# See the comment for #commits for more info on why we memoize this way
def projects(page: 1, per_page: 20)
strong_memoize(:projects) do strong_memoize(:projects) do
search(Project, query, base_options, page: page, per_page: per_page) Project.elastic_search(query, options: base_options)
end end
end end
# See the comment for #commits for more info on why we memoize this way def issues
def issues(page: 1, per_page: 20)
strong_memoize(:issues) do strong_memoize(:issues) do
search(Issue, query, base_options, page: page, per_page: per_page) Issue.elastic_search(query, options: base_options)
end end
end end
# See the comment for #commits for more info on why we memoize this way def milestones
def milestones(page: 1, per_page: 20)
strong_memoize(:milestones) do strong_memoize(:milestones) do
# Must pass 'issues' and 'merge_requests' to check # Must pass 'issues' and 'merge_requests' to check
# if any of the features is available for projects in Elastic::ApplicationSearch#project_ids_query # if any of the features is available for projects in Elastic::ApplicationSearch#project_ids_query
...@@ -198,18 +164,17 @@ module Gitlab ...@@ -198,18 +164,17 @@ module Gitlab
options = base_options options = base_options
options[:features] = [:issues, :merge_requests] options[:features] = [:issues, :merge_requests]
search(Milestone, query, options, page: page, per_page: per_page) Milestone.elastic_search(query, options: options)
end end
end end
# See the comment for #commits for more info on why we memoize this way def merge_requests
def merge_requests(page: 1, per_page: 20)
strong_memoize(:merge_requests) do strong_memoize(:merge_requests) do
search(MergeRequest, query, base_options.merge(project_ids: non_guest_project_ids), page: page, per_page: per_page) options = base_options.merge(project_ids: non_guest_project_ids)
MergeRequest.elastic_search(query, options: options)
end end
end end
# See the comment for #commits for more info on why we memoize this way
def blobs def blobs
return Kaminari.paginate_array([]) if query.blank? return Kaminari.paginate_array([]) if query.blank?
...@@ -226,7 +191,6 @@ module Gitlab ...@@ -226,7 +191,6 @@ module Gitlab
end end
end end
# See the comment for #commits for more info on why we memoize this way
def wiki_blobs def wiki_blobs
return Kaminari.paginate_array([]) if query.blank? return Kaminari.paginate_array([]) if query.blank?
......
require 'spec_helper' require 'spec_helper'
describe 'Global elastic search', :elastic do describe 'Global elastic search' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) } let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
before do before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true) stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
Gitlab::Elastic::Helper.create_empty_index
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
end end
after do after do
Gitlab::Elastic::Helper.delete_index
stub_ee_application_setting(elasticsearch_search: false, elasticsearch_indexing: false) stub_ee_application_setting(elasticsearch_search: false, elasticsearch_indexing: false)
end end
shared_examples 'a pure Elasticsearch result' do
it 'avoids N+1 database queries' do
create(object, creation_args)
Gitlab::Elastic::Helper.refresh_index
control_count = ActiveRecord::QueryRecorder.new { visit path }.count
create_list(object, 10, creation_args)
Gitlab::Elastic::Helper.refresh_index
control_count = control_count + (10 * query_count_multiplier) + 1
expect { visit path }.not_to exceed_query_limit(control_count)
end
end
describe 'I do not overload the database' do
context 'searching issues' do
let(:object) { :issue }
let(:creation_args) { { project: project, title: 'initial' } }
let(:path) { search_path(search: 'initial', scope: 'issues') }
let(:query_count_multiplier) { 0 }
it_behaves_like 'a pure Elasticsearch result'
end
context 'searching projects' do
let(:object) { :project }
let(:creation_args) { { namespace: user.namespace } }
let(:path) { search_path(search: 'project*', scope: 'projects') }
# Each Project requires 4 extra queries: one for each "count" (forks, open MRs, open Issues) and one for access level
let(:query_count_multiplier) { 4 }
it_behaves_like 'a pure Elasticsearch result'
end
context 'searching merge requests' do
it 'avoids N+1 database queries' do
path = search_path(search: 'initial', scope: 'merge_requests')
create(:merge_request, title: 'initial', source_project: project)
Gitlab::Elastic::Helper.refresh_index
control_count = ActiveRecord::QueryRecorder.new { visit path }.count
merge_requests = create_list(:merge_request, 10, title: 'initial')
merge_requests.each { |mr| mr.target_project.add_maintainer(user) }
Gitlab::Elastic::Helper.refresh_index
# Each MR loaded has a Route load that has been tricky to track down
expect { visit path }.not_to exceed_query_limit(control_count + 11)
end
end
context 'searching milestones' do
let(:object) { :milestone }
let(:creation_args) { { project: project } }
let(:path) { search_path(search: 'milestone*', scope: 'milestones') }
let(:query_count_multiplier) { 0 }
it_behaves_like 'a pure Elasticsearch result'
end
end
describe 'I search through the issues and I see pagination' do describe 'I search through the issues and I see pagination' do
before do before do
create_list(:issue, 21, project: project, title: 'initial') create_list(:issue, 21, project: project, title: 'initial')
......
...@@ -162,31 +162,31 @@ describe Gitlab::Elastic::ProjectSearchResults do ...@@ -162,31 +162,31 @@ describe Gitlab::Elastic::ProjectSearchResults do
it 'does not list project confidential issues for non project members' do it 'does not list project confidential issues for non project members' do
results = described_class.new(non_member, query, project.id) results = described_class.new(non_member, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).not_to include security_issue_1.id expect(issues).not_to include security_issue_1
expect(issues).not_to include security_issue_2.id expect(issues).not_to include security_issue_2
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
end end
it 'lists project confidential issues for author' do it 'lists project confidential issues for author' do
results = described_class.new(author, query, project.id) results = described_class.new(author, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).to include security_issue_1.id expect(issues).to include security_issue_1
expect(issues).not_to include security_issue_2.id expect(issues).not_to include security_issue_2
expect(results.issues_count).to eq 2 expect(results.issues_count).to eq 2
end end
it 'lists project confidential issues for assignee' do it 'lists project confidential issues for assignee' do
results = described_class.new(assignee, query, project.id) results = described_class.new(assignee, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).not_to include security_issue_1.id expect(issues).not_to include security_issue_1
expect(issues).to include security_issue_2.id expect(issues).to include security_issue_2
expect(results.issues_count).to eq 2 expect(results.issues_count).to eq 2
end end
...@@ -194,11 +194,11 @@ describe Gitlab::Elastic::ProjectSearchResults do ...@@ -194,11 +194,11 @@ describe Gitlab::Elastic::ProjectSearchResults do
project.add_developer(member) project.add_developer(member)
results = described_class.new(member, query, project.id) results = described_class.new(member, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).to include security_issue_1.id expect(issues).to include security_issue_1
expect(issues).to include security_issue_2.id expect(issues).to include security_issue_2
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
end end
...@@ -206,21 +206,21 @@ describe Gitlab::Elastic::ProjectSearchResults do ...@@ -206,21 +206,21 @@ describe Gitlab::Elastic::ProjectSearchResults do
project.add_guest(member) project.add_guest(member)
results = described_class.new(member, query, project.id) results = described_class.new(member, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).not_to include security_issue_1.id expect(issues).not_to include security_issue_1
expect(issues).not_to include security_issue_2.id expect(issues).not_to include security_issue_2
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
end end
it 'lists all project issues for admin' do it 'lists all project issues for admin' do
results = described_class.new(admin, query, project.id) results = described_class.new(admin, query, project.id)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue.id expect(issues).to include issue
expect(issues).to include security_issue_1.id expect(issues).to include security_issue_1
expect(issues).to include security_issue_2.id expect(issues).to include security_issue_2
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
end end
end end
......
...@@ -95,11 +95,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -95,11 +95,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue_1.id, @issue_2.id)
expect(issue_ids).not_to include(@issue_3.id)
expect(issues).to include @issue_1
expect(issues).to include @issue_2
expect(issues).not_to include @issue_3
expect(results.issues_count).to eq 2 expect(results.issues_count).to eq 2
end end
...@@ -112,11 +112,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -112,11 +112,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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) results = described_class.new(user, '#2', limit_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include @issue_2.id
expect(issue_ids).not_to include(@issue_1.id, @issue_3.id)
expect(issues).not_to include @issue_1
expect(issues).to include @issue_2
expect(issues).not_to include @issue_3
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
end end
...@@ -154,56 +154,53 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -154,56 +154,53 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include @issue.id expect(issues).to include @issue
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_1
@security_issue_2.id, expect(issues).not_to include @security_issue_2
@security_issue_3.id, expect(issues).not_to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include @issue.id expect(issues).to include @issue
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_1
@security_issue_2.id, expect(issues).not_to include @security_issue_2
@security_issue_3.id, expect(issues).not_to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_1.id, expect(issues).to include @security_issue_1
@security_issue_3.id) expect(issues).not_to include @security_issue_2
expect(issue_ids).not_to include(@security_issue_2.id, expect(issues).to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_2.id, expect(issues).not_to include @security_issue_1
@security_issue_4.id) expect(issues).to include @security_issue_2
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_3
@security_issue_3.id, expect(issues).to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
end end
...@@ -212,28 +209,27 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -212,28 +209,27 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_1.id, expect(issues).to include @security_issue_1
@security_issue_2.id, expect(issues).to include @security_issue_2
@security_issue_3.id) expect(issues).to include @security_issue_3
expect(issue_ids).not_to include(@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 4 expect(results.issues_count).to eq 4
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_project_ids)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include(@issue.id, expect(issues).to include @issue
@security_issue_1.id, expect(issues).to include @security_issue_1
@security_issue_2.id, expect(issues).to include @security_issue_2
@security_issue_3.id, expect(issues).to include @security_issue_3
@security_issue_4.id) expect(issues).to include @security_issue_4
expect(issues).not_to include @security_issue_5.id expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 5 expect(results.issues_count).to eq 5
end end
end end
...@@ -243,55 +239,53 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -243,55 +239,53 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include @issue.id expect(issues).to include @issue
expect(issues).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_1
@security_issue_2.id, expect(issues).not_to include @security_issue_2
@security_issue_3.id, expect(issues).not_to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
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_project_ids)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include @issue.id expect(issues).to include @issue
expect(issues).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_1
@security_issue_2.id, expect(issues).not_to include @security_issue_2
@security_issue_3.id, expect(issues).not_to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_3.id) expect(issues).not_to include @security_issue_1
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_2
@security_issue_2.id, expect(issues).to include @security_issue_3
@security_issue_4.id, expect(issues).not_to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 2 expect(results.issues_count).to eq 2
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_4.id) expect(issues).not_to include @security_issue_1
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).not_to include @security_issue_2
@security_issue_2.id, expect(issues).not_to include @security_issue_3
@security_issue_3.id, expect(issues).to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 2 expect(results.issues_count).to eq 2
end end
...@@ -300,28 +294,27 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -300,28 +294,27 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_3.id, expect(issues).not_to include @security_issue_1
@security_issue_4.id) expect(issues).not_to include @security_issue_2
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).to include @security_issue_3
@security_issue_2.id, expect(issues).to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
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_project_ids)
issue_ids = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issue_ids).to include(@issue.id, expect(issues).to include @issue
@security_issue_3.id, expect(issues).not_to include @security_issue_1
@security_issue_4.id) expect(issues).not_to include @security_issue_2
expect(issue_ids).not_to include(@security_issue_1.id, expect(issues).to include @security_issue_3
@security_issue_2.id, expect(issues).to include @security_issue_4
@security_issue_5.id) expect(issues).not_to include @security_issue_5
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
end end
end end
...@@ -358,10 +351,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -358,10 +351,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
merge_requests = results.objects('merge_requests').map(&:id) merge_requests = results.objects('merge_requests')
expect(merge_requests).to include(@merge_request_1.id, @merge_request_2.id) expect(merge_requests).to include @merge_request_1
expect(merge_requests).not_to include @merge_request_3.id expect(merge_requests).to include @merge_request_2
expect(merge_requests).not_to include @merge_request_3
expect(results.merge_requests_count).to eq 2 expect(results.merge_requests_count).to eq 2
end end
...@@ -374,10 +368,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -374,10 +368,11 @@ describe Gitlab::Elastic::SearchResults, :elastic do
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_project_ids)
merge_requests = results.objects('merge_requests').map(&:id) merge_requests = results.objects('merge_requests')
expect(merge_requests).to include @merge_request_2.id expect(merge_requests).not_to include @merge_request_1
expect(merge_requests).not_to include(@merge_request_1.id, @merge_request_3.id) expect(merge_requests).to include @merge_request_2
expect(merge_requests).not_to include @merge_request_3
expect(results.merge_requests_count).to eq 1 expect(results.merge_requests_count).to eq 1
end end
...@@ -683,17 +678,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -683,17 +678,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_project_ids)
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include(issue_1.id, issue_3.id, issue_4.id)
expect(issues).to include issue_1
expect(issues).to include issue_3
expect(issues).to include issue_4
expect(results.issues_count).to eq 3 expect(results.issues_count).to eq 3
# Unauthenticated search # Unauthenticated search
results = described_class.new(nil, 'project', []) results = described_class.new(nil, 'project', [])
issues = results.objects('issues').map(&:id) issues = results.objects('issues')
expect(issues).to include issue_4.id expect(issues).to include issue_4
expect(results.issues_count).to eq 1 expect(results.issues_count).to eq 1
end end
end end
...@@ -825,17 +821,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -825,17 +821,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_project_ids)
projects = results.objects('projects').map(&:id) milestones = results.objects('projects')
expect(projects).to include(internal_project.id, private_project2.id, public_project.id)
expect(milestones).to include internal_project
expect(milestones).to include private_project2
expect(milestones).to include public_project
expect(results.projects_count).to eq 3 expect(results.projects_count).to eq 3
# Unauthenticated search # Unauthenticated search
results = described_class.new(nil, 'project', []) results = described_class.new(nil, 'project', [])
projects = results.objects('projects').map(&:id) projects = results.objects('projects')
expect(projects).to include public_project.id expect(projects).to include public_project
expect(results.projects_count).to eq 1 expect(results.projects_count).to eq 1
end end
end end
...@@ -851,17 +848,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do ...@@ -851,17 +848,18 @@ describe Gitlab::Elastic::SearchResults, :elastic do
# Authenticated search # Authenticated search
results = described_class.new(user, 'project', limit_project_ids) results = described_class.new(user, 'project', limit_project_ids)
merge_requests = results.objects('merge_requests').map(&:id) merge_requests = results.objects('merge_requests')
expect(merge_requests).to include(merge_request_1.id, merge_request_3.id, merge_request_4.id)
expect(merge_requests).to include merge_request_1
expect(merge_requests).to include merge_request_3
expect(merge_requests).to include merge_request_4
expect(results.merge_requests_count).to eq 3 expect(results.merge_requests_count).to eq 3
# Unauthenticated search # Unauthenticated search
results = described_class.new(nil, 'project', []) results = described_class.new(nil, 'project', [])
merge_requests = results.objects('merge_requests').map(&:id) merge_requests = results.objects('merge_requests')
expect(merge_requests).to include merge_request_4.id expect(merge_requests).to include merge_request_4
expect(results.merge_requests_count).to eq 1 expect(results.merge_requests_count).to eq 1
end end
end end
......
...@@ -39,7 +39,6 @@ describe Milestone, :elastic do ...@@ -39,7 +39,6 @@ describe Milestone, :elastic do
expected_hash = milestone.attributes.extract!( expected_hash = milestone.attributes.extract!(
'id', 'id',
'iid',
'title', 'title',
'description', 'description',
'project_id', 'project_id',
......
...@@ -40,18 +40,18 @@ describe Search::GroupService, :elastic do ...@@ -40,18 +40,18 @@ describe Search::GroupService, :elastic do
end end
context 'finding projects by name' do context 'finding projects by name' do
subject { results.objects('projects').map(&:id) } subject { results.objects('projects') }
context 'in parent group' do context 'in parent group' do
let(:search_group) { nested_group.parent } let(:search_group) { nested_group.parent }
it { is_expected.to match_array([project1.id, project2.id, project3.id]) } it { is_expected.to match_array([project1, project2, project3]) }
end end
context 'in subgroup' do context 'in subgroup' do
let(:search_group) { nested_group } let(:search_group) { nested_group }
it { is_expected.to match_array([project1.id, project2.id]) } it { is_expected.to match_array([project1, project2]) }
end end
end end
end end
......
...@@ -85,10 +85,6 @@ module Gitlab ...@@ -85,10 +85,6 @@ module Gitlab
UsersFinder.new(current_user, search: query).execute UsersFinder.new(current_user, search: query).execute
end end
def display_options(_scope)
{}
end
private private
def projects def projects
......
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