mirror of
https://github.com/discourse/discourse.git
synced 2026-08-04 10:39:43 +08:00
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
61 lines
1.8 KiB
Ruby
Vendored
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
|