[deploy] Refactor:Remove Reaction Search Code (#10377)

This commit is contained in:
Molly Struve 2020-09-23 12:27:50 -05:00 committed by GitHub
parent 779fad25b9
commit e9cb7b2fd9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 14 additions and 647 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -4,7 +4,6 @@ module DataSync
RELATED_DOCS = %i[
articles
podcast_episodes
reactions
].freeze
SHARED_FIELDS = %i[

View file

@ -3,7 +3,6 @@ module DataSync
class User < Base
RELATED_DOCS = %i[
articles
reactions
podcast_episodes
chat_channel_memberships
comments

View file

@ -4,7 +4,6 @@ module Search
Search::ChatChannelMembership,
Search::Listing,
Search::FeedContent,
Search::Reaction,
Search::Tag,
Search::User,
].freeze

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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