Skip to content

Commit 7ce6f5d

Browse files
test: cover all new subjects and outbound handlers
discord-nats/subjects.rs: - test_bot_subjects_new: verifica los 15 nuevos subjects de bot (typing, voice, guild/channel/role lifecycle, presence, modal, autocomplete, bot_ready) - test_agent_subjects_new: verifica los 17 nuevos subjects de agent (modal_respond, autocomplete_respond, ban, kick, timeout, channel/role CRUD, pin, unpin, bulk_delete, thread create/archive) discord-bot/outbound_tests.rs: - 17 nuevos tests "command is consumed" para todos los handlers agregados en la PR anterior (modal_respond, autocomplete_respond, ban, kick, timeout, create/edit/delete channel, create/assign/ remove/delete role, pin, unpin, bulk_delete, create/archive thread) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e85d962 commit 7ce6f5d

2 files changed

Lines changed: 305 additions & 0 deletions

File tree

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

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,271 @@ mod tests {
264264
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
265265
}
266266

267+
// ── modal_respond ─────────────────────────────────────────────────────────
268+
269+
#[tokio::test]
270+
async fn test_modal_respond_command_is_consumed() {
271+
use discord_types::ModalRespondCommand;
272+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
273+
let prefix = format!("test-out-modal-{}", uuid::Uuid::new_v4().simple());
274+
start_processor(client.clone(), &prefix).await;
275+
publish(&client, &subjects::agent::interaction_modal_respond(&prefix), &ModalRespondCommand {
276+
interaction_id: 1111,
277+
interaction_token: "fake-token".to_string(),
278+
custom_id: "my_modal".to_string(),
279+
title: "Test Modal".to_string(),
280+
inputs: vec![],
281+
}).await;
282+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
283+
}
284+
285+
// ── autocomplete_respond ──────────────────────────────────────────────────
286+
287+
#[tokio::test]
288+
async fn test_autocomplete_respond_command_is_consumed() {
289+
use discord_types::{AutocompleteChoice, AutocompleteRespondCommand};
290+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
291+
let prefix = format!("test-out-ac-{}", uuid::Uuid::new_v4().simple());
292+
start_processor(client.clone(), &prefix).await;
293+
publish(&client, &subjects::agent::interaction_autocomplete_respond(&prefix), &AutocompleteRespondCommand {
294+
interaction_id: 2222,
295+
interaction_token: "fake-token".to_string(),
296+
choices: vec![AutocompleteChoice { name: "Option A".to_string(), value: "a".to_string() }],
297+
}).await;
298+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
299+
}
300+
301+
// ── ban ───────────────────────────────────────────────────────────────────
302+
303+
#[tokio::test]
304+
async fn test_ban_user_command_is_consumed() {
305+
use discord_types::BanUserCommand;
306+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
307+
let prefix = format!("test-out-ban-{}", uuid::Uuid::new_v4().simple());
308+
start_processor(client.clone(), &prefix).await;
309+
publish(&client, &subjects::agent::guild_ban(&prefix), &BanUserCommand {
310+
guild_id: 200,
311+
user_id: 42,
312+
reason: Some("spam".to_string()),
313+
delete_message_seconds: 0,
314+
}).await;
315+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
316+
}
317+
318+
// ── kick ──────────────────────────────────────────────────────────────────
319+
320+
#[tokio::test]
321+
async fn test_kick_user_command_is_consumed() {
322+
use discord_types::KickUserCommand;
323+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
324+
let prefix = format!("test-out-kick-{}", uuid::Uuid::new_v4().simple());
325+
start_processor(client.clone(), &prefix).await;
326+
publish(&client, &subjects::agent::guild_kick(&prefix), &KickUserCommand {
327+
guild_id: 200,
328+
user_id: 42,
329+
reason: None,
330+
}).await;
331+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
332+
}
333+
334+
// ── timeout ───────────────────────────────────────────────────────────────
335+
336+
#[tokio::test]
337+
async fn test_timeout_user_command_is_consumed() {
338+
use discord_types::TimeoutUserCommand;
339+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
340+
let prefix = format!("test-out-timeout-{}", uuid::Uuid::new_v4().simple());
341+
start_processor(client.clone(), &prefix).await;
342+
publish(&client, &subjects::agent::guild_timeout(&prefix), &TimeoutUserCommand {
343+
guild_id: 200,
344+
user_id: 42,
345+
duration_secs: 3600,
346+
reason: Some("cooling off".to_string()),
347+
}).await;
348+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
349+
}
350+
351+
// ── create_channel ────────────────────────────────────────────────────────
352+
353+
#[tokio::test]
354+
async fn test_create_channel_command_is_consumed() {
355+
use discord_types::{ChannelType, CreateChannelCommand};
356+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
357+
let prefix = format!("test-out-ch-create-{}", uuid::Uuid::new_v4().simple());
358+
start_processor(client.clone(), &prefix).await;
359+
publish(&client, &subjects::agent::channel_create(&prefix), &CreateChannelCommand {
360+
guild_id: 200,
361+
name: "new-channel".to_string(),
362+
channel_type: ChannelType::GuildText,
363+
category_id: None,
364+
topic: None,
365+
}).await;
366+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
367+
}
368+
369+
// ── edit_channel ──────────────────────────────────────────────────────────
370+
371+
#[tokio::test]
372+
async fn test_edit_channel_command_is_consumed() {
373+
use discord_types::EditChannelCommand;
374+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
375+
let prefix = format!("test-out-ch-edit-{}", uuid::Uuid::new_v4().simple());
376+
start_processor(client.clone(), &prefix).await;
377+
publish(&client, &subjects::agent::channel_edit(&prefix), &EditChannelCommand {
378+
channel_id: 300,
379+
name: Some("renamed".to_string()),
380+
topic: None,
381+
}).await;
382+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
383+
}
384+
385+
// ── delete_channel ────────────────────────────────────────────────────────
386+
387+
#[tokio::test]
388+
async fn test_delete_channel_command_is_consumed() {
389+
use discord_types::DeleteChannelCommand;
390+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
391+
let prefix = format!("test-out-ch-del-{}", uuid::Uuid::new_v4().simple());
392+
start_processor(client.clone(), &prefix).await;
393+
publish(&client, &subjects::agent::channel_delete(&prefix), &DeleteChannelCommand { channel_id: 300 }).await;
394+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
395+
}
396+
397+
// ── create_role ───────────────────────────────────────────────────────────
398+
399+
#[tokio::test]
400+
async fn test_create_role_command_is_consumed() {
401+
use discord_types::CreateRoleCommand;
402+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
403+
let prefix = format!("test-out-role-create-{}", uuid::Uuid::new_v4().simple());
404+
start_processor(client.clone(), &prefix).await;
405+
publish(&client, &subjects::agent::role_create(&prefix), &CreateRoleCommand {
406+
guild_id: 200,
407+
name: "VIP".to_string(),
408+
color: Some(0xFFD700),
409+
hoist: true,
410+
mentionable: false,
411+
}).await;
412+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
413+
}
414+
415+
// ── assign_role ───────────────────────────────────────────────────────────
416+
417+
#[tokio::test]
418+
async fn test_assign_role_command_is_consumed() {
419+
use discord_types::AssignRoleCommand;
420+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
421+
let prefix = format!("test-out-role-assign-{}", uuid::Uuid::new_v4().simple());
422+
start_processor(client.clone(), &prefix).await;
423+
publish(&client, &subjects::agent::role_assign(&prefix), &AssignRoleCommand {
424+
guild_id: 200, user_id: 42, role_id: 111,
425+
}).await;
426+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
427+
}
428+
429+
// ── remove_role ───────────────────────────────────────────────────────────
430+
431+
#[tokio::test]
432+
async fn test_remove_role_command_is_consumed() {
433+
use discord_types::RemoveRoleCommand;
434+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
435+
let prefix = format!("test-out-role-remove-{}", uuid::Uuid::new_v4().simple());
436+
start_processor(client.clone(), &prefix).await;
437+
publish(&client, &subjects::agent::role_remove(&prefix), &RemoveRoleCommand {
438+
guild_id: 200, user_id: 42, role_id: 111,
439+
}).await;
440+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
441+
}
442+
443+
// ── delete_role ───────────────────────────────────────────────────────────
444+
445+
#[tokio::test]
446+
async fn test_delete_role_command_is_consumed() {
447+
use discord_types::DeleteRoleCommand;
448+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
449+
let prefix = format!("test-out-role-del-{}", uuid::Uuid::new_v4().simple());
450+
start_processor(client.clone(), &prefix).await;
451+
publish(&client, &subjects::agent::role_delete(&prefix), &DeleteRoleCommand {
452+
guild_id: 200, role_id: 111,
453+
}).await;
454+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
455+
}
456+
457+
// ── pin ───────────────────────────────────────────────────────────────────
458+
459+
#[tokio::test]
460+
async fn test_pin_message_command_is_consumed() {
461+
use discord_types::PinMessageCommand;
462+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
463+
let prefix = format!("test-out-pin-{}", uuid::Uuid::new_v4().simple());
464+
start_processor(client.clone(), &prefix).await;
465+
publish(&client, &subjects::agent::message_pin(&prefix), &PinMessageCommand {
466+
channel_id: 100, message_id: 50,
467+
}).await;
468+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
469+
}
470+
471+
// ── unpin ─────────────────────────────────────────────────────────────────
472+
473+
#[tokio::test]
474+
async fn test_unpin_message_command_is_consumed() {
475+
use discord_types::UnpinMessageCommand;
476+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
477+
let prefix = format!("test-out-unpin-{}", uuid::Uuid::new_v4().simple());
478+
start_processor(client.clone(), &prefix).await;
479+
publish(&client, &subjects::agent::message_unpin(&prefix), &UnpinMessageCommand {
480+
channel_id: 100, message_id: 50,
481+
}).await;
482+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
483+
}
484+
485+
// ── bulk_delete ───────────────────────────────────────────────────────────
486+
487+
#[tokio::test]
488+
async fn test_bulk_delete_messages_command_is_consumed() {
489+
use discord_types::BulkDeleteMessagesCommand;
490+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
491+
let prefix = format!("test-out-bulk-{}", uuid::Uuid::new_v4().simple());
492+
start_processor(client.clone(), &prefix).await;
493+
publish(&client, &subjects::agent::message_bulk_delete(&prefix), &BulkDeleteMessagesCommand {
494+
channel_id: 100,
495+
message_ids: vec![1, 2, 3],
496+
}).await;
497+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
498+
}
499+
500+
// ── create_thread ─────────────────────────────────────────────────────────
501+
502+
#[tokio::test]
503+
async fn test_create_thread_command_is_consumed() {
504+
use discord_types::CreateThreadCommand;
505+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
506+
let prefix = format!("test-out-thread-create-{}", uuid::Uuid::new_v4().simple());
507+
start_processor(client.clone(), &prefix).await;
508+
publish(&client, &subjects::agent::thread_create(&prefix), &CreateThreadCommand {
509+
channel_id: 100,
510+
name: "Discussion".to_string(),
511+
message_id: None,
512+
auto_archive_mins: 1440,
513+
}).await;
514+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
515+
}
516+
517+
// ── archive_thread ────────────────────────────────────────────────────────
518+
519+
#[tokio::test]
520+
async fn test_archive_thread_command_is_consumed() {
521+
use discord_types::ArchiveThreadCommand;
522+
let Some(client) = try_connect().await else { eprintln!("SKIP: NATS not available"); return; };
523+
let prefix = format!("test-out-thread-archive-{}", uuid::Uuid::new_v4().simple());
524+
start_processor(client.clone(), &prefix).await;
525+
publish(&client, &subjects::agent::thread_archive(&prefix), &ArchiveThreadCommand {
526+
channel_id: 100,
527+
locked: false,
528+
}).await;
529+
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
530+
}
531+
267532
// ── multiple commands in sequence ─────────────────────────────────────────
268533

269534
#[tokio::test]

rsworkspace/crates/discord-nats/src/subjects.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,46 @@ mod tests {
391391
assert_eq!(agent::all("prod"), "discord.prod.agent.>");
392392
}
393393

394+
#[test]
395+
fn test_bot_subjects_new() {
396+
assert_eq!(bot::typing_start("prod"), "discord.prod.bot.typing.start");
397+
assert_eq!(bot::voice_state_update("prod"), "discord.prod.bot.voice.state_update");
398+
assert_eq!(bot::guild_create("prod"), "discord.prod.bot.guild.create");
399+
assert_eq!(bot::guild_update("prod"), "discord.prod.bot.guild.update");
400+
assert_eq!(bot::guild_delete("prod"), "discord.prod.bot.guild.delete");
401+
assert_eq!(bot::channel_create("prod"), "discord.prod.bot.channel.create");
402+
assert_eq!(bot::channel_update("prod"), "discord.prod.bot.channel.update");
403+
assert_eq!(bot::channel_delete("prod"), "discord.prod.bot.channel.delete");
404+
assert_eq!(bot::role_create("prod"), "discord.prod.bot.role.create");
405+
assert_eq!(bot::role_update("prod"), "discord.prod.bot.role.update");
406+
assert_eq!(bot::role_delete("prod"), "discord.prod.bot.role.delete");
407+
assert_eq!(bot::presence_update("prod"), "discord.prod.bot.presence.update");
408+
assert_eq!(bot::interaction_modal("prod"), "discord.prod.bot.interaction.modal");
409+
assert_eq!(bot::interaction_autocomplete("prod"), "discord.prod.bot.interaction.autocomplete");
410+
assert_eq!(bot::bot_ready("prod"), "discord.prod.bot.ready");
411+
}
412+
413+
#[test]
414+
fn test_agent_subjects_new() {
415+
assert_eq!(agent::interaction_modal_respond("prod"), "discord.prod.agent.interaction.modal_respond");
416+
assert_eq!(agent::interaction_autocomplete_respond("prod"),"discord.prod.agent.interaction.autocomplete_respond");
417+
assert_eq!(agent::guild_ban("prod"), "discord.prod.agent.guild.ban");
418+
assert_eq!(agent::guild_kick("prod"), "discord.prod.agent.guild.kick");
419+
assert_eq!(agent::guild_timeout("prod"), "discord.prod.agent.guild.timeout");
420+
assert_eq!(agent::channel_create("prod"), "discord.prod.agent.channel.create");
421+
assert_eq!(agent::channel_edit("prod"), "discord.prod.agent.channel.edit");
422+
assert_eq!(agent::channel_delete("prod"), "discord.prod.agent.channel.delete");
423+
assert_eq!(agent::role_create("prod"), "discord.prod.agent.role.create");
424+
assert_eq!(agent::role_assign("prod"), "discord.prod.agent.role.assign");
425+
assert_eq!(agent::role_remove("prod"), "discord.prod.agent.role.remove");
426+
assert_eq!(agent::role_delete("prod"), "discord.prod.agent.role.delete");
427+
assert_eq!(agent::message_pin("prod"), "discord.prod.agent.message.pin");
428+
assert_eq!(agent::message_unpin("prod"), "discord.prod.agent.message.unpin");
429+
assert_eq!(agent::message_bulk_delete("prod"), "discord.prod.agent.message.bulk_delete");
430+
assert_eq!(agent::thread_create("prod"), "discord.prod.agent.thread.create");
431+
assert_eq!(agent::thread_archive("prod"), "discord.prod.agent.thread.archive");
432+
}
433+
394434
#[test]
395435
fn test_prefix_substitution() {
396436
assert_eq!(

0 commit comments

Comments
 (0)