Skip to content

Commit ce5d6f5

Browse files
refactor: migrate mock infrastructure to trogon-std/trogon-nats
- Add trogon-std and trogon-nats crates (from main branch) to workspace - Replace custom ReadEnv/InMemoryEnv in config.rs with trogon-std::env - Make DiscordBridge generic over Publish<P = MessagePublisher> so tests can inject MockPublisher without a real NATS connection - Add with_publisher() constructor for test-only bridge construction - Rewrite bridge_nats_tests.rs as pure unit tests using MockPublisher (no NATS server required, captures published messages in-memory) - Fix ratelimit handler: serenity EventHandler::ratelimit has no ctx param, so revert to log-only; remove unreachable publish_ratelimit - Fix bridge_tests.rs: use Bridge type alias for generic inference - Fix outbound_tests.rs: add as_voice field to SendMessageCommand literals All 84 discord-bot tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 08aece1 commit ce5d6f5

36 files changed

Lines changed: 2908 additions & 205 deletions

rsworkspace/Cargo.lock

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rsworkspace/crates/discord-bot/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ thiserror = "2.0"
3131
axum = "0.7"
3232
uuid = { version = "1", features = ["v4"] }
3333
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
34+
trogon-std = { path = "../trogon-std" }
3435

3536
[dev-dependencies]
3637
tempfile = "3"
3738
futures = "0.3"
39+
trogon-std = { path = "../trogon-std", features = ["test-support"] }

rsworkspace/crates/discord-bot/src/bridge.rs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex};
1414
use std::time::{SystemTime, UNIX_EPOCH};
1515

1616
use anyhow::Result;
17-
use discord_nats::{subjects, MessagePublisher};
17+
use discord_nats::{subjects, MessagePublisher, Publish};
1818
use discord_types::{
1919
events::*,
2020
session::{member_session_id, session_id},
@@ -168,8 +168,8 @@ use serenity::prelude::TypeMapKey;
168168
use tracing::{debug, warn};
169169

170170
/// Discord → NATS bridge
171-
pub struct DiscordBridge {
172-
publisher: MessagePublisher,
171+
pub struct DiscordBridge<P: Publish = MessagePublisher> {
172+
publisher: P,
173173
pub access_config: AccessConfig,
174174
sequence: Arc<AtomicU64>,
175175
bot_user_id: Arc<AtomicU64>,
@@ -197,12 +197,12 @@ pub struct DiscordBridge {
197197
pub dm_group_channels: Vec<u64>,
198198
}
199199

200-
impl TypeMapKey for DiscordBridge {
201-
type Value = Arc<DiscordBridge>;
200+
impl TypeMapKey for DiscordBridge<MessagePublisher> {
201+
type Value = Arc<DiscordBridge<MessagePublisher>>;
202202
}
203203

204-
impl DiscordBridge {
205-
/// Create a new bridge
204+
impl DiscordBridge<MessagePublisher> {
205+
/// Create a new bridge backed by a real NATS connection.
206206
pub fn new(
207207
client: async_nats::Client,
208208
prefix: String,
@@ -217,9 +217,42 @@ impl DiscordBridge {
217217
pluralkit_token: Option<String>,
218218
dm_group_enabled: bool,
219219
dm_group_channels: Vec<u64>,
220+
) -> Self {
221+
Self::with_publisher(
222+
MessagePublisher::new(client, prefix),
223+
access_config,
224+
presence_enabled,
225+
guild_commands_guild_id,
226+
reaction_mode,
227+
reaction_allowlist,
228+
ack_reaction,
229+
allow_bots,
230+
pluralkit_enabled,
231+
pluralkit_token,
232+
dm_group_enabled,
233+
dm_group_channels,
234+
)
235+
}
236+
}
237+
238+
impl<P: Publish> DiscordBridge<P> {
239+
/// Create a new bridge with any publisher (useful for testing with `MockPublisher`).
240+
pub fn with_publisher(
241+
publisher: P,
242+
access_config: AccessConfig,
243+
presence_enabled: bool,
244+
guild_commands_guild_id: Option<u64>,
245+
reaction_mode: crate::config::ReactionMode,
246+
reaction_allowlist: Vec<u64>,
247+
ack_reaction: Option<String>,
248+
allow_bots: bool,
249+
pluralkit_enabled: bool,
250+
pluralkit_token: Option<String>,
251+
dm_group_enabled: bool,
252+
dm_group_channels: Vec<u64>,
220253
) -> Self {
221254
Self {
222-
publisher: MessagePublisher::new(client, prefix),
255+
publisher,
223256
access_config,
224257
sequence: Arc::new(AtomicU64::new(0)),
225258
bot_user_id: Arc::new(AtomicU64::new(0)),
@@ -2203,15 +2236,6 @@ impl DiscordBridge {
22032236
Ok(())
22042237
}
22052238

2206-
pub async fn publish_ratelimit(&self, path: String, timeout_ms: u64, global: bool) -> Result<()> {
2207-
let meta = EventMetadata::new("", self.next_sequence());
2208-
let ev = RatelimitEvent { metadata: meta, path, timeout_ms, global };
2209-
let subject = subjects::bot::ratelimit(self.prefix());
2210-
self.publisher.publish(&subject, &ev).await?;
2211-
debug!("Published ratelimit to {}", subject);
2212-
Ok(())
2213-
}
2214-
22152239
}
22162240

22172241
fn convert_soundboard(sound: &SerenitySoundboard) -> SoundInfo {

0 commit comments

Comments
 (0)