test(e2e): fence on the server where a test slept for another client
Tests that need one client's request to have landed before another client acts slept for it: a join before a room message, ticker or room search, a watcher's global-room join and leave, a guest accepting invitations, a room created before an outsider asks for it, share counts and interests before they are queried, a stored message before its recipient logs in, and an acknowledgement before the session ends. Several of those requests get no reply to wait on. soulfind takes each connection's messages in order, so a fence asks it about a user over the connection that has to be settled and waits for the answer, which only arrives once everything sent before it has been handled. Where the event itself is visible - a member list, alice's own ticker - the tests wait on that instead.
This commit is contained in:
@@ -2955,9 +2955,9 @@ fn a_joined_room_reports_its_members_statistics() {
|
|||||||
assert!(sharer.login().expect("sharer login"));
|
assert!(sharer.login().expect("sharer login"));
|
||||||
sharer.join_room(room).expect("sharer joins room");
|
sharer.join_room(room).expect("sharer joins room");
|
||||||
|
|
||||||
// Let the server register the sharer's membership and share counts, so
|
// The sharer's membership and share counts have to land first, so the
|
||||||
// the observer's own join reply describes a room that already has them.
|
// observer's own join reply describes a room that already has them.
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
fence(&sharer, "e2e_stats_observer");
|
||||||
|
|
||||||
let mut observer =
|
let mut observer =
|
||||||
Client::with_settings(server.settings("e2e_stats_observer", "pw"));
|
Client::with_settings(server.settings("e2e_stats_observer", "pw"));
|
||||||
@@ -3038,9 +3038,9 @@ fn watching_a_user_returns_their_status_and_share_counts() {
|
|||||||
watcher.connect().expect("watcher connect");
|
watcher.connect().expect("watcher connect");
|
||||||
assert!(watcher.login().expect("watcher login"));
|
assert!(watcher.login().expect("watcher login"));
|
||||||
|
|
||||||
// Let the subject's share counts reach the server before watching, so
|
// The subject's share counts have to reach the server before watching,
|
||||||
// the reply describes a user it already knows the statistics for.
|
// so the reply describes a user it already knows the statistics for.
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
fence(&subject, "e2e_watch_watcher");
|
||||||
|
|
||||||
watcher
|
watcher
|
||||||
.watch_user("e2e_watch_subject")
|
.watch_user("e2e_watch_subject")
|
||||||
@@ -3814,6 +3814,18 @@ fn await_room_event<T>(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait until the server has handled everything `client` has sent, including
|
||||||
|
/// requests it never answers: soulfind takes a connection's messages in order,
|
||||||
|
/// so the answer to a question about `other` asked now comes after them.
|
||||||
|
fn fence(client: &Client, other: &str) {
|
||||||
|
client.request_user_info(other).expect("ask about a user");
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
|
while client.user_info(other).is_none() {
|
||||||
|
assert!(Instant::now() < deadline, "the server should answer");
|
||||||
|
std::thread::sleep(Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_ticker_set_in_a_room_reaches_the_other_members() {
|
fn a_ticker_set_in_a_room_reaches_the_other_members() {
|
||||||
use soulseek_rs::types::RoomEvent;
|
use soulseek_rs::types::RoomEvent;
|
||||||
@@ -3830,7 +3842,12 @@ fn a_ticker_set_in_a_room_reaches_the_other_members() {
|
|||||||
|
|
||||||
alice.join_room(room).expect("alice joins");
|
alice.join_room(room).expect("alice joins");
|
||||||
bob.join_room(room).expect("bob joins");
|
bob.join_room(room).expect("bob joins");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
// A ticker reaches only who is in the room when it is set.
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
|
while bob.room_members(room).is_empty() {
|
||||||
|
assert!(Instant::now() < deadline, "bob should get into the room");
|
||||||
|
std::thread::sleep(Duration::from_millis(50));
|
||||||
|
}
|
||||||
let _ = bob.take_room_events();
|
let _ = bob.take_room_events();
|
||||||
|
|
||||||
alice
|
alice
|
||||||
@@ -3874,11 +3891,15 @@ fn a_client_joining_later_receives_the_whole_ticker_board() {
|
|||||||
alice.connect().expect("alice connect");
|
alice.connect().expect("alice connect");
|
||||||
assert!(alice.login().expect("alice login"));
|
assert!(alice.login().expect("alice login"));
|
||||||
alice.join_room(room).expect("alice joins");
|
alice.join_room(room).expect("alice joins");
|
||||||
std::thread::sleep(Duration::from_millis(300));
|
|
||||||
alice
|
alice
|
||||||
.set_room_ticker(room, "standing message")
|
.set_room_ticker(room, "standing message")
|
||||||
.expect("set ticker");
|
.expect("set ticker");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
// The room, alice included, is told once the board holds it.
|
||||||
|
await_room_event(&alice, Duration::from_secs(5), |event| {
|
||||||
|
matches!(event, RoomEvent::TickerAdded { room: r, .. } if r == room)
|
||||||
|
.then_some(())
|
||||||
|
})
|
||||||
|
.expect("alice should see her ticker go up");
|
||||||
|
|
||||||
// Carol joins afterwards and must be handed the board that already exists.
|
// Carol joins afterwards and must be handed the board that already exists.
|
||||||
let mut carol =
|
let mut carol =
|
||||||
@@ -3919,7 +3940,7 @@ fn the_global_room_feed_carries_a_room_we_never_joined() {
|
|||||||
|
|
||||||
watcher.join_global_room().expect("join global room");
|
watcher.join_global_room().expect("join global room");
|
||||||
talker.join_room(room).expect("talker joins a room");
|
talker.join_room(room).expect("talker joins a room");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
fence(&watcher, "e2e_global_talk");
|
||||||
let _ = watcher.take_room_events();
|
let _ = watcher.take_room_events();
|
||||||
|
|
||||||
let body = "spoken where nobody is watching";
|
let body = "spoken where nobody is watching";
|
||||||
@@ -3943,7 +3964,7 @@ fn the_global_room_feed_carries_a_room_we_never_joined() {
|
|||||||
|
|
||||||
// And leaving the feed stops it: the next message must not arrive.
|
// And leaving the feed stops it: the next message must not arrive.
|
||||||
watcher.leave_global_room().expect("leave global room");
|
watcher.leave_global_room().expect("leave global room");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
fence(&watcher, "e2e_global_talk");
|
||||||
let _ = watcher.take_room_events();
|
let _ = watcher.take_room_events();
|
||||||
talker
|
talker
|
||||||
.say_in_room(room, "after leaving")
|
.say_in_room(room, "after leaving")
|
||||||
@@ -4009,7 +4030,16 @@ fn a_room_search_is_answered_by_the_rooms_members() {
|
|||||||
);
|
);
|
||||||
sharer.join_room(room).expect("sharer joins");
|
sharer.join_room(room).expect("sharer joins");
|
||||||
searcher.join_room(room).expect("searcher joins");
|
searcher.join_room(room).expect("searcher joins");
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
// A room search goes to whoever is in the room when it is sent.
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
|
while !searcher
|
||||||
|
.room_members(room)
|
||||||
|
.iter()
|
||||||
|
.any(|member| member == "e2e_rs_sharer")
|
||||||
|
{
|
||||||
|
assert!(Instant::now() < deadline, "both should get into the room");
|
||||||
|
std::thread::sleep(Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
|
||||||
let query = "relic";
|
let query = "relic";
|
||||||
searcher.search_room(room, query).expect("room search");
|
searcher.search_room(room, query).expect("room search");
|
||||||
@@ -4046,7 +4076,7 @@ fn shared_interests_make_two_users_similar() {
|
|||||||
alice
|
alice
|
||||||
.add_dislike("e2e_interest_muzak")
|
.add_dislike("e2e_interest_muzak")
|
||||||
.expect("alice dislikes something");
|
.expect("alice dislikes something");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
fence(&bob, "e2e_like_alice");
|
||||||
|
|
||||||
// Who else likes this item (code 112).
|
// Who else likes this item (code 112).
|
||||||
let deadline = Instant::now() + Duration::from_secs(5);
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
@@ -4140,7 +4170,7 @@ fn recommendations_are_returned_for_our_interests() {
|
|||||||
alice.add_interest(shared).expect("alice likes shared");
|
alice.add_interest(shared).expect("alice likes shared");
|
||||||
bob.add_interest(shared).expect("bob likes shared");
|
bob.add_interest(shared).expect("bob likes shared");
|
||||||
bob.add_interest(other).expect("bob likes other");
|
bob.add_interest(other).expect("bob likes other");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
fence(&bob, "e2e_rec_alice");
|
||||||
|
|
||||||
let deadline = Instant::now() + Duration::from_secs(8);
|
let deadline = Instant::now() + Duration::from_secs(8);
|
||||||
let mut recommended = Vec::new();
|
let mut recommended = Vec::new();
|
||||||
@@ -4635,7 +4665,8 @@ fn a_private_room_is_owned_granted_and_revoked() {
|
|||||||
owner
|
owner
|
||||||
.join_private_room(room)
|
.join_private_room(room)
|
||||||
.expect("owner creates the room");
|
.expect("owner creates the room");
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
// An invite reaches only a user already accepting invitations.
|
||||||
|
fence(&guest, "e2e_priv_owner");
|
||||||
|
|
||||||
// The guest is invited, and hears about it (code 139).
|
// The guest is invited, and hears about it (code 139).
|
||||||
owner
|
owner
|
||||||
@@ -4754,7 +4785,7 @@ fn a_private_room_someone_else_owns_cannot_be_taken() {
|
|||||||
owner
|
owner
|
||||||
.join_private_room(room)
|
.join_private_room(room)
|
||||||
.expect("owner creates the room");
|
.expect("owner creates the room");
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
fence(&owner, "e2e_taken_outsider");
|
||||||
|
|
||||||
// An outsider asking for the same name must be refused (code 1003), not
|
// An outsider asking for the same name must be refused (code 1003), not
|
||||||
// handed the room.
|
// handed the room.
|
||||||
@@ -4807,7 +4838,7 @@ fn an_acknowledged_offline_message_is_not_delivered_twice() {
|
|||||||
sender
|
sender
|
||||||
.send_private_message("e2e_ack_recipient", body)
|
.send_private_message("e2e_ack_recipient", body)
|
||||||
.expect("send to an offline user");
|
.expect("send to an offline user");
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
fence(&sender, "e2e_ack_recipient");
|
||||||
|
|
||||||
let received_once = |label: &str| -> bool {
|
let received_once = |label: &str| -> bool {
|
||||||
let mut client =
|
let mut client =
|
||||||
@@ -4825,7 +4856,9 @@ fn an_acknowledged_offline_message_is_not_delivered_twice() {
|
|||||||
std::thread::sleep(Duration::from_millis(100));
|
std::thread::sleep(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
// The acknowledgement goes out ahead of the message it answers, so
|
||||||
|
// once the server has handled what followed, it has the ack too.
|
||||||
|
fence(&client, "e2e_ack_sender");
|
||||||
got
|
got
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5379,7 +5412,7 @@ fn a_member_can_give_up_a_private_room_and_an_owner_can_disband_it() {
|
|||||||
owner
|
owner
|
||||||
.join_private_room(room)
|
.join_private_room(room)
|
||||||
.expect("owner creates the room");
|
.expect("owner creates the room");
|
||||||
std::thread::sleep(Duration::from_millis(750));
|
fence(&guest, "e2e_leave_owner");
|
||||||
owner
|
owner
|
||||||
.add_room_member(room, "e2e_leave_guest")
|
.add_room_member(room, "e2e_leave_guest")
|
||||||
.expect("owner invites the guest");
|
.expect("owner invites the guest");
|
||||||
|
|||||||
Reference in New Issue
Block a user