0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-04 10:39:43 +08:00
discourse/plugins/discourse-narrative-bot/spec/jobs/bot_input_spec.rb
Régis Hanol f00dfb922a
FIX: Use bundled quotes for discobot instead of dead external API (#40367)
The discobot `quote` and `help` commands fetched a random quote from the
external `api.forismatic.com` service for English locales. That host now
returns HTTP 521, so `QuoteGenerator.generate` (which calls Excon with
`expects: [200, 201]`) raised and crashed the `bot_input` job, leaving
users with no reply. `roll` and `fortune` kept working because they run
locally, and non-English locales were unaffected because they already
used bundled quotes.

This removes the external call entirely and samples from the locally
bundled quotes for the user's effective locale — the same data already
shipped for translations — so the commands work without any network
dependency and can no longer fail silently. Sampling over every
available quote also surfaces entries that the previous `rand(1..10)`
never reached.

Adds a `QuoteGenerator` unit spec and a `bot_input` job spec covering
the no-network reply path and error propagation.

Ref - t/184527
2026-05-28 17:37:29 +02:00

61 lines
1.8 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe Jobs::BotInput do
fab!(:user)
fab!(:topic)
fab!(:post) { Fabricate(:post, topic:, user:) }
let(:discobot_user) { DiscourseNarrativeBot::Base.new.discobot_user }
before do
discobot_user
SiteSetting.discourse_narrative_bot_enabled = true
post.update!(raw: "@discobot quote")
end
it "does nothing when the user no longer exists" do
missing_user_id = User.maximum(:id).to_i + 100
expect do
described_class.new.execute(user_id: missing_user_id, post_id: post.id, input: "reply")
end.to_not change { Post.count }
end
it "runs the track selector with the given input in the user's locale" do
selector = mock
selector.expects(:select).once
DiscourseNarrativeBot::TrackSelector
.expects(:new)
.with(:reply, user, post_id: post.id, topic_id: nil)
.returns(selector)
described_class.new.execute(user_id: user.id, post_id: post.id, input: "reply")
end
it "replies to a quote request without contacting any external service" do
expect do
described_class.new.execute(user_id: user.id, post_id: post.id, input: "reply")
end.to change { Post.count }.by(1)
bundled_quotes =
I18n
.t("discourse_narrative_bot.quote")
.values
.select { |v| v.is_a?(Hash) }
.map { |q| DiscourseNarrativeBot::QuoteGenerator.format_quote(q[:quote], q[:author]) }
expect(Post.last.user).to eq(discobot_user)
expect(bundled_quotes).to include(Post.last.raw)
end
it "propagates errors raised while processing a track" do
DiscourseNarrativeBot::TrackSelector
.any_instance
.stubs(:select)
.raises(StandardError.new("boom"))
expect do
described_class.new.execute(user_id: user.id, post_id: post.id, input: "reply")
end.to raise_error(StandardError, "boom")
end
end