test(e2e): a room announces members arriving and leaving

UserJoinedRoom and UserLeftRoom (codes 16 and 17) were parsed and applied
to the roster with nothing proving either end of that, which is the kind
of gap that only shows up when someone relies on it.
This commit is contained in:
Michel de Graaf
2026-09-09 17:16:10 +00:00
parent 68586639ac
commit e30cca6825
2 changed files with 74 additions and 2 deletions
+2 -2
View File
@@ -23,8 +23,8 @@ Message names and codes follow the Soulseek protocol as implemented by
| 13 | SayChatroom | yes | e2e — a message between two users in a room |
| 14 | JoinRoom | yes | e2e — public rooms, and private ones |
| 15 | LeaveRoom | yes | e2e — room list and membership |
| 16 | UserJoinedRoom | yes | e2e — room membership statistics |
| 17 | UserLeftRoom | yes | e2e — room membership statistics |
| 16 | UserJoinedRoom | yes | e2e — a member arriving is announced |
| 17 | UserLeftRoom | yes | e2e — a member leaving is announced |
| 18 | ConnectToPeer | yes | e2e — firewalled download and browse |
| 22 | MessageUser | yes | e2e — a private message between users |
| 23 | MessageAcked | yes | e2e — an offline message is delivered once |
+72
View File
@@ -5212,3 +5212,75 @@ fn a_peer_tells_us_about_itself_when_asked() {
let _ = std::fs::remove_dir_all(share_dir);
}
#[test]
fn a_room_reports_members_arriving_and_leaving() {
use soulseek_rs::types::RoomEvent;
let server = server_or_skip!();
let room = "e2e_room_comings";
let mut alice =
Client::with_settings(server.settings("e2e_comings_alice", "pw"));
alice.connect().expect("alice connect");
assert!(alice.login().expect("alice login"));
alice.join_room(room).expect("alice joins");
std::thread::sleep(Duration::from_millis(500));
let _ = alice.take_room_events();
// Bob arrives after her: she is told (code 16), and her roster grows.
let mut bob =
Client::with_settings(server.settings("e2e_comings_bob", "pw"));
bob.connect().expect("bob connect");
assert!(bob.login().expect("bob login"));
bob.join_room(room).expect("bob joins");
let joined =
await_room_event(&alice, Duration::from_secs(5), |event| match event {
RoomEvent::UserJoined { room: r, username }
if r == room && username == "e2e_comings_bob" =>
{
Some(())
}
_ => None,
});
assert!(joined.is_some(), "alice should be told bob arrived");
assert!(
alice
.room_members(room)
.iter()
.any(|u| u == "e2e_comings_bob"),
"the roster should carry bob, got {:?}",
alice.room_members(room)
);
// And when he leaves (code 17) the roster loses him again.
bob.leave_room(room).expect("bob leaves");
let left =
await_room_event(&alice, Duration::from_secs(5), |event| match event {
RoomEvent::UserLeft { room: r, username }
if r == room && username == "e2e_comings_bob" =>
{
Some(())
}
_ => None,
});
assert!(left.is_some(), "alice should be told bob left");
let deadline = Instant::now() + Duration::from_secs(3);
while Instant::now() < deadline
&& alice
.room_members(room)
.iter()
.any(|u| u == "e2e_comings_bob")
{
std::thread::sleep(Duration::from_millis(100));
}
assert!(
!alice
.room_members(room)
.iter()
.any(|u| u == "e2e_comings_bob"),
"the roster should drop him, got {:?}",
alice.room_members(room)
);
}