diff --git a/.rubocop_todo/layout/extra_spacing.yml b/.rubocop_todo/layout/extra_spacing.yml index 2b352fdfd97d2bd9cc6e1beea3f2a651b0bc18d2..76ca09f9f14eac759852229c60bd1f7cd76e29f0 100644 --- a/.rubocop_todo/layout/extra_spacing.yml +++ b/.rubocop_todo/layout/extra_spacing.yml @@ -5,7 +5,6 @@ Layout/ExtraSpacing: - 'ee/app/graphql/mutations/geo/registries/update.rb' - 'ee/app/models/epic_issue.rb' - 'ee/app/models/merge_request/predictions.rb' - - 'ee/app/models/search/namespace_index_assignment.rb' - 'ee/app/services/dependencies/export_serializers/group_dependencies_service.rb' - 'ee/app/workers/pull_mirrors/reenable_configuration_worker.rb' - 'ee/lib/ee/gitlab/ci/pipeline/quota/size.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index b5f347f23a6c28b3c4f4d097b9b4fe2d7109ccfa..d06c7f5c375016713adf4bb2a827ac008b141c76 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -1647,7 +1647,6 @@ Layout/LineLength: - 'ee/spec/models/merge_requests/compliance_violation_spec.rb' - 'ee/spec/models/merge_requests/external_status_check_spec.rb' - 'ee/spec/models/namespace_setting_spec.rb' - - 'ee/spec/models/note_spec.rb' - 'ee/spec/models/packages/package_file_spec.rb' - 'ee/spec/models/project_import_data_spec.rb' - 'ee/spec/models/project_import_state_spec.rb' diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml index e5e5dadea0e5400ef03d6a5bea1b8485bb079b27..799c899f729402a4d961770fb4aabb0eed89c573 100644 --- a/.rubocop_todo/style/inline_disable_annotation.yml +++ b/.rubocop_todo/style/inline_disable_annotation.yml @@ -1345,7 +1345,6 @@ Style/InlineDisableAnnotation: - 'ee/app/models/protected_environments/approval_rules/summarizable.rb' - 'ee/app/models/protected_environments/authorizable.rb' - 'ee/app/models/requirements_management/requirement.rb' - - 'ee/app/models/search/namespace_index_assignment.rb' - 'ee/app/models/security/training.rb' - 'ee/app/models/vulnerabilities/finding.rb' - 'ee/app/policies/merge_request_diff_policy.rb' diff --git a/.rubocop_todo/style/redundant_parentheses.yml b/.rubocop_todo/style/redundant_parentheses.yml index 3bb507c1074631f97fc30d2e3a50c7cac179da05..b483df815ac53ed64a09d0607672821410278514 100644 --- a/.rubocop_todo/style/redundant_parentheses.yml +++ b/.rubocop_todo/style/redundant_parentheses.yml @@ -13,7 +13,6 @@ Style/RedundantParentheses: - 'ee/app/controllers/groups/billings_controller.rb' - 'ee/app/helpers/ee/projects_helper.rb' - 'ee/app/models/push_rule.rb' - - 'ee/app/models/search/index.rb' - 'ee/app/services/concerns/approval_rules/updater.rb' - 'ee/app/services/merge_trains/refresh_service.rb' - 'ee/lib/ee/gitlab/git_access.rb' diff --git a/.rubocop_todo/style/redundant_self.yml b/.rubocop_todo/style/redundant_self.yml index 6ffd55f942b920a2b1c8130c079fd94229bdaabc..20ddd0992005287db9ad38ec9a456b0548265e7a 100644 --- a/.rubocop_todo/style/redundant_self.yml +++ b/.rubocop_todo/style/redundant_self.yml @@ -202,7 +202,6 @@ Style/RedundantSelf: - 'ee/lib/ee/gitlab/auth/ldap/sync/proxy.rb' - 'ee/lib/ee/gitlab/auth/ldap/sync/users.rb' - 'ee/lib/ee/gitlab/background_migration/delete_invalid_epic_issues.rb' - - 'ee/lib/elastic/instance_proxy_util.rb' - 'ee/lib/elastic/latest/commit_config.rb' - 'ee/lib/elastic/latest/issue_config.rb' - 'ee/lib/elastic/latest/note_config.rb' diff --git a/config/feature_flags/development/search_index_partitioning_notes.yml b/config/feature_flags/development/search_index_partitioning_notes.yml deleted file mode 100644 index 1abd3be35c5ff3b93b23050d2384faec54e80c5c..0000000000000000000000000000000000000000 --- a/config/feature_flags/development/search_index_partitioning_notes.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: search_index_partitioning_notes -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112402 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392376 -milestone: '15.10' -type: development -group: group::global search -default_enabled: false diff --git a/db/docs/search_indices.yml b/db/docs/search_indices.yml index 4bb470c6f02990ab3b4d56d7be879089cb9be632..0260e6158d1d213b37ee90eaeb99d9283a7f2580 100644 --- a/db/docs/search_indices.yml +++ b/db/docs/search_indices.yml @@ -9,4 +9,4 @@ description: Represents an Advanced Search index introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113612/ milestone: '15.11' gitlab_schema: gitlab_main_cell -exempt_from_sharding: true # table scheduled for deletion https://gitlab.com/gitlab-org/gitlab/-/issues/473381 +exempt_from_sharding: true diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb index 5a0ecea07cfef33c0c6c5d3326b3357850f65a30..33aee173557d877b429765f35b0f63e18402b17e 100644 --- a/ee/app/models/ee/namespace.rb +++ b/ee/app/models/ee/namespace.rb @@ -50,13 +50,6 @@ module Namespace accepts_nested_attributes_for :gitlab_subscription, update_only: true accepts_nested_attributes_for :namespace_limit - has_many :search_index_assignments, class_name: 'Search::NamespaceIndexAssignment' - - has_many :search_indices, - through: :search_index_assignments, - source: 'index', - class_name: 'Search::Index' - has_one :audit_event_http_namespace_filter, class_name: 'AuditEvents::Streaming::HTTP::NamespaceFilter' has_one :audit_event_http_instance_namespace_filter, class_name: 'AuditEvents::Streaming::HTTP::Instance::NamespaceFilter' has_many :work_items_colors, inverse_of: :namespace, class_name: 'WorkItems::Color' @@ -539,10 +532,6 @@ def search_code_with_zoekt? ::Search::Zoekt.search?(self) end - def has_index_assignment?(type:) - ::Search::NamespaceIndexAssignment.has_assignment?(namespace: self, type: type) - end - def invalidate_elasticsearch_indexes_cache! ::Gitlab::CurrentSettings.invalidate_elasticsearch_indexes_cache_for_namespace!(self.id) end diff --git a/ee/app/models/ee/note.rb b/ee/app/models/ee/note.rb index 905bc2e6486680104078feb0538a3c41340f23e8..bc3583d09e10bb6e27c80e9a7d2768fc44029d40 100644 --- a/ee/app/models/ee/note.rb +++ b/ee/app/models/ee/note.rb @@ -37,11 +37,6 @@ def inc_relations_for_view(noteable = nil) end end - def search_index - namespace = project&.namespace || author.namespace # Personal snippets do not have a project - ::Search::IndexRegistry.index_for_namespace(namespace: namespace, type: ::Search::NoteIndex) - end - override :use_elasticsearch? def use_elasticsearch? !system && super diff --git a/ee/app/models/search/index.rb b/ee/app/models/search/index.rb deleted file mode 100644 index c14dca6656b3d3eceb4caa24c67e9b946d524125..0000000000000000000000000000000000000000 --- a/ee/app/models/search/index.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -module Search - class Index < ApplicationRecord - MAX_BUCKET_NUMBER = Search::INDEX_PARTITIONING_HASHING_MODULO - 1 - - has_many :namespace_index_assignments, foreign_key: :search_index_id, inverse_of: :index - has_many :namespaces, through: :namespace_index_assignments - - before_validation :set_path - - validates_presence_of :path, :type - validates :bucket_number, numericality: { - allow_nil: true, - only_integer: true, - greater_than_or_equal_to: 0, - less_than_or_equal_to: MAX_BUCKET_NUMBER - } - validates :type, uniqueness: { - scope: :path, message: 'violates unique constraint between [:type, :path]' - } - validates :type, uniqueness: { - scope: :bucket_number, message: 'violates unique constraint between [:type, :bucket_number]' - } - - after_create :create_advanced_search_index!, unless: :skip_create_advanced_search_index - attr_accessor :skip_create_advanced_search_index - - class << self - def route(hash:) - if hash > MAX_BUCKET_NUMBER - raise ArgumentError, "hash must be less than or equal to max bucket number: #{MAX_BUCKET_NUMBER}" - end - - next_index(bucket_number: hash) || create_default_index_with_max_bucket_number! - end - - def next_index(bucket_number:) - where(bucket_number: bucket_number...).order(:bucket_number).first - end - - def indexed_class - raise NotImplementedError, "#{name} does not have `self.indexed_class` defined" - end - - def create_default_index_with_max_bucket_number! - create!( - path: legacy_index_path, - bucket_number: MAX_BUCKET_NUMBER, - number_of_shards: legacy_index_settings.fetch(:number_of_shards), - number_of_replicas: legacy_index_settings.fetch(:number_of_replicas), - skip_create_advanced_search_index: true - ) - rescue ActiveRecord::RecordNotUnique - find_by!(path: legacy_index_path, bucket_number: MAX_BUCKET_NUMBER) - end - - def global_search_alias - indexed_class.__elasticsearch__.index_name - end - - private - - def legacy_index_path - new.helper.target_index_name(target: global_search_alias) - end - - def legacy_index_settings - @legacy_index_settings ||= new.settings(with_overrides: false).fetch(:index) - end - end - - def settings(with_overrides: true) - @settings ||= parse(config.settings).tap do |hsh| - if with_overrides - # This overrides application settings - hsh[:index][:number_of_shards] = number_of_shards - hsh[:index][:number_of_replicas] = number_of_replicas - end - end - end - - def mappings - @mappings ||= parse(config.mappings) - end - - def config - self.class.indexed_class.__elasticsearch__ - end - - def helper - @helper ||= ::Gitlab::Elastic::Helper.default - end - - private - - def parse(obj) - obj.to_hash.with_indifferent_access.deep_transform_values { |v| v.respond_to?(:call) ? v.call : v } - end - - def create_advanced_search_index! - helper.create_index( - index_name: path, - mappings: mappings, - settings: settings, - with_alias: false, - alias_name: :noop, - options: { - skip_if_exists: true, - meta: { - index_id: id, - index_type: type - } - } - ) - end - - def set_path - self.path ||= path_name_components.join('-') - end - - def path_name_components - [ - self.class.global_search_alias, - (bucket_number || 'na'), - Time.current.utc.strftime('%Y%m%d%H%M') - ] - end - end -end diff --git a/ee/app/models/search/index_registry.rb b/ee/app/models/search/index_registry.rb deleted file mode 100644 index 6338e3da17f741021c63861c6ff376845dabf259..0000000000000000000000000000000000000000 --- a/ee/app/models/search/index_registry.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -module Search - class IndexRegistry - DEFAULT_CACHE_DURATION = 1.minute - - def self.index_for_namespace(namespace:, type:) - new(namespace: namespace, type: type).index - end - - attr_reader :namespace, :type - - def initialize(namespace:, type:) - @namespace = namespace - @type = type - @cache_key = cache_key - end - - def index - type.new(fetch_index_attrs) - end - - private - - def fetch_index_attrs - cache_backend.fetch(cache_key, expires_in: DEFAULT_CACHE_DURATION) do - fetch_index_from_db.as_json - end - end - - def cache_backend - Gitlab::ProcessMemoryCache.cache_backend - end - - def cache_key - [self.class.name, :index_for_namespace, namespace.id, type.name] - end - - def fetch_index_from_db - fetch_assigned_index || assign_index - end - - def fetch_assigned_index - type.joins(:namespace_index_assignments) - .find_by(namespace_index_assignments: { namespace_id: namespace.id, index_type: type.name }) - end - - def assign_index - type.route(hash: namespace.hashed_root_namespace_id).tap do |idx| - ::Search::NamespaceIndexAssignment.assign_index(namespace: namespace, index: idx) - end - end - end -end diff --git a/ee/app/models/search/namespace_index_assignment.rb b/ee/app/models/search/namespace_index_assignment.rb deleted file mode 100644 index 96e280735387c554fde80d90f59ab354deb2c1c8..0000000000000000000000000000000000000000 --- a/ee/app/models/search/namespace_index_assignment.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Search - class NamespaceIndexAssignment < ApplicationRecord - belongs_to :index, foreign_key: :search_index_id, inverse_of: :namespace_index_assignments - belongs_to :namespace, optional: true - - before_validation :set_namespace_id_hashed - before_validation :set_namespace_id_non_nullable - before_validation :set_index_type - validate :only_root_namespaces_can_be_indexed - - validates_presence_of :search_index_id, :namespace_id - - validates :namespace_id, uniqueness: { - scope: :index_type, message: 'violates unique constraint between [:namespace_id, :index_type]' - } - validates :namespace_id, uniqueness: { - scope: :search_index_id, message: 'violates unique constraint between [:namespace_id, :search_index_id]' - } - - def self.assign_index(namespace:, index:) - safe_find_or_create_by!(namespace: namespace, index_type: index.type) do |record| # rubocop:disable Performance/ActiveRecordSubtransactionMethods - record.namespace_id_non_nullable = namespace.id - record.index = index - end - end - - private - - def set_namespace_id_hashed - self.namespace_id_hashed ||= namespace&.hashed_root_namespace_id - end - - def set_namespace_id_non_nullable - self.namespace_id_non_nullable ||= namespace&.id - end - - def set_index_type - self.index_type = index&.type if index.present? - end - - def only_root_namespaces_can_be_indexed - return if namespace.nil? || namespace.root? - - errors.add(:base, 'Only root namespaces can be assigned an index') - end - end -end diff --git a/ee/app/models/search/note_index.rb b/ee/app/models/search/note_index.rb deleted file mode 100644 index f2f09d9c50c2d3b15120f5a14ddfc2b0095a8eaa..0000000000000000000000000000000000000000 --- a/ee/app/models/search/note_index.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module Search - class NoteIndex < Index - self.allow_legacy_sti_class = true - - def self.indexed_class - ::Note - end - end -end diff --git a/ee/lib/elastic/instance_proxy_util.rb b/ee/lib/elastic/instance_proxy_util.rb index d529e414feab48ecfc95639a5cd71af557b059d8..86d0acba173995a412dd7cbf369635c9a34abe98 100644 --- a/ee/lib/elastic/instance_proxy_util.rb +++ b/ee/lib/elastic/instance_proxy_util.rb @@ -13,14 +13,14 @@ def initialize(target, use_separate_indices: false) config = version_namespace.const_get(const_name, false) - @index_name = load_index_name(config) + @index_name = config.index_name @document_type = config.document_type end ### Multi-version utils def real_class - self.singleton_class.superclass + singleton_class.superclass end def version_namespace @@ -39,29 +39,6 @@ def methods_for_one_write_target private - def load_index_name(config) - index_partitioning_enabled? ? search_write_index_path : config.index_name - end - - def index_partitioning_enabled? - case target - when Note - Feature.enabled?(:search_index_partitioning_notes, target.project) - else - false - end - end - - def search_write_index_path - search_index = target.search_index - - unless search_index.present? - raise ArgumentError, "Search index assignment was missing for #{target.class} with id: `#{target.id}`" - end - - search_index.path - end - # Some attributes are actually complicated methods. Bad data can cause # them to raise exceptions. When this happens, we still want the remainder # of the object to be saved, so silently swallow the errors diff --git a/ee/spec/factories/search/index.rb b/ee/spec/factories/search/index.rb deleted file mode 100644 index 15d7024dbf1ec8badfcd31cc325d43a4d98bd804..0000000000000000000000000000000000000000 --- a/ee/spec/factories/search/index.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :search_index, class: 'Search::Index' do - initialize_with { type.present? ? type.new : Search::Index.new } - sequence(:path) { |n| "index-path-#{n}" } - sequence(:bucket_number) { |n| n } - type { Search::NoteIndex } - end -end diff --git a/ee/spec/lib/elastic/latest/application_instance_proxy_spec.rb b/ee/spec/lib/elastic/latest/application_instance_proxy_spec.rb index 7556411a8baff07bddec10ba222fa913bad89f9b..7d53c8f3c2b0ab0a588fae4eef295daf1badb4c4 100644 --- a/ee/spec/lib/elastic/latest/application_instance_proxy_spec.rb +++ b/ee/spec/lib/elastic/latest/application_instance_proxy_spec.rb @@ -10,46 +10,6 @@ subject { included_class.new(target) } - describe '#index_name' do - subject { described_class.new(target, use_separate_indices: true) } - - let_it_be(:target) { create(:note) } - let(:search_index) do - instance_double(Search::NoteIndex, present?: search_index_present, path: path) - end - - let(:search_index_present) { true } - let(:path) { 'this-is-a-search-index-path' } - - before do - allow(target).to receive(:search_index).and_return(search_index) - end - - context 'when search index is valid' do - it 'returns search index path' do - expect(subject.index_name).to eq(search_index.path) - end - end - - context 'when search index is missing' do - let(:search_index_present) { false } - - it 'raises an error' do - expect { subject.index_name }.to raise_error ArgumentError, /index assignment was missing/i - end - end - - context 'when :search_index_partitioning_notes is disabled' do - before do - stub_feature_flags(search_index_partitioning_notes: false) - end - - it 'returns config index_name' do - expect(subject.index_name).to eq(Elastic::Latest::NoteConfig.index_name) - end - end - end - describe '#es_parent' do let(:target) { create(:merge_request) } diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb index 5618dac9484c0a2b9f15383a2eb30aa00500b0cc..95a16f41426ef4bfefbdba03a075fbae5616893d 100644 --- a/ee/spec/models/ee/namespace_spec.rb +++ b/ee/spec/models/ee/namespace_spec.rb @@ -143,15 +143,6 @@ end end - describe '#has_index_assignment?', feature_category: :global_search do - it 'delegates to ::Search::NamespaceIndexAssignment' do - index_type = Search::NoteIndex - expect(::Search::NamespaceIndexAssignment).to receive(:has_assignment?) - .with(namespace: namespace, type: index_type).and_return(true) - expect(namespace.has_index_assignment?(type: index_type)).to eq(true) - end - end - describe '#hashed_root_namespace_id', feature_category: :global_search do it 'delegates to Search.hash_namespace_id' do expect(::Search).to receive(:hash_namespace_id).with(namespace.root_ancestor.id).and_return 8_675_309 diff --git a/ee/spec/models/note_spec.rb b/ee/spec/models/note_spec.rb index df3e54b26f3b30d42b49cc082a66936d8050911a..a0b136313ef9d3b4aa2800054a0a371bd3a079b1 100644 --- a/ee/spec/models/note_spec.rb +++ b/ee/spec/models/note_spec.rb @@ -214,7 +214,8 @@ create(:note, noteable: vulnerability_2, project: vulnerability_2.project) create(:note, noteable: vulnerability_2, project: vulnerability_2.project) - expect(described_class.count_for_vulnerability_id([vulnerability_1.id, vulnerability_2.id])).to eq(vulnerability_1.id => 1, vulnerability_2.id => 2) + expect(described_class.count_for_vulnerability_id([vulnerability_1.id, + vulnerability_2.id])).to eq(vulnerability_1.id => 1, vulnerability_2.id => 2) end end @@ -271,32 +272,6 @@ end end - describe '#search_index', feature_category: :global_search do - let(:note) { create(:note) } - let(:search_index) { instance_double(::Search::NoteIndex) } - - it 'delegates to Search::IndexRegistry' do - expect(::Search::IndexRegistry).to receive(:index_for_namespace) - .with(namespace: note.project.namespace, type: ::Search::NoteIndex) - .and_return(search_index) - - expect(note.search_index).to eq(search_index) - end - - context 'when not assigned to a project' do - let(:user) { create(:user) } - let(:note) { described_class.new(author: user) } - - it 'uses author namespace' do - expect(::Search::IndexRegistry).to receive(:index_for_namespace) - .with(namespace: user.namespace, type: ::Search::NoteIndex) - .and_return(search_index) - - expect(note.search_index).to eq(search_index) - end - end - end - describe '#for_group_wiki?' do it 'returns true for a group-level wiki page' do expect(build_stubbed(:note_on_wiki_page, :on_group_level_wiki).for_group_wiki?).to be_truthy diff --git a/ee/spec/models/search/index_registry_spec.rb b/ee/spec/models/search/index_registry_spec.rb deleted file mode 100644 index 885a9d4276b60599836c5f8677d8a2208580b311..0000000000000000000000000000000000000000 --- a/ee/spec/models/search/index_registry_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Search::IndexRegistry, feature_category: :global_search do - describe '.index_for_namespace' do - let(:index) { build(:search_index, type: type) } - let(:type) { Search::NoteIndex } - let(:namespace) { create(:namespace) } - let(:cache_backend) { Gitlab::ProcessMemoryCache.cache_backend } - - context 'when an index is already assigned to a namespace' do - let!(:assignment) { Search::NamespaceIndexAssignment.assign_index(namespace: namespace, index: assigned_index) } - let(:assigned_index) { create(:search_index, type: type, path: 'assigned-index-path') } - - it 'returns the index in the index assignment' do - expect(described_class.index_for_namespace(namespace: namespace, type: type)).to eq(assigned_index) - end - end - - context 'when there is not an index assignment' do - let(:index) { create(:search_index, type: type) } - - it 'makes a new assignment and returns routed index for a namespace' do - expect(type).to receive(:route).with(hash: namespace.hashed_root_namespace_id).and_return(index) - expect(::Search::NamespaceIndexAssignment).to receive(:assign_index).with(namespace: namespace, index: index) - expect(described_class.index_for_namespace(namespace: namespace, type: type)).to eq(index) - end - end - - it 'uses cache correctly' do - expect(cache_backend).to receive(:fetch).with( - [described_class.name, :index_for_namespace, namespace.id, type.name], - expires_in: 1.minute - ).and_call_original - - described_class.index_for_namespace(namespace: namespace, type: type) - end - - it 'assigns the index when there is a cache miss' do - expect(type).to receive(:route).with(hash: namespace.hashed_root_namespace_id).and_return(index) - expect(Search::NamespaceIndexAssignment).to receive(:assign_index).with(namespace: namespace, index: index).once - described_class.index_for_namespace(namespace: namespace, type: type) - - expect(Search::NamespaceIndexAssignment).not_to receive(:assign_index) - - 5.times do - described_class.index_for_namespace(namespace: namespace, type: type) - end - end - end -end diff --git a/ee/spec/models/search/index_spec.rb b/ee/spec/models/search/index_spec.rb deleted file mode 100644 index 906f646b9d3efae3e612475fe75c708b29758de4..0000000000000000000000000000000000000000 --- a/ee/spec/models/search/index_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Search::Index, feature_category: :global_search do - describe '.indexed_class' do - it 'raises a NotImplementedError' do - expect { described_class.indexed_class }.to raise_error NotImplementedError - end - end -end diff --git a/ee/spec/models/search/namespace_index_assignment_spec.rb b/ee/spec/models/search/namespace_index_assignment_spec.rb deleted file mode 100644 index 061a456a7887431ac341a2ff2756d99084adf270..0000000000000000000000000000000000000000 --- a/ee/spec/models/search/namespace_index_assignment_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Search::NamespaceIndexAssignment, feature_category: :global_search do - let_it_be(:namespace) { create(:namespace) } - let_it_be(:index) { create(:search_index, type: Search::NoteIndex) } - let_it_be(:indexed_parent_namespace) { create(:group) } - let_it_be(:indexed_child_namespace) { create(:group, parent: indexed_parent_namespace) } - - let(:assignment) { described_class.new(index: index, namespace: namespace) } - - describe 'validations' do - it 'does not allow you to mark a subgroup as indexed' do - expect do - described_class.create!(index: index, namespace: indexed_child_namespace) - end.to raise_error(/Only root namespaces can be assigned an index/) - end - - it 'is valid with proper attributes' do - expect(assignment).to be_valid - end - - it 'is invalid when namespace is missing' do - assignment.namespace = nil - expect(assignment).not_to be_valid - end - - it 'is invalid when index is missing' do - assignment.index = nil - expect(assignment).not_to be_valid - end - - it 'is invalid when there is a duplicative assignment' do - next_assignment = assignment.dup - assignment.save! - expect(next_assignment).not_to be_valid - expect(next_assignment.errors.messages.fetch(:namespace_id)).to match_array([ - 'violates unique constraint between [:namespace_id, :index_type]', - 'violates unique constraint between [:namespace_id, :search_index_id]' - ]) - end - end - - describe '.assign_index' do - it 'calls safe_find_or_create_by! with correct arguments' do - expect(described_class).to receive(:safe_find_or_create_by!).with( - namespace: namespace, index_type: index.type - ).and_call_original - - described_class.assign_index(namespace: namespace, index: index) - - record = described_class.last - expect(record.namespace).to eq(namespace) - expect(record.index).to eq(index) - end - end - - describe '.set_namespace_id_hashed' do - it 'sets to namespace.hashed_root_namespace_id' do - expect(assignment.namespace_id_hashed).to be_nil - assignment.validate - expect(assignment.namespace_id_hashed).to eq(namespace.hashed_root_namespace_id) - end - end - - describe '.set_namespace_id_non_nullable' do - it 'sets to namespace id' do - expect(assignment.namespace_id_non_nullable).to be_nil - assignment.validate - expect(assignment.namespace_id_non_nullable).to eq(namespace.id) - end - end - - describe '.set_index_type' do - it 'sets to index type' do - expect(assignment.index_type).to be_nil - assignment.validate - expect(assignment.index_type).to eq(index.type) - end - end -end diff --git a/ee/spec/models/search/note_index_spec.rb b/ee/spec/models/search/note_index_spec.rb deleted file mode 100644 index cebc8a7cd19e877954dab43ef36de6d2afaa98d4..0000000000000000000000000000000000000000 --- a/ee/spec/models/search/note_index_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Search::NoteIndex, feature_category: :global_search do - it_behaves_like 'a search index' - - describe '.indexed_class' do - it 'is configured correctly' do - expect(described_class.indexed_class).to eq(Note) - end - end -end diff --git a/ee/spec/support/shared_examples/models/search/search_index_shared_examples.rb b/ee/spec/support/shared_examples/models/search/search_index_shared_examples.rb deleted file mode 100644 index f5b250e470685c1b521c5589f520ed05379fbbb8..0000000000000000000000000000000000000000 --- a/ee/spec/support/shared_examples/models/search/search_index_shared_examples.rb +++ /dev/null @@ -1,264 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'a search index' do - let(:indexed_class) { described_class.indexed_class } - let(:max_bucket_number) { described_class::MAX_BUCKET_NUMBER } - let(:helper) { instance_double(::Gitlab::Elastic::Helper) } - let(:index_path) { 'test-index-path' } - let(:index) { build(:search_index, type: described_class, number_of_shards: 5) } - let(:config) { index.config } - - before do - allow(::Gitlab::Elastic::Helper).to receive(:default).and_return(helper) - allow(helper).to receive(:target_index_name) - .with(target: indexed_class.__elasticsearch__.index_name).and_return(index_path) - allow(helper).to receive(:create_index) - end - - describe 'creating index in Elasticsearch' do - it 'creates an index in Elasticsearch when saving to DB' do - index_id = 123 - allow(index).to receive(:id).and_return index_id - - expect(helper).to receive(:create_index).with( - alias_name: :noop, - index_name: index.path, - mappings: index.mappings, - settings: index.settings, - with_alias: false, - options: { - skip_if_exists: true, - meta: { - index_id: index_id, - index_type: index.type - } - } - ) - - index.save! - end - - context 'when Elasticsearch is unreachable' do - it 'rolls back the transaction and raises the Elasticsearch error' do - err = Elasticsearch::Transport::Transport::Error.new("boom") - expect(helper).to receive(:create_index).and_raise(err) - expect { index.save! }.to raise_error(err) - expect(described_class.count).to eq(0) - end - end - - context 'when skip_create_advanced_search_index is set to true' do - it 'does not create Elasticsearch index' do - index.skip_create_advanced_search_index = true - expect(helper).not_to receive(:create_index) - index.save! - end - end - end - - describe '#config' do - it 'is the Elasticsearch class proxy for indexed class' do - expect(config).to eq(described_class.indexed_class.__elasticsearch__) - end - end - - describe 'Elasticsearch related settings' do - let(:config) { instance_double(Elastic::MultiVersionClassProxy, mappings: mappings, settings: settings) } - let(:mappings) { { mapping: 'mapping' }.with_indifferent_access } - let(:settings) { { setting: 'setting', index: {} }.with_indifferent_access } - - before do - allow(index).to receive(:config).and_return(config) - end - - describe 'mappings' do - it "delegates to the config's mappings" do - expect(index.mappings).to eq(mappings) - end - end - - describe 'settings' do - it "delegates to the config's settings with shard and replica settings added" do - expect(index.settings).to eq(settings.merge( - index: { number_of_replicas: index.number_of_replicas, number_of_shards: index.number_of_shards } - )) - end - end - end - - describe '#path', :freeze_time do - let(:global_search_alias) { index.class.global_search_alias } - let(:index) { build(:search_index, type: described_class, bucket_number: bucket_number, path: nil) } - let(:bucket_number) { 5 } - let(:time) { Time.now.utc.strftime('%Y%m%d%H%M') } - - it 'has a default value that is set after validations' do - expect(index.path).to be_nil - index.validate! - expect(index.path).to eq("#{global_search_alias}-#{index.bucket_number}-#{time}") - end - - context 'when bucket_number is nil' do - let(:bucket_number) { nil } - - it 'sets the correct default value after validations' do - expect(index.path).to be_nil - index.validate! - expect(index.path).to eq("#{global_search_alias}-na-#{time}") - end - end - end - - describe '#helper' do - it 'is Elastic helper' do - expect(index.helper).to eq(helper) - end - end - - describe 'validations' do - it 'is valid with proper attributes' do - expect(index).to be_valid - end - - it 'is invalid when missing type' do - index.type = nil - expect(index).not_to be_valid - end - - it 'is invalid when there is a duplicative index' do - next_index = index.dup - index.save! - - expect(next_index).not_to be_valid - expect(next_index.errors.messages.fetch(:type)).to match_array([ - "violates unique constraint between [:type, :path]", - "violates unique constraint between [:type, :bucket_number]" - ]) - end - - describe '#bucket_number' do - it 'is valid when nil' do - index.bucket_number = nil - expect(index).to be_valid - end - - it 'is valid when given a number that is less than or equal to hashing modulo' do - index.bucket_number = 0 - expect(index).to be_valid - - index.bucket_number = max_bucket_number - expect(index).to be_valid - end - - it 'is invalid when given a float' do - index.bucket_number = 8675.309 - expect(index).to be_invalid - end - - it 'is invalid when given a number that is greater than hashing modulo' do - index.bucket_number = max_bucket_number + 1 - expect(index).to be_invalid - end - - it 'is invalid when given a number that is less than zero' do - index.bucket_number = -100 - expect(index).to be_invalid - end - end - end - - describe '.next_index' do - let(:index_one) { create(:search_index, type: described_class, bucket_number: 123) } - let(:index_two) { create(:search_index, type: described_class, bucket_number: 300) } - - before do - index_one - index_two - end - - it 'returns the first index ordered by bucket number' do - expect(described_class.next_index(bucket_number: 124)).to eq(index_two) - expect(described_class.next_index(bucket_number: 300)).to eq(index_two) - end - - it 'returns nil if there are no indices with bucket_number greater than the one provided' do - expect(described_class.next_index(bucket_number: 301)).to be_nil - expect(described_class.next_index(bucket_number: 1_234)).to be_nil - end - end - - describe '.route' do - context 'when there are not any indices' do - it 'creates a default index' do - expect(described_class).to receive(:create_default_index_with_max_bucket_number!) - described_class.route(hash: 123) - end - end - - context 'when there are multiple indices in the DB' do - let(:index_one) { create(:search_index, type: described_class, bucket_number: 123) } - let(:index_two) { create(:search_index, type: described_class, bucket_number: 300) } - let(:default_index) { create(:search_index, type: described_class, bucket_number: max_bucket_number) } - - before do - index_one - index_two - default_index - end - - it 'returns the correct index' do - expect(described_class.route(hash: -10)).to eq(index_one) - expect(described_class.route(hash: 0)).to eq(index_one) - expect(described_class.route(hash: 90)).to eq(index_one) - expect(described_class.route(hash: 123)).to eq(index_one) - expect(described_class.route(hash: 124)).to eq(index_two) - expect(described_class.route(hash: 300)).to eq(index_two) - expect(described_class.route(hash: 301)).to eq(default_index) - expect(described_class.route(hash: 1_000)).to eq(default_index) - expect(described_class.route(hash: max_bucket_number)).to eq(default_index) - end - end - - context 'when given a bucket number that is outside maximum' do - it 'raises an ArgumentError' do - expect { described_class.route(hash: max_bucket_number + 1) }.to raise_error( - ArgumentError, /hash must be less than or equal to max bucket number: #{max_bucket_number}/o - ) - end - end - end - - describe '.create_default_index_with_max_bucket_number!' do - it 'calls create! with correct arguments' do - expect(described_class).to receive(:create!).with( - path: index_path, - bucket_number: max_bucket_number, - number_of_replicas: 1, - number_of_shards: 5, - skip_create_advanced_search_index: true - ).and_return :result - - expect(described_class.create_default_index_with_max_bucket_number!).to eq(:result) - end - - it 'fetches index with matching attributes if there is a conflict' do - expect(described_class).to receive(:create!).with( - path: index_path, - bucket_number: max_bucket_number, - number_of_replicas: 1, - number_of_shards: 5, - skip_create_advanced_search_index: true - ).and_raise ActiveRecord::RecordNotUnique - - expect(described_class).to receive(:find_by!).with(path: index_path, bucket_number: max_bucket_number) - .and_return :other_result - - expect(described_class.create_default_index_with_max_bucket_number!).to eq(:other_result) - end - - it 'does not create an Elasticsearch index' do - expect(helper).not_to receive(:create_index) - described_class.create_default_index_with_max_bucket_number! - end - end -end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 9008f1b18e6a276acc6e14aef18a37571ea57e32..51737925156c78126ebdbb6615df9ff50c979a60 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -1363,7 +1363,6 @@ - './ee/spec/models/namespaces/free_user_cap_spec.rb' - './ee/spec/models/namespaces/storage/root_excess_size_spec.rb' - './ee/spec/models/namespaces/storage/root_size_spec.rb' -- './ee/spec/models/note_spec.rb' - './ee/spec/models/packages/package_file_spec.rb' - './ee/spec/models/path_lock_spec.rb' - './ee/spec/models/plan_spec.rb'