All checks were successful
CI / ci (push) Successful in 5m57s
Replace raw String user IDs with a UserId newtype in domain for type safety, and add 30s ping/pong to prevent idle WebSocket disconnects.
99 lines
2.8 KiB
Rust
99 lines
2.8 KiB
Rust
mod common;
|
|
|
|
use domain::{BroadcastEvent, UserId};
|
|
|
|
fn uid(id: &str) -> UserId {
|
|
UserId::new(id.to_string())
|
|
}
|
|
|
|
#[test]
|
|
fn connect_increments_count() {
|
|
let (state, _) = common::test_state();
|
|
assert_eq!(application::soldiers::connect::execute(&state, uid("a")), 1);
|
|
assert_eq!(application::soldiers::connect::execute(&state, uid("b")), 2);
|
|
assert_eq!(application::soldiers::connect::execute(&state, uid("c")), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn disconnect_decrements_count() {
|
|
let (state, _) = common::test_state();
|
|
application::soldiers::connect::execute(&state, uid("a"));
|
|
application::soldiers::connect::execute(&state, uid("b"));
|
|
|
|
assert_eq!(
|
|
application::soldiers::disconnect::execute(&state, &uid("a")),
|
|
1
|
|
);
|
|
assert_eq!(
|
|
application::soldiers::disconnect::execute(&state, &uid("b")),
|
|
0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn disconnect_unknown_user_is_harmless() {
|
|
let (state, _) = common::test_state();
|
|
application::soldiers::connect::execute(&state, uid("a"));
|
|
assert_eq!(
|
|
application::soldiers::disconnect::execute(&state, &uid("unknown")),
|
|
1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn connect_publishes_soldier_count() {
|
|
let (state, spy) = common::test_state();
|
|
application::soldiers::connect::execute(&state, uid("a"));
|
|
|
|
let events = spy.events();
|
|
assert_eq!(events.len(), 1);
|
|
assert!(matches!(events[0], BroadcastEvent::SoldierCountChanged(1)));
|
|
}
|
|
|
|
#[test]
|
|
fn disconnect_publishes_soldier_count() {
|
|
let (state, spy) = common::test_state();
|
|
application::soldiers::connect::execute(&state, uid("a"));
|
|
application::soldiers::disconnect::execute(&state, &uid("a"));
|
|
|
|
let events = spy.events();
|
|
assert_eq!(events.len(), 2);
|
|
assert!(matches!(events[1], BroadcastEvent::SoldierCountChanged(0)));
|
|
}
|
|
|
|
#[test]
|
|
fn disconnect_clears_cooldown() {
|
|
let (state, _) = common::test_state();
|
|
let user = uid("user-1");
|
|
application::soldiers::connect::execute(&state, user.clone());
|
|
|
|
application::canvas::place_pixel::execute(
|
|
&state,
|
|
application::canvas::place_pixel::Command {
|
|
user_id: &user,
|
|
position: domain::Position::new(0, 0),
|
|
color: domain::Color::new(0xFF),
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
application::soldiers::disconnect::execute(&state, &user);
|
|
|
|
// Reconnect with same ID — cooldown should be gone
|
|
application::soldiers::connect::execute(&state, user.clone());
|
|
let result = application::canvas::place_pixel::execute(
|
|
&state,
|
|
application::canvas::place_pixel::Command {
|
|
user_id: &user,
|
|
position: domain::Position::new(1, 1),
|
|
color: domain::Color::new(0xAA),
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
assert!(matches!(
|
|
result,
|
|
application::canvas::place_pixel::Outcome::Placed(_)
|
|
));
|
|
}
|