Live location tracking and playback for the game "manhunt"
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add tests for transport

Ben C e596a1ed 6be4c69f

+629 -20
+2 -1
TODO.md
··· 25 25 - [ ] Backend : More tests 26 26 - [x] Lobby tests 27 27 - [x] Game end test for actual return from loop 28 - - [ ] More transport crates tests 28 + - [x] More transport crate tests 29 + - [ ] Signaling is wrong, only kick everyone else on host leave if the lobby is open 29 30 - [x] Organize signalling and seperate out more logic 30 31 - [x] Signaling tests 31 32 - [ ] Testing crate for integration testing?
+627 -19
manhunt-transport/src/matchbox.rs
··· 1 - use std::{collections::HashSet, pin::Pin, sync::Arc}; 1 + use std::{collections::HashSet, marker::PhantomData, pin::Pin, sync::Arc}; 2 2 3 3 use anyhow::{Context, anyhow}; 4 4 use futures::{ 5 - SinkExt, StreamExt, 5 + SinkExt, Stream, StreamExt, 6 6 channel::mpsc::{UnboundedReceiver, UnboundedSender}, 7 7 }; 8 8 use log::{error, info}; ··· 22 22 type MsgPair = (Option<Uuid>, TransportMessage); 23 23 type Queue = QueuePair<MsgPair>; 24 24 25 - pub struct MatchboxTransport { 25 + pub struct MatchboxTransport<S: SocketImpl = WebRtcSocket> { 26 26 my_id: Uuid, 27 27 incoming: Queue, 28 28 all_peers: Mutex<HashSet<Uuid>>, 29 29 msg_sender: UnboundedSender<MatchboxMsgPair>, 30 30 cancel_token: CancellationToken, 31 + phantom: PhantomData<S>, 31 32 } 32 33 33 34 type LoopFutRes = Result<(), SocketError>; 34 35 35 36 type MatchboxMsgPair = (PeerId, Box<[u8]>); 37 + type MatchboxSender = UnboundedSender<MatchboxMsgPair>; 38 + type MatchboxReceiver = UnboundedReceiver<MatchboxMsgPair>; 39 + type MatchboxChannel = (MatchboxSender, MatchboxReceiver); 36 40 37 41 fn map_socket_error(err: SocketError) -> anyhow::Error { 38 42 match err { ··· 41 45 } 42 46 } 43 47 44 - impl MatchboxTransport { 45 - pub async fn new(join_code: &str, is_host: bool) -> Result<Arc<Self>> { 46 - let (itx, irx) = mpsc::channel(15); 48 + type FutPin<T> = Pin<Box<dyn Future<Output = T> + Send>>; 49 + type MessageLoopFuture = FutPin<LoopFutRes>; 50 + type PeerMsg = (PeerId, PeerState); 51 + 52 + pub trait SocketImpl: Unpin + Send + Sync + Sized + Stream<Item = PeerMsg> { 53 + fn new(room_url: &str) -> (Self, MessageLoopFuture); 54 + fn get_id(&mut self) -> Option<PeerId>; 55 + fn take_channel(&mut self) -> MatchboxChannel; 56 + } 57 + 58 + impl SocketImpl for WebRtcSocket { 59 + fn new(room_url: &str) -> (Self, MessageLoopFuture) { 60 + Self::new_reliable(room_url) 61 + } 62 + 63 + fn get_id(&mut self) -> Option<PeerId> { 64 + self.id() 65 + } 47 66 67 + fn take_channel(&mut self) -> MatchboxChannel { 68 + self.take_channel(0).expect("Failed to get channel").split() 69 + } 70 + } 71 + 72 + impl<S: SocketImpl + 'static> MatchboxTransport<S> { 73 + pub async fn new(join_code: &str, is_host: bool) -> Result<Arc<Self>> { 48 74 let ws_url = server::room_url(join_code, is_host); 75 + let (socket, loop_fut) = S::new(&ws_url); 76 + Self::from_socket_and_loop_fut(socket, loop_fut).await 77 + } 49 78 50 - let (mut socket, mut loop_fut) = WebRtcSocket::new_reliable(&ws_url); 51 - 52 - let (mtx, mrx) = socket 53 - .take_channel(0) 54 - .expect("Failed to get channel") 55 - .split(); 79 + async fn from_socket_and_loop_fut( 80 + mut socket: S, 81 + mut loop_fut: MessageLoopFuture, 82 + ) -> Result<Arc<Self>> { 83 + let (itx, irx) = mpsc::channel(15); 84 + let (mtx, mrx) = socket.take_channel(); 56 85 57 86 let res = loop { 58 87 tokio::select! { ··· 79 108 all_peers: Mutex::new(HashSet::with_capacity(5)), 80 109 msg_sender: mtx.clone(), 81 110 cancel_token: CancellationToken::new(), 111 + phantom: PhantomData, 82 112 }); 83 113 84 114 tokio::spawn({ ··· 92 122 } 93 123 Err(why) => { 94 124 drop(mrx); 95 - mtx.close_channel(); 125 + drop(mtx); 96 126 drop(socket); 97 127 Err(why) 98 128 } 99 129 } 100 130 } 101 131 102 - async fn wait_for_id(socket: &mut WebRtcSocket) -> Option<Uuid> { 103 - if let Some(id) = socket.id() { 132 + async fn wait_for_id(socket: &mut S) -> Option<Uuid> { 133 + if let Some(id) = socket.get_id() { 104 134 Some(id.0) 105 135 } else { 106 136 yield_now().await; ··· 118 148 119 149 async fn main_loop( 120 150 &self, 121 - mut socket: WebRtcSocket, 122 - loop_fut: Pin<Box<dyn Future<Output = LoopFutRes> + Send + 'static>>, 151 + mut socket: S, 152 + loop_fut: MessageLoopFuture, 123 153 mut mrx: UnboundedReceiver<MatchboxMsgPair>, 124 154 ) { 125 155 tokio::pin!(loop_fut); ··· 164 194 self.push_incoming(Some(self.my_id), msg).await; 165 195 166 196 self.msg_sender.close_channel(); 197 + self.incoming.1.lock().await.close(); 167 198 drop(mrx); 168 - socket.try_update_peers().ok(); 169 199 drop(socket); 170 200 if should_await { 171 201 if let Err(why) = loop_fut.await { ··· 251 281 buffer 252 282 } 253 283 284 + #[cfg(test)] 285 + pub async fn force_recv_msg(&self) -> MsgPair { 286 + self.incoming 287 + .1 288 + .lock() 289 + .await 290 + .recv() 291 + .await 292 + .expect("No messages") 293 + } 294 + 295 + #[cfg(test)] 296 + pub async fn assert_no_incoming(&self) { 297 + assert!(self.incoming.1.lock().await.is_empty()); 298 + } 299 + 254 300 pub fn cancel(&self) { 255 301 self.cancel_token.cancel(); 256 302 } 257 303 } 258 304 259 - impl Transport for MatchboxTransport { 305 + impl<S: SocketImpl + 'static> Transport for MatchboxTransport<S> { 260 306 fn self_id(&self) -> Uuid { 261 307 self.my_id 262 308 } ··· 295 341 Self::new(code, host).await 296 342 } 297 343 } 344 + 345 + #[cfg(test)] 346 + mod tests { 347 + 348 + use futures::{ 349 + channel::{mpsc, oneshot}, 350 + lock::Mutex as FutMutex, 351 + }; 352 + use manhunt_logic::{GameEvent, LobbyMessage, PlayerProfile}; 353 + use matchbox_socket::SignalingError; 354 + 355 + use super::*; 356 + use tokio::test; 357 + 358 + use std::{collections::HashMap, sync::Mutex as StdMutex, time::Duration}; 359 + 360 + type PeerRx = UnboundedReceiver<PeerMsg>; 361 + type PeerTx = UnboundedSender<PeerMsg>; 362 + type IdHandle = Arc<StdMutex<Option<PeerId>>>; 363 + 364 + struct MockSocket { 365 + peer_recv: PeerRx, 366 + id: IdHandle, 367 + channel: Option<MatchboxChannel>, 368 + cancel: CancellationToken, 369 + } 370 + 371 + impl MockSocket { 372 + pub fn new( 373 + peer_recv: PeerRx, 374 + channel: MatchboxChannel, 375 + id: IdHandle, 376 + ) -> ( 377 + Self, 378 + MessageLoopFuture, 379 + oneshot::Sender<LoopFutRes>, 380 + CancellationToken, 381 + ) { 382 + let (stop_tx, stop_rx) = oneshot::channel(); 383 + let cancel = CancellationToken::new(); 384 + let sock = Self { 385 + peer_recv, 386 + channel: Some(channel), 387 + id, 388 + cancel: cancel.clone(), 389 + }; 390 + 391 + let fut = Box::pin(async move { stop_rx.await.expect("Failed to recv") }); 392 + 393 + (sock, fut, stop_tx, cancel) 394 + } 395 + } 396 + 397 + impl Drop for MockSocket { 398 + fn drop(&mut self) { 399 + self.cancel.cancel(); 400 + } 401 + } 402 + 403 + impl Stream for MockSocket { 404 + type Item = (PeerId, PeerState); 405 + 406 + fn poll_next( 407 + self: Pin<&mut Self>, 408 + cx: &mut std::task::Context<'_>, 409 + ) -> std::task::Poll<Option<Self::Item>> { 410 + let mut peer_state_rx = Pin::new(&mut self.get_mut().peer_recv); 411 + peer_state_rx.as_mut().poll_next(cx) 412 + } 413 + } 414 + 415 + impl SocketImpl for MockSocket { 416 + fn new(_room_url: &str) -> (Self, MessageLoopFuture) { 417 + unreachable!("Tests should use [MatchboxTransport::from_socket_and_loop_fut]") 418 + } 419 + 420 + fn get_id(&mut self) -> Option<PeerId> { 421 + *self.id.lock().unwrap() 422 + } 423 + 424 + fn take_channel(&mut self) -> (MatchboxSender, MatchboxReceiver) { 425 + self.channel.take().expect("Channel already taken") 426 + } 427 + } 428 + 429 + type MatchboxTransport = super::MatchboxTransport<MockSocket>; 430 + 431 + struct WaitingPeer { 432 + incoming: MatchboxSender, 433 + outgoing: MatchboxReceiver, 434 + peer_tx: PeerTx, 435 + intended_id: PeerId, 436 + id_handle: IdHandle, 437 + disconnect: oneshot::Sender<LoopFutRes>, 438 + client_cancel: CancellationToken, 439 + } 440 + 441 + #[derive(Default, Debug)] 442 + struct MockSignaling { 443 + peers: HashMap< 444 + PeerId, 445 + ( 446 + PeerTx, 447 + oneshot::Sender<LoopFutRes>, 448 + CancellationToken, 449 + CancellationToken, 450 + ), 451 + >, 452 + senders: Arc<FutMutex<HashMap<PeerId, MatchboxSender>>>, 453 + } 454 + 455 + impl MockSignaling { 456 + fn new() -> Self { 457 + tokio::time::pause(); 458 + Self::default() 459 + } 460 + 461 + fn client_connect( 462 + &self, 463 + id: Uuid, 464 + ) -> ( 465 + WaitingPeer, 466 + FutPin<Result<Arc<MatchboxTransport>, anyhow::Error>>, 467 + ) { 468 + let (itx, irx) = mpsc::unbounded(); 469 + let (otx, orx) = mpsc::unbounded(); 470 + let (peer_tx, peer_rx) = mpsc::unbounded(); 471 + let id_handle = Arc::new(StdMutex::new(None)); 472 + 473 + let (sock, fut, disconnect, cancel) = 474 + MockSocket::new(peer_rx, (otx, irx), id_handle.clone()); 475 + 476 + let transport_fut = Box::pin(MatchboxTransport::from_socket_and_loop_fut(sock, fut)); 477 + 478 + let peer = WaitingPeer { 479 + incoming: itx, 480 + outgoing: orx, 481 + peer_tx, 482 + intended_id: PeerId(id), 483 + id_handle, 484 + disconnect, 485 + client_cancel: cancel, 486 + }; 487 + 488 + (peer, transport_fut) 489 + } 490 + 491 + async fn broadcast_peer_join(&mut self, source: PeerId) { 492 + let (source_sender, _, _, _) = self.peers.get(&source).expect("Source not in peers"); 493 + let mut source_sender = source_sender.clone(); 494 + let peers = self.peers.iter_mut().filter(|(k, _)| **k != source); 495 + for (id, (peer_tx, _, _, _)) in peers { 496 + peer_tx 497 + .send((source, PeerState::Connected)) 498 + .await 499 + .expect("Failed to send"); 500 + source_sender 501 + .send((*id, PeerState::Connected)) 502 + .await 503 + .expect("Failed to send"); 504 + } 505 + } 506 + 507 + async fn broadcast_peer_leave(&mut self, source: PeerId) { 508 + let peers = self.peers.iter_mut().filter(|(k, _)| **k != source); 509 + for (_, (peer_tx, _, _, _)) in peers { 510 + peer_tx 511 + .send((source, PeerState::Disconnected)) 512 + .await 513 + .expect("Failed to send"); 514 + } 515 + } 516 + 517 + /// Assign an ID to a MockSocket and set it so the future resolves 518 + async fn assign_id(&mut self, waiting: WaitingPeer) { 519 + let WaitingPeer { 520 + id_handle, 521 + intended_id, 522 + incoming, 523 + mut outgoing, 524 + peer_tx, 525 + disconnect, 526 + client_cancel, 527 + } = waiting; 528 + 529 + let cancel = CancellationToken::new(); 530 + 531 + *id_handle.lock().unwrap() = Some(intended_id); 532 + self.peers.insert( 533 + intended_id, 534 + (peer_tx, disconnect, cancel.clone(), client_cancel), 535 + ); 536 + self.senders.lock().await.insert(intended_id, incoming); 537 + self.broadcast_peer_join(intended_id).await; 538 + 539 + let senders = self.senders.clone(); 540 + 541 + tokio::spawn(async move { 542 + let id = intended_id; 543 + loop { 544 + tokio::select! { 545 + biased; 546 + 547 + _ = cancel.cancelled() => { break; } 548 + 549 + Some((peer, packet)) = outgoing.next() => { 550 + let mut senders = senders.lock().await; 551 + let sender = senders.get_mut(&peer).expect("Failed to find peer"); 552 + sender.send((id, packet)).await.expect("Failed to send"); 553 + } 554 + } 555 + } 556 + }); 557 + } 558 + 559 + async fn disconnect_peer(&mut self, id: Uuid, res: LoopFutRes) { 560 + let (_, dc, cancel, _) = self.peers.remove(&PeerId(id)).expect("Peer not connected"); 561 + cancel.cancel(); 562 + dc.send(res).expect("Failed to send dc"); 563 + self.broadcast_peer_leave(PeerId(id)).await; 564 + } 565 + 566 + async fn wait_for_socket_drop(&self, id: Uuid) { 567 + let cancel = self.peers.get(&PeerId(id)).unwrap().3.clone(); 568 + cancel.cancelled().await; 569 + } 570 + 571 + async fn wait_for_client_disconnected(&mut self, id: Uuid) { 572 + self.wait_for_socket_drop(id).await; 573 + self.disconnect_peer(id, Ok(())).await; 574 + } 575 + 576 + async fn wait(&self) { 577 + tokio::time::sleep(Duration::from_millis(1)).await; 578 + } 579 + 580 + async fn quick_join(&mut self, id: Uuid) -> Arc<MatchboxTransport> { 581 + let (wait, fut) = self.client_connect(id); 582 + self.assign_id(wait).await; 583 + fut.await.expect("Transport init failed") 584 + } 585 + } 586 + 587 + const fn id(x: u128) -> Uuid { 588 + Uuid::from_u128(x) 589 + } 590 + 591 + #[test] 592 + async fn test_full_loop() { 593 + let mut sig = MockSignaling::new(); 594 + 595 + let (wait, fut) = sig.client_connect(id(1)); 596 + 597 + sig.assign_id(wait).await; 598 + 599 + let transport = fut.await.expect("Tansport failed to initialize"); 600 + 601 + assert_eq!(transport.my_id, id(1)); 602 + 603 + transport.disconnect().await; 604 + 605 + sig.wait_for_client_disconnected(id(1)).await; 606 + } 607 + 608 + #[test] 609 + async fn test_dc_pre_assign() { 610 + let sig = MockSignaling::new(); 611 + 612 + let (wait, fut) = sig.client_connect(id(1)); 613 + 614 + wait.disconnect.send(Ok(())).expect("Failed to send"); 615 + 616 + let res = fut.await; 617 + 618 + assert!(res.is_err()); 619 + assert!(wait.incoming.is_closed()); 620 + assert!(wait.peer_tx.is_closed()); 621 + assert!(wait.client_cancel.is_cancelled()); 622 + } 623 + 624 + #[test] 625 + async fn test_err_pre_assign() { 626 + let sig = MockSignaling::new(); 627 + 628 + let (wait, fut) = sig.client_connect(id(1)); 629 + 630 + wait.disconnect 631 + .send(Err(SocketError::Disconnected( 632 + SignalingError::UnknownFormat, 633 + ))) 634 + .expect("Failed to send"); 635 + 636 + let res = fut.await; 637 + 638 + assert!(res.is_err()); 639 + assert!(wait.incoming.is_closed()); 640 + assert!(wait.peer_tx.is_closed()); 641 + assert!(wait.client_cancel.is_cancelled()); 642 + } 643 + 644 + #[test] 645 + async fn test_graceful_disconnect() { 646 + let mut sig = MockSignaling::new(); 647 + 648 + let (wait, fut) = sig.client_connect(id(1)); 649 + 650 + let can = wait.client_cancel.clone(); 651 + 652 + sig.assign_id(wait).await; 653 + 654 + let transport = fut.await.expect("Transport init failed"); 655 + 656 + sig.disconnect_peer(id(1), Ok(())).await; 657 + 658 + let (_, disconnected) = transport 659 + .incoming 660 + .1 661 + .lock() 662 + .await 663 + .recv() 664 + .await 665 + .expect("Transport didnt send error"); 666 + 667 + assert!(matches!(disconnected, TransportMessage::Disconnected)); 668 + 669 + can.cancelled().await; 670 + 671 + assert!(transport.incoming.0.is_closed()); 672 + assert!(transport.msg_sender.is_closed()); 673 + } 674 + 675 + #[test] 676 + async fn test_error_handle() { 677 + let mut sig = MockSignaling::new(); 678 + 679 + let (wait, fut) = sig.client_connect(id(1)); 680 + 681 + let can = wait.client_cancel.clone(); 682 + 683 + sig.assign_id(wait).await; 684 + 685 + let transport = fut.await.expect("Transport init failed"); 686 + 687 + sig.disconnect_peer( 688 + id(1), 689 + Err(SocketError::Disconnected(SignalingError::UnknownFormat)), 690 + ) 691 + .await; 692 + 693 + let (_, disconnected) = transport 694 + .incoming 695 + .1 696 + .lock() 697 + .await 698 + .recv() 699 + .await 700 + .expect("Transport didnt send error"); 701 + 702 + assert!(matches!(disconnected, TransportMessage::Error(_))); 703 + 704 + // Wait for the transport to drop the socket 705 + can.cancelled().await; 706 + 707 + assert!(transport.incoming.0.is_closed()); 708 + assert!(transport.msg_sender.is_closed()); 709 + } 710 + 711 + #[test] 712 + async fn test_message_passing() { 713 + let mut sig = MockSignaling::new(); 714 + 715 + let t1 = sig.quick_join(id(1)).await; 716 + let t2 = sig.quick_join(id(2)).await; 717 + 718 + sig.wait().await; 719 + 720 + let (_, msg) = t1.force_recv_msg().await; 721 + let (_, msg2) = t2.force_recv_msg().await; 722 + 723 + assert_eq!(t1.all_peers.lock().await.len(), 1); 724 + assert_eq!(t2.all_peers.lock().await.len(), 1); 725 + assert!(matches!(msg, TransportMessage::PeerConnect(pid) if pid == id(2))); 726 + assert!(matches!(msg2, TransportMessage::PeerConnect(pid) if pid == id(1))); 727 + 728 + t1.send_transport_message(Some(id(2)), GameEvent::PlayerCaught(id(1)).into()) 729 + .await; 730 + 731 + sig.wait().await; 732 + 733 + let (_, msg) = t2.force_recv_msg().await; 734 + 735 + assert!( 736 + matches!(msg, TransportMessage::Game(ge) if matches!(*ge, GameEvent::PlayerCaught(i) if i == id(1))) 737 + ); 738 + 739 + t2.send_transport_message(None, LobbyMessage::PlayerSwitch(id(2), true).into()) 740 + .await; 741 + 742 + sig.wait().await; 743 + 744 + let (_, msg) = t1.force_recv_msg().await; 745 + 746 + assert!( 747 + matches!(msg, TransportMessage::Lobby(lm) if matches!(*lm, LobbyMessage::PlayerSwitch(i, b) if i == id(2) && b)) 748 + ); 749 + } 750 + 751 + #[test] 752 + async fn test_msg_broadcast() { 753 + let mut sig = MockSignaling::new(); 754 + 755 + let t1 = sig.quick_join(id(1)).await; 756 + let t2 = sig.quick_join(id(2)).await; 757 + let t3 = sig.quick_join(id(3)).await; 758 + let t4 = sig.quick_join(id(4)).await; 759 + 760 + sig.wait().await; 761 + 762 + let ts = [t1, t2, t3, t4]; 763 + 764 + for t in ts.iter() { 765 + assert_eq!(t.all_peers.lock().await.len(), ts.len() - 1); 766 + // Eat the PeerConnected messages 767 + for _ in 0..(ts.len() - 1) { 768 + t.force_recv_msg().await; 769 + } 770 + } 771 + 772 + ts[0] 773 + .send_transport_message(None, GameEvent::PlayerCaught(id(1)).into()) 774 + .await; 775 + 776 + sig.wait().await; 777 + 778 + ts[0].assert_no_incoming().await; 779 + 780 + for t in ts.iter().skip(1) { 781 + let (pid, msg) = t.force_recv_msg().await; 782 + assert_eq!(pid, Some(id(1))); 783 + assert!( 784 + matches!(msg, TransportMessage::Game(ge) if matches!(*ge, GameEvent::PlayerCaught(i) if i == id(1))) 785 + ); 786 + } 787 + } 788 + 789 + #[test] 790 + async fn test_direct_msg() { 791 + let mut sig = MockSignaling::new(); 792 + 793 + let t1 = sig.quick_join(id(1)).await; 794 + let t2 = sig.quick_join(id(2)).await; 795 + let t3 = sig.quick_join(id(3)).await; 796 + 797 + sig.wait().await; 798 + 799 + let ts = [t1, t2, t3]; 800 + 801 + for t in ts.iter() { 802 + assert_eq!(t.all_peers.lock().await.len(), ts.len() - 1); 803 + // Eat the PeerConnected messages 804 + for _ in 0..(ts.len() - 1) { 805 + t.force_recv_msg().await; 806 + } 807 + } 808 + 809 + ts[0] 810 + .send_transport_message(Some(id(2)), GameEvent::PlayerCaught(id(1)).into()) 811 + .await; 812 + 813 + sig.wait().await; 814 + 815 + ts[0].assert_no_incoming().await; 816 + ts[2].assert_no_incoming().await; 817 + 818 + let (pid, msg) = ts[1].force_recv_msg().await; 819 + assert_eq!(pid, Some(id(1))); 820 + assert!( 821 + matches!(msg, TransportMessage::Game(ge) if matches!(*ge, GameEvent::PlayerCaught(i) if i == id(1))) 822 + ); 823 + } 824 + 825 + #[test] 826 + async fn test_multiple_disconnect() { 827 + let mut sig = MockSignaling::new(); 828 + 829 + let t1 = sig.quick_join(id(1)).await; 830 + let t2 = sig.quick_join(id(2)).await; 831 + let t3 = sig.quick_join(id(3)).await; 832 + 833 + sig.wait().await; 834 + 835 + let ts = [t1, t2, t3]; 836 + 837 + for t in ts.iter() { 838 + assert_eq!(t.all_peers.lock().await.len(), ts.len() - 1); 839 + // Eat the PeerConnected messages 840 + for _ in 0..(ts.len() - 1) { 841 + t.force_recv_msg().await; 842 + } 843 + } 844 + 845 + ts[0].disconnect().await; 846 + 847 + sig.wait_for_client_disconnected(id(1)).await; 848 + 849 + sig.wait().await; 850 + 851 + for t in ts.iter().skip(1) { 852 + let (_, msg) = t.force_recv_msg().await; 853 + 854 + let all = t.all_peers.lock().await; 855 + assert!(!all.contains(&id(1))); 856 + assert!(matches!(msg, TransportMessage::PeerDisconnect(i) if i == id(1))); 857 + } 858 + } 859 + 860 + #[test] 861 + async fn test_big_message() { 862 + // Just a random string that's bigger than the max packet size 863 + let pfp = "vbnsj".repeat(65560); 864 + let pfp2 = pfp.clone(); 865 + 866 + let mut sig = MockSignaling::new(); 867 + 868 + let t1 = sig.quick_join(id(1)).await; 869 + let t2 = sig.quick_join(id(2)).await; 870 + 871 + sig.wait().await; 872 + 873 + t1.force_recv_msg().await; 874 + t2.force_recv_msg().await; 875 + 876 + t1.send_transport_message( 877 + Some(id(2)), 878 + LobbyMessage::PlayerSync( 879 + id(1), 880 + PlayerProfile { 881 + display_name: "asdf".to_string(), 882 + pfp_base64: Some(pfp2), 883 + }, 884 + ) 885 + .into(), 886 + ) 887 + .await; 888 + 889 + sig.wait().await; 890 + 891 + let (_, msg) = t2.force_recv_msg().await; 892 + 893 + if let TransportMessage::Lobby(le) = msg { 894 + if let LobbyMessage::PlayerSync(i, p) = *le { 895 + assert_eq!(i, id(1)); 896 + assert_eq!(p.display_name, "asdf".to_string()); 897 + assert_eq!(p.pfp_base64, Some(pfp)); 898 + } else { 899 + panic!("Incorrect lobby message"); 900 + } 901 + } else { 902 + panic!("Incorrect message"); 903 + } 904 + } 905 + }