From d9fddff9c671aabf63579623aa78c68f42b60aff Mon Sep 17 00:00:00 2001 From: Pablo Monfort Date: Tue, 11 Aug 2026 23:43:32 -0300 Subject: [PATCH 1/3] AO3-6910 Add tests for Sentry reporting on ES BadRequest --- .../autocomplete_controller_spec.rb | 21 +++++++++++++++++++ spec/models/search/query_spec.rb | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 68459a76885..e25c1758efe 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -3,6 +3,27 @@ describe AutocompleteController do include LoginMacros + describe "GET #noncanonical_tag" do + context "when Elasticsearch raises a BadRequest error" do + before do + allow($elasticsearch).to receive(:search) + .and_raise(Elastic::Transport::Transport::Errors::BadRequest) + end + + it "returns an empty result" do + get :noncanonical_tag, params: { term: "test", type: "freeform", format: :json } + expect(JSON.parse(response.body)).to eq([]) + end + + it "reports the exception to Sentry" do + sentry = class_double("Sentry", capture_exception: nil).as_stubbed_const + get :noncanonical_tag, params: { term: "test", type: "freeform", format: :json } + expect(sentry).to have_received(:capture_exception) + .with(instance_of(Elastic::Transport::Transport::Errors::BadRequest)) + end + end + end + describe "tag" do let!(:tag1) { create(:canonical_fandom, name: "Match") } let!(:tag2) { create(:canonical_fandom, name: "Blargh") } diff --git a/spec/models/search/query_spec.rb b/spec/models/search/query_spec.rb index 45a7776dbd6..77c02b1ebc0 100644 --- a/spec/models/search/query_spec.rb +++ b/spec/models/search/query_spec.rb @@ -1,6 +1,27 @@ require 'spec_helper' describe Query do + describe "#search" do + context "when Elasticsearch raises a BadRequest error" do + before do + allow($elasticsearch).to receive(:search) + .and_raise(Elastic::Transport::Transport::Errors::BadRequest) + end + + it "returns an error hash" do + result = Query.new.search + expect(result).to eq(error: "Your search failed because of a syntax error. Please try again.") + end + + it "reports the exception to Sentry" do + sentry = class_double("Sentry", capture_exception: nil).as_stubbed_const + Query.new.search + expect(sentry).to have_received(:capture_exception) + .with(instance_of(Elastic::Transport::Transport::Errors::BadRequest)) + end + end + end + describe '#split_query_text_phrases' do it "should add quoted phrases to a query string" do q = Query.new From 905d95a66535bab263883388f086ee033c5968f0 Mon Sep 17 00:00:00 2001 From: Pablo Monfort Date: Wed, 12 Aug 2026 00:18:26 -0300 Subject: [PATCH 2/3] AO3-6910 Report ES BadRequest errors to Sentry --- app/controllers/autocomplete_controller.rb | 3 ++- app/models/search/query.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index 594094d24b3..33891ad23f4 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -110,7 +110,8 @@ def noncanonical_tag body: { size: "100", query: { bool: { filter: [{ match: { tag_type: params[:type].capitalize } }, { match: { canonical: false } }], must: search_list } } } ) render_output((match + search_results["hits"]["hits"].first(10).map { |t| t["_source"]["name"] }).uniq) - rescue Elastic::Transport::Transport::Errors::BadRequest + rescue Elastic::Transport::Transport::Errors::BadRequest => e + Sentry.capture_exception(e) if defined?(Sentry) render_output(match) end end diff --git a/app/models/search/query.rb b/app/models/search/query.rb index 70f10699b03..d36528b9246 100644 --- a/app/models/search/query.rb +++ b/app/models/search/query.rb @@ -14,7 +14,8 @@ def search body: generated_query, track_total_hits: true ) - rescue Elastic::Transport::Transport::Errors::BadRequest + rescue Elastic::Transport::Transport::Errors::BadRequest => e + Sentry.capture_exception(e) if defined?(Sentry) { error: "Your search failed because of a syntax error. Please try again." } end end From 91ba2c30c29f59093bff46e9646e5d846b3e717a Mon Sep 17 00:00:00 2001 From: Pablo Monfort Date: Wed, 12 Aug 2026 01:15:18 -0300 Subject: [PATCH 3/3] AO3-6910 Add test for DB fallback on ES BadRequest --- spec/controllers/autocomplete_controller_spec.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index e25c1758efe..48cf0006ec0 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -10,11 +10,17 @@ .and_raise(Elastic::Transport::Transport::Errors::BadRequest) end - it "returns an empty result" do + it "returns an empty result when there is no exact match" do get :noncanonical_tag, params: { term: "test", type: "freeform", format: :json } expect(JSON.parse(response.body)).to eq([]) end + it "falls back to the exact database match" do + create(:freeform, name: "test", canonical: false) + get :noncanonical_tag, params: { term: "test", type: "freeform", format: :json } + expect(JSON.parse(response.body)).to eq([{ "id" => "test", "name" => "test" }]) + end + it "reports the exception to Sentry" do sentry = class_double("Sentry", capture_exception: nil).as_stubbed_const get :noncanonical_tag, params: { term: "test", type: "freeform", format: :json }