From e9cb7b2fd91bd5944d8044fde0720cafa5c883b8 Mon Sep 17 00:00:00 2001 From: Molly Struve Date: Wed, 23 Sep 2020 12:27:50 -0500 Subject: [PATCH] [deploy] Refactor:Remove Reaction Search Code (#10377) --- app/models/article.rb | 2 - app/models/reaction.rb | 6 - app/serializers/search/reaction_serializer.rb | 30 ----- .../data_sync/elasticsearch/article.rb | 38 ------ app/services/data_sync/elasticsearch/tag.rb | 1 - app/services/data_sync/elasticsearch/user.rb | 1 - app/services/search/cluster.rb | 1 - .../search/query_builders/reaction.rb | 92 ------------- app/services/search/reaction.rb | 47 ------- ...01194251_reindex_reading_list_reactions.rb | 11 +- spec/lib/acts_as_taggable_on/tag_spec.rb | 4 - .../reindex_reading_list_reactions_spec.rb | 18 --- spec/models/article_spec.rb | 43 ------ spec/models/reaction_spec.rb | 56 -------- spec/models/tag_spec.rb | 4 - .../search/reaction_serializer_spec.rb | 32 ----- .../data_sync/elasticsearch/article_spec.rb | 25 ---- spec/services/moderator/merge_user_spec.rb | 4 - .../search/query_builders/reaction_spec.rb | 92 ------------- spec/services/search/reaction_spec.rb | 124 ------------------ spec/services/users/delete_spec.rb | 14 -- spec/workers/search/bulk_index_worker_spec.rb | 16 +-- 22 files changed, 14 insertions(+), 647 deletions(-) delete mode 100644 app/serializers/search/reaction_serializer.rb delete mode 100644 app/services/data_sync/elasticsearch/article.rb delete mode 100644 app/services/search/query_builders/reaction.rb delete mode 100644 app/services/search/reaction.rb delete mode 100644 spec/lib/data_update_scripts/reindex_reading_list_reactions_spec.rb delete mode 100644 spec/serializers/search/reaction_serializer_spec.rb delete mode 100644 spec/services/data_sync/elasticsearch/article_spec.rb delete mode 100644 spec/services/search/query_builders/reaction_spec.rb delete mode 100644 spec/services/search/reaction_spec.rb diff --git a/app/models/article.rb b/app/models/article.rb index 241fbde41..aaafb496a 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -8,7 +8,6 @@ class Article < ApplicationRecord SEARCH_SERIALIZER = Search::ArticleSerializer SEARCH_CLASS = Search::FeedContent - DATA_SYNC_CLASS = DataSync::Elasticsearch::Article acts_as_taggable_on :tags resourcify @@ -91,7 +90,6 @@ class Article < ApplicationRecord } after_commit :async_score_calc, :update_main_image_background_hex, :touch_collection, on: %i[create update] after_commit :index_to_elasticsearch, on: %i[create update] - after_commit :sync_related_elasticsearch_docs, on: %i[create update] after_commit :remove_from_elasticsearch, on: [:destroy] serialize :cached_user diff --git a/app/models/reaction.rb b/app/models/reaction.rb index 83c0c81c5..ed08db93e 100644 --- a/app/models/reaction.rb +++ b/app/models/reaction.rb @@ -1,14 +1,10 @@ class Reaction < ApplicationRecord - include Searchable BASE_POINTS = { "vomit" => -50.0, "thumbsup" => 5.0, "thumbsdown" => -10.0 }.freeze - SEARCH_SERIALIZER = Search::ReactionSerializer - SEARCH_CLASS = Search::Reaction - CATEGORIES = %w[like readinglist unicorn thinking hands thumbsup thumbsdown vomit].freeze PUBLIC_CATEGORIES = %w[like readinglist unicorn thinking hands].freeze REACTABLE_TYPES = %w[Comment Article User].freeze @@ -41,8 +37,6 @@ class Reaction < ApplicationRecord after_create_commit :record_field_test_event after_commit :async_bust after_commit :bust_reactable_cache, :update_reactable, on: %i[create update] - after_commit :index_to_elasticsearch, if: :indexable?, on: %i[create update] - after_commit :remove_from_elasticsearch, if: :indexable?, on: [:destroy] class << self def count_for_article(id) diff --git a/app/serializers/search/reaction_serializer.rb b/app/serializers/search/reaction_serializer.rb deleted file mode 100644 index e86cfe95d..000000000 --- a/app/serializers/search/reaction_serializer.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Search - class ReactionSerializer < ApplicationSerializer - attributes :id, :created_at, :category, :status, :user_id - - attribute :reactable do |reaction| - reactable = reaction.reactable - tags = if reactable.respond_to?(:tags) - reactable.tags.map do |tag| - { name: tag.name, keywords_for_search: tag.keywords_for_search } - end - else - [] - end - - { - id: reactable.id, - body_text: reactable.respond_to?(:body_text) ? reactable.body_text : reactable.body_markdown, - class_name: reactable.class.name, - path: reactable.path, - published_date_string: reactable.readable_publish_date, - reading_time: reactable.respond_to?(:reading_time) ? reactable.reading_time : 1, - tags: tags, - title: reactable.title, - user: NestedUserSerializer.new(reactable.user).serializable_hash.dig( - :data, :attributes - ) - } - end - end -end diff --git a/app/services/data_sync/elasticsearch/article.rb b/app/services/data_sync/elasticsearch/article.rb deleted file mode 100644 index bd26987ed..000000000 --- a/app/services/data_sync/elasticsearch/article.rb +++ /dev/null @@ -1,38 +0,0 @@ -module DataSync - module Elasticsearch - class Article < Base - RELATED_DOCS = %i[ - reactions - ].freeze - - SHARED_FIELDS = %i[ - body_markdown - path - published - reading_time - tag_list - title - ].freeze - - private - - def sync_related_documents - RELATED_DOCS.each do |relation_name| - if updated_record.published - __send__(relation_name).find_each(&:index_to_elasticsearch) - elsif updated_fields.key?(:published) - __send__(relation_name).find_each(&:remove_from_elasticsearch) - end - end - end - - def sync_needed? - updated_fields.slice(*SHARED_FIELDS).any? && reactions.any? - end - - def reactions - updated_record.reactions.readinglist - end - end - end -end diff --git a/app/services/data_sync/elasticsearch/tag.rb b/app/services/data_sync/elasticsearch/tag.rb index 8f1ae3bd1..2b486856d 100644 --- a/app/services/data_sync/elasticsearch/tag.rb +++ b/app/services/data_sync/elasticsearch/tag.rb @@ -4,7 +4,6 @@ module DataSync RELATED_DOCS = %i[ articles podcast_episodes - reactions ].freeze SHARED_FIELDS = %i[ diff --git a/app/services/data_sync/elasticsearch/user.rb b/app/services/data_sync/elasticsearch/user.rb index a2514fc48..2bce507d9 100644 --- a/app/services/data_sync/elasticsearch/user.rb +++ b/app/services/data_sync/elasticsearch/user.rb @@ -3,7 +3,6 @@ module DataSync class User < Base RELATED_DOCS = %i[ articles - reactions podcast_episodes chat_channel_memberships comments diff --git a/app/services/search/cluster.rb b/app/services/search/cluster.rb index 9aea2ea67..f1457be23 100644 --- a/app/services/search/cluster.rb +++ b/app/services/search/cluster.rb @@ -4,7 +4,6 @@ module Search Search::ChatChannelMembership, Search::Listing, Search::FeedContent, - Search::Reaction, Search::Tag, Search::User, ].freeze diff --git a/app/services/search/query_builders/reaction.rb b/app/services/search/query_builders/reaction.rb deleted file mode 100644 index aa641af73..000000000 --- a/app/services/search/query_builders/reaction.rb +++ /dev/null @@ -1,92 +0,0 @@ -module Search - module QueryBuilders - class Reaction < QueryBase - QUERY_KEYS = { - search_fields: [ - "reactable.tags.keywords_for_search", - "reactable.tags.name^3", - "reactable.body_text^2", - "reactable.title^6", - "reactable.user.name", - "reactable.user.username", - ] - }.freeze - - # Search keys from our controllers may not match what we have stored in Elasticsearch so we map them here, - # this allows us to change our Elasticsearch docs without worrying about the frontend - TERM_KEYS = { - category: "category", - tag_names: "reactable.tags.name", - user_id: "user_id", - status: "status" - }.freeze - - DEFAULT_PARAMS = { - sort_by: "created_at", - sort_direction: "desc", - size: 0 - }.freeze - - SOURCE = %i[ - id - reactable.path - reactable.published_date_string - reactable.reading_time - reactable.tags - reactable.title - reactable.user - ].freeze - - attr_accessor :params, :body - - def initialize(params:) - super() - - @params = params.deep_symbolize_keys - - # Default to only readinglist reactions - @params[:category] = "readinglist" - - build_body - end - - private - - def build_queries - @body[:query] = { bool: {} } - @body[:query][:bool][:filter] = terms_keys if terms_keys_present? - @body[:query][:bool][:must] = query_conditions if query_keys_present? - end - - def terms_keys_present? - TERM_KEYS.detect { |key, _| @params[key].present? } - end - - def terms_keys - TERM_KEYS.flat_map do |term_key, search_key| - next unless @params.key? term_key - - values = Array.wrap(@params[term_key]) - - if params[:tag_boolean_mode] == "all" && term_key == :tag_names - values.map { |val| { term: { search_key => val } } } - else - { terms: { search_key => values } } - end - end.compact - end - - def query_hash(key, fields) - { - simple_query_string: { - query: key, - fields: fields, - lenient: true, - analyze_wildcard: true, - minimum_should_match: 2 - } - } - end - end - end -end diff --git a/app/services/search/reaction.rb b/app/services/search/reaction.rb deleted file mode 100644 index e9748d80f..000000000 --- a/app/services/search/reaction.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Search - class Reaction < Base - INDEX_NAME = "reactions_#{Rails.env}".freeze - INDEX_ALIAS = "reactions_#{Rails.env}_alias".freeze - MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/reactions.json"), symbolize_names: true).freeze - DEFAULT_PAGE = 0 - DEFAULT_PER_PAGE = 80 - - class << self - def search_documents(params:) - set_query_size(params) - query_hash = "Search::QueryBuilders::#{name.demodulize}".safe_constantize.new(params: params).as_hash - - results = search(body: query_hash) - hits = results.dig("hits", "hits").map { |hit| prepare_doc(hit) } - { - "reactions" => paginate_hits(hits, params), - "total" => results.dig("hits", "total", "value") - } - end - - private - - def index_settings - if Rails.env.production? - { - number_of_shards: 10, - number_of_replicas: 1 - } - else - { - number_of_shards: 1, - number_of_replicas: 0 - } - end - end - - def dynamic_index_settings - if Rails.env.production? - { refresh_interval: "2s" } - else - { refresh_interval: "1s" } - end - end - end - end -end diff --git a/lib/data_update_scripts/20200901194251_reindex_reading_list_reactions.rb b/lib/data_update_scripts/20200901194251_reindex_reading_list_reactions.rb index 59a7008b8..abdeab3fb 100644 --- a/lib/data_update_scripts/20200901194251_reindex_reading_list_reactions.rb +++ b/lib/data_update_scripts/20200901194251_reindex_reading_list_reactions.rb @@ -1,11 +1,12 @@ module DataUpdateScripts class ReindexReadingListReactions def run - Reaction.readinglist.select(:id).in_batches do |batch| - Search::BulkIndexWorker.set(queue: :default).perform_async( - "Reaction", batch.ids - ) - end + # Reactions are no longer indexed in Elasticsearch + # Reaction.readinglist.select(:id).in_batches do |batch| + # Search::BulkIndexWorker.set(queue: :default).perform_async( + # "Reaction", batch.ids + # ) + # end end end end diff --git a/spec/lib/acts_as_taggable_on/tag_spec.rb b/spec/lib/acts_as_taggable_on/tag_spec.rb index 6e6cfdd1b..312d47309 100644 --- a/spec/lib/acts_as_taggable_on/tag_spec.rb +++ b/spec/lib/acts_as_taggable_on/tag_spec.rb @@ -15,16 +15,12 @@ RSpec.describe ActsAsTaggableOn::Tag, type: :lib do podcast_episode = create(:podcast_episode) tag = article.tags.first podcast_episode.tags << tag - reaction = create(:reaction, reactable: article, category: "readinglist") new_keywords = "keyword1, keyword2, keyword3" sidekiq_perform_enqueued_jobs tag.update(keywords_for_search: new_keywords) sidekiq_perform_enqueued_jobs expect(collect_keywords(article)).to include(new_keywords) - expect( - reaction.elasticsearch_doc.dig("_source", "reactable", "tags").flat_map { |t| t["keywords_for_search"] }, - ).to include(new_keywords) expect(collect_keywords(podcast_episode)).to include(new_keywords) end end diff --git a/spec/lib/data_update_scripts/reindex_reading_list_reactions_spec.rb b/spec/lib/data_update_scripts/reindex_reading_list_reactions_spec.rb deleted file mode 100644 index 84a622f8a..000000000 --- a/spec/lib/data_update_scripts/reindex_reading_list_reactions_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "rails_helper" -require Rails.root.join("lib/data_update_scripts/20200901194251_reindex_reading_list_reactions.rb") - -describe DataUpdateScripts::ReindexReadingListReactions, elasticsearch: "Reaction" do - it "indexes feed content(articles, comments, podcast episodes) to Elasticsearch" do - reactions = create_list(:reaction, 3, category: "readinglist") - Sidekiq::Worker.clear_all - - reactions.each do |reaction| - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - end - - sidekiq_perform_enqueued_jobs { described_class.new.run } - reactions.each do |reaction| - expect(reaction.elasticsearch_doc).not_to be_nil - end - end -end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 9ea40286d..1c39db144 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -68,49 +68,6 @@ RSpec.describe Article, type: :model do article.destroy end end - - it "on update syncs elasticsearch data" do - allow(article).to receive(:sync_related_elasticsearch_docs) - article.save - expect(article).to have_received(:sync_related_elasticsearch_docs) - end - end - - describe "#after_update_commit" do - it "if article is unpublished removes reading list reactions from index" do - reaction = create(:reaction, reactable: article, category: "readinglist") - sidekiq_perform_enqueued_jobs - expect(reaction.elasticsearch_doc).not_to be_nil - - unpublished_body = "---\ntitle: Hellohnnnn#{rand(1000)}\npublished: false\ntags: hiring\n---\n\nHello" - article.update(body_markdown: unpublished_body) - sidekiq_perform_enqueued_jobs - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - end - - it "if article is published indexes reading list reactions" do - reaction = create(:reaction, reactable: article, category: "readinglist") - sidekiq_perform_enqueued_jobs - unpublished_body = "---\ntitle: Hellohnnnn#{rand(1000)}\npublished: false\ntags: hiring\n---\n\nHello" - article.update(body_markdown: unpublished_body) - sidekiq_perform_enqueued_jobs - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - - published_body = "---\ntitle: Hellohnnnn#{rand(1000)}\npublished: true\ntags: hiring\n---\n\nHello" - article.update(body_markdown: published_body) - sidekiq_perform_enqueued_jobs - expect(reaction.elasticsearch_doc).not_to be_nil - end - - it "indexes reaction if a REACTION_INDEXED_FIELDS is changed" do - reaction = create(:reaction, reactable: article, category: "readinglist") - allow(article).to receive(:index_to_elasticsearch) - allow(article.user).to receive(:index_to_elasticsearch) - - sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: ["Reaction", reaction.id]) do - article.update(body_markdown: "---\ntitle: NEW TITLE#{rand(1000)}\n") - end - end end context "when published" do diff --git a/spec/models/reaction_spec.rb b/spec/models/reaction_spec.rb index 1724d96a5..3026f6693 100644 --- a/spec/models/reaction_spec.rb +++ b/spec/models/reaction_spec.rb @@ -87,62 +87,6 @@ RSpec.describe Reaction, type: :model do end end - describe "#after_commit" do - context "when category is readingList and reactable is published" do - it "on update enqueues job to index reaction to elasticsearch" do - reaction.save - sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, reaction.id]) do - reaction.update(category: "readinglist") - end - end - - it "on create enqueues job to index reaction to elasticsearch" do - reaction.category = "readinglist" - sidekiq_assert_enqueued_with(job: Search::IndexWorker) do - reaction.save - end - end - - it "on destroy enqueues job to delete reaction from elasticsearch" do - reaction.category = "readinglist" - reaction.save - sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker, - args: [described_class::SEARCH_CLASS.to_s, reaction.id]) do - reaction.destroy - end - end - end - - context "when category is not readinglist" do - before do - reaction.category = "like" - allow(reaction.user).to receive(:index_to_elasticsearch) - allow(reaction.reactable).to receive(:index_to_elasticsearch) - sidekiq_perform_enqueued_jobs - end - - it "on update does not enqueue job to index reaction to elasticsearch" do - reaction.save - sidekiq_assert_no_enqueued_jobs(only: Search::IndexWorker) do - reaction.update(category: "unicorn") - end - end - - it "on create does not enqueue job to index reaction to elasticsearch" do - sidekiq_assert_no_enqueued_jobs(only: Search::IndexWorker) do - reaction.save - end - end - - it "on destroy does not enqueue job to delete reaction from elasticsearch" do - reaction.save - sidekiq_assert_no_enqueued_jobs(only: Search::RemoveFromIndexWorker) do - reaction.destroy - end - end - end - end - describe "#skip_notification_for?" do let(:receiver) { build(:user) } let(:reaction) { build(:reaction, reactable: build(:article), user: nil) } diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index ddbda3092..07233f638 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -127,16 +127,12 @@ RSpec.describe Tag, type: :model do podcast_episode = create(:podcast_episode) tag = described_class.find(article.tags.first.id) podcast_episode.tags << tag - reaction = create(:reaction, reactable: article, category: "readinglist") new_keywords = "keyword1, keyword2, keyword3" sidekiq_perform_enqueued_jobs tag.update(keywords_for_search: new_keywords) sidekiq_perform_enqueued_jobs expect(collect_keywords(article)).to include(new_keywords) - expect( - reaction.elasticsearch_doc.dig("_source", "reactable", "tags").flat_map { |t| t["keywords_for_search"] }, - ).to include(new_keywords) expect(collect_keywords(podcast_episode)).to include(new_keywords) end end diff --git a/spec/serializers/search/reaction_serializer_spec.rb b/spec/serializers/search/reaction_serializer_spec.rb deleted file mode 100644 index a5c22265d..000000000 --- a/spec/serializers/search/reaction_serializer_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require "rails_helper" - -RSpec.describe Search::ReactionSerializer do - let(:user) { create(:user) } - let(:tag) { create(:tag, name: "ama") } - let(:article) { create(:article, user: user, tags: tag.name) } - let(:comment) { create(:comment, user: user, commentable: article) } - let(:article_reaction) { create(:reaction, reactable: article, user: user) } - let(:comment_reaction) { create(:reaction, reactable: comment, user: user) } - - it "serializes an article reaction" do - data_hash = described_class.new(article_reaction).serializable_hash.dig(:data, :attributes) - user_data = Search::NestedUserSerializer.new(user).serializable_hash.dig(:data, :attributes) - expect(data_hash.dig(:reactable, :user)).to eq(user_data) - expect(data_hash[:reactable].keys).to include(:id, :body_text, :class_name, :path, :tags, :title) - expect(data_hash.keys).to include(:id, :created_at, :category, :status, :user_id) - end - - it "serializes a comment reaction" do - data_hash = described_class.new(comment_reaction).serializable_hash.dig(:data, :attributes) - user_data = Search::NestedUserSerializer.new(user).serializable_hash.dig(:data, :attributes) - expect(data_hash.dig(:reactable, :user)).to eq(user_data) - expect(data_hash[:reactable].keys).to include(:id, :body_text, :class_name, :path, :tags, :title) - expect(data_hash.keys).to include(:id, :created_at, :category, :status, :user_id) - end - - it "creates valid json for Elasticsearch" do - data_hash = described_class.new(article_reaction).serializable_hash.dig(:data, :attributes) - result = Reaction::SEARCH_CLASS.index(article.id, data_hash) - expect(result["result"]).to eq("created") - end -end diff --git a/spec/services/data_sync/elasticsearch/article_spec.rb b/spec/services/data_sync/elasticsearch/article_spec.rb deleted file mode 100644 index cd11b65d9..000000000 --- a/spec/services/data_sync/elasticsearch/article_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "rails_helper" - -RSpec.describe DataSync::Elasticsearch::Article, type: :service do - let(:article) { create(:article) } - - it "defines necessary constants" do - expect(described_class::RELATED_DOCS).not_to be_nil - expect(described_class::SHARED_FIELDS).not_to be_nil - end - - describe "#sync_related_documents" do - it "removes docs from elasticsearch if article is unpublished" do - allow(article).to receive(:saved_changes).and_return(published: [true, false]) - reaction = create(:reaction, reactable: article, category: "readinglist") - sidekiq_perform_enqueued_jobs - expect(reaction.elasticsearch_doc).not_to be_nil - - article.update_column(:published, false) - - described_class.new(article).call - sidekiq_perform_enqueued_jobs - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - end - end -end diff --git a/spec/services/moderator/merge_user_spec.rb b/spec/services/moderator/merge_user_spec.rb index 51e9e50d6..1d6f08498 100644 --- a/spec/services/moderator/merge_user_spec.rb +++ b/spec/services/moderator/merge_user_spec.rb @@ -28,8 +28,6 @@ RSpec.describe Moderator::MergeUser, type: :service do drain_all_sidekiq_jobs expect(article.elasticsearch_doc.dig("_source", "user", "id")).to eq(delete_user_id) expect(comment.elasticsearch_doc.dig("_source", "user", "id")).to eq(delete_user_id) - expect(reaction.elasticsearch_doc.dig("_source", "user_id")).to eq(delete_user_id) - expect(article_reaction.elasticsearch_doc.dig("_source", "reactable", "user", "id")).to eq(delete_user_id) sidekiq_perform_enqueued_jobs do described_class.call(admin: admin, keep_user: keep_user, delete_user_id: delete_user.id) @@ -37,8 +35,6 @@ RSpec.describe Moderator::MergeUser, type: :service do drain_all_sidekiq_jobs expect(article.reload.elasticsearch_doc.dig("_source", "user", "id")).to eq(keep_user.id) expect(comment.reload.elasticsearch_doc.dig("_source", "user", "id")).to eq(keep_user.id) - expect(reaction.reload.elasticsearch_doc.dig("_source", "user_id")).to eq(keep_user.id) - expect(article_reaction.reload.elasticsearch_doc.dig("_source", "reactable", "user", "id")).to eq(keep_user.id) end it "updates badge_achievements_count" do diff --git a/spec/services/search/query_builders/reaction_spec.rb b/spec/services/search/query_builders/reaction_spec.rb deleted file mode 100644 index 4899822e2..000000000 --- a/spec/services/search/query_builders/reaction_spec.rb +++ /dev/null @@ -1,92 +0,0 @@ -require "rails_helper" - -RSpec.describe Search::QueryBuilders::Reaction, type: :service do - describe "::initialize" do - it "sets params" do - filter_params = { foo: "bar" } - filter = described_class.new(params: filter_params) - expect(filter.params).to include(filter_params) - end - - it "builds query body" do - filter = described_class.new(params: {}) - expect(filter.body).not_to be_nil - end - - it "sets category to readinglist" do - filter = described_class.new(params: {}) - expect(filter.params).to include(category: "readinglist") - end - end - - describe "#as_hash" do - let(:query_fields) { described_class::QUERY_KEYS[:search_fields] } - - it "applies QUERY_KEYS from params" do - params = { search_fields: "test" } - filter = described_class.new(params: params) - expected_query = [{ - "simple_query_string" => { - "query" => "test", - "fields" => query_fields, - "lenient" => true, - "analyze_wildcard" => true, - "minimum_should_match" => 2 - } - }] - expect(search_bool_clause(filter)["must"]).to match_array(expected_query) - end - - it "applies TERM_KEYS from params" do - params = { tag_names: "beginner", user_id: 777, status: "valid" } - filter = described_class.new(params: params) - expected_filters = [ - { "terms" => { "status" => ["valid"] } }, - { "terms" => { "reactable.tags.name" => ["beginner"] } }, - { "terms" => { "user_id" => [777] } }, - { "terms" => { "category" => ["readinglist"] } }, - ] - expect(search_bool_clause(filter)["filter"]).to match_array(expected_filters) - end - - it "applies QUERY_KEYS and TERM_KEYS from params" do - Timecop.freeze(Time.current) do - params = { search_fields: "ruby", tag_names: "cfp" } - filter = described_class.new(params: params) - expected_query = [{ - "simple_query_string" => { "query" => "ruby", "fields" => query_fields, "lenient" => true, - "analyze_wildcard" => true, "minimum_should_match" => 2 } - }] - expected_filters = [ - { "terms" => { "reactable.tags.name" => ["cfp"] } }, - { "terms" => { "category" => ["readinglist"] } }, - ] - expect(search_bool_clause(filter)["must"]).to match_array(expected_query) - expect(search_bool_clause(filter)["filter"]).to match_array(expected_filters) - end - end - - it "ignores params we don't support" do - params = { not_supported: "trash", search_fields: "cfp" } - filter = described_class.new(params: params) - expected_query = [{ - "simple_query_string" => { - "query" => "cfp", "fields" => query_fields, "lenient" => true, - "analyze_wildcard" => true, "minimum_should_match" => 2 - } - }] - expect(search_bool_clause(filter)["must"]).to match_array(expected_query) - end - - it "allows default params to be overriden" do - params = { sort_by: "status", sort_direction: "asc", size: 20 } - filter = described_class.new(params: params).as_hash - expect(filter["sort"]).to eq("status" => "asc") - expect(filter["size"]).to eq(20) - end - end - - def search_bool_clause(query_builder) - query_builder.as_hash.dig("query", "bool") - end -end diff --git a/spec/services/search/reaction_spec.rb b/spec/services/search/reaction_spec.rb deleted file mode 100644 index f145bfcc2..000000000 --- a/spec/services/search/reaction_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -require "rails_helper" - -RSpec.describe Search::Reaction, type: :service do - it "defines INDEX_NAME, INDEX_ALIAS, and MAPPINGS", :aggregate_failures do - expect(described_class::INDEX_NAME).not_to be_nil - expect(described_class::INDEX_ALIAS).not_to be_nil - expect(described_class::MAPPINGS).not_to be_nil - end - - describe "::search_documents", elasticsearch: "Reaction" do - let(:article1) { create(:article) } - let(:article2) { create(:article) } - let(:reaction1) { create(:reaction, category: "readinglist", reactable: article1, created_at: 1.week.ago) } - let(:reaction2) { create(:reaction, category: "readinglist", reactable: article2, created_at: Time.current) } - let(:query_params) { { size: 5 } } - - it "parses reaction document hits from search response" do - mock_search_response = { "hits" => { "hits" => {} } } - allow(described_class).to receive(:search) { mock_search_response } - described_class.search_documents(params: {}) - expect(described_class).to have_received(:search).with(body: a_kind_of(Hash)) - end - - it "returns fields necessary for the view" do - view_keys = %w[id reactable] - reactable_keys = %w[title path published_date_string tags user] - user_keys = %w[username name profile_image_90] - index_documents([reaction1]) - - result = described_class.search_documents(params: { size: 1 }) - reaction_doc = result["reactions"].first - expect(result["total"]).to be_present - expect(reaction_doc.keys).to include(*view_keys) - expect(reaction_doc["reactable"].keys).to include(*reactable_keys) - expect(reaction_doc.dig("reactable", "user").keys).to include(*user_keys) - end - - context "with a query" do - it "searches by search_fields" do - allow(article1).to receive(:title).and_return("ruby") - allow(article2).to receive(:body_text).and_return("Ruby Tuesday") - index_documents([reaction1, reaction2]) - query_params[:search_fields] = "ruby" - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(2) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction1.id, reaction2.id) - end - end - - context "with a filter term" do - let(:tag_one) { create(:tag) } - let(:tag_two) { create(:tag) } - - it "filters by tag names" do - article1.tags << tag_one - article2.tags << tag_two - index_documents([reaction1, reaction2]) - query_params[:tag_names] = [tag_one.name] - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(1) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction1.id) - end - - it "filters by multiple tag names when tag_boolean_mode is set to all" do - article1.tags << tag_one - article2.tags << tag_two - article2.tags << tag_one - index_documents([reaction1, reaction2]) - query_params[:tag_names] = [tag_one.name, tag_two.name] - query_params[:tag_boolean_mode] = "all" - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(1) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction2.id) - end - - it "filters by user_id" do - index_documents([reaction1, reaction2]) - query_params[:user_id] = reaction1.user_id - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(1) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction1.id) - end - - it "filters by status" do - reaction1.update(status: "invalid") - index_documents([reaction1, reaction2]) - query_params[:status] = %w[valid confirmed] - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(1) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction2.id) - end - - it "filters by category by default" do - reaction1.update(category: "like") - index_documents([reaction1, reaction2]) - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - expect(reaction_docs.count).to eq(1) - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to include(reaction2.id) - end - end - - context "with default sorting" do - it "sorts by created_at" do - index_documents([reaction1, reaction2]) - - reaction_docs = described_class.search_documents(params: query_params)["reactions"] - doc_ids = reaction_docs.map { |t| t["id"] } - expect(doc_ids).to eq([reaction2.id, reaction1.id]) - end - end - end -end diff --git a/spec/services/users/delete_spec.rb b/spec/services/users/delete_spec.rb index 060e50193..cb1a2d635 100644 --- a/spec/services/users/delete_spec.rb +++ b/spec/services/users/delete_spec.rb @@ -66,20 +66,6 @@ RSpec.describe Users::Delete, type: :service do expect { article.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) end - it "removes reactions from Elasticsearch" do - article = create(:article, user: user) - reaction = create(:reaction, category: "readinglist", reactable: article) - user_reaction = create(:reaction, user_id: user.id, category: "readinglist") - sidekiq_perform_enqueued_jobs - expect(reaction.elasticsearch_doc).not_to be_nil - expect(user_reaction.elasticsearch_doc).not_to be_nil - sidekiq_perform_enqueued_jobs do - described_class.call(user) - end - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - expect { user_reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) - end - it "deletes field tests memberships" do create(:field_test_membership, participant_id: user.id) diff --git a/spec/workers/search/bulk_index_worker_spec.rb b/spec/workers/search/bulk_index_worker_spec.rb index 4d12fbbd3..3db204bb5 100644 --- a/spec/workers/search/bulk_index_worker_spec.rb +++ b/spec/workers/search/bulk_index_worker_spec.rb @@ -4,19 +4,19 @@ RSpec.describe Search::BulkIndexWorker, type: :worker do let(:worker) { subject } let(:article) { create(:article) } - include_examples "#enqueues_on_correct_queue", "high_priority", ["Reaction", 1] + include_examples "#enqueues_on_correct_queue", "high_priority", ["Tag", 1] - it "indexes documents for a set of given ids and object class", elasticsearch: "Reaction" do - reactions = [create(:reaction, reactable: article), create(:reaction), create(:reaction)] + it "indexes documents for a set of given ids and object class", elasticsearch: "Tag" do + tags = [create(:tag), create(:tag), create(:tag)] Sidekiq::Worker.clear_all - reactions.each do |reaction| - expect { reaction.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) + tags.each do |tag| + expect { tag.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound) end - worker.perform("Reaction", reactions.map(&:id)) + worker.perform("Tag", tags.map(&:id)) - reactions.each do |reaction| - expect(reaction.elasticsearch_doc.dig("_source", "id")).to eql(reaction.id) + tags.each do |tag| + expect(tag.elasticsearch_doc.dig("_source", "id")).to eql(tag.id) end end end