How to test asynchronous client server code?

#1

How do I test asynchronous code? I’m getting by with a mutable flag but man is this test ugly. I was wondering if there are any best practices for doing this sort of thing, I’m open to using a new library as well - but I’d prefer to do it all with std if possible.

The client and server are provided by the ws-rs library.

Playground

#[cfg(test)]
mod tests {
  use std::sync::{Arc, Mutex, MutexGuard};
  use std::sync::mpsc::channel;
  use std::thread;

  use crate::components::{Player, Position};
  use crate::message::PositionMessage;
  use crate::wsserver;

  struct Flag(bool);

  struct Client <'a> {
    out: ws::Sender,
    received: MutexGuard<'a, Flag>
  }

  impl <'a> ws::Handler for Client <'a> {
    fn on_message(&mut self, _: ws::Message) -> Result<(), ws::Error> {
      self.received.0 = true;
      self.out.close(ws::CloseCode::Normal)
    }
  }

  #[test]
  fn send_server_position_message() {
    let (position_message_sender, position_message_receiver) = channel();
    let (input_message_sender, _) = channel();

    thread::Builder::new()
      .name("Websockets Server".to_owned())
      .spawn(move || { wsserver::main(position_message_receiver, input_message_sender) })
      .unwrap();

    let flag = Arc::new(Mutex::new(Flag(false)));
    let flag_clone = flag.clone();

    let client = thread::spawn(move || {
      let flag = flag.clone();
      ws::connect("ws://127.0.0.1:8081", |out| {
        Client { out, received: flag.lock().unwrap() }
      }).unwrap();
    });

    position_message_sender.send(PositionMessage {
      player: Player { id: 0 },
      position: Position { x: 0.0, y: 0.0 }
    }).unwrap();

    client.join().unwrap();

    assert!(flag_clone.lock().unwrap().0);
  }
}