rustwave 0.1.0

A lightweight async event-driven WebSocket framework for Rust
Documentation
// Run this  test file: cargo test --test disconnect -- --nocapture

use rustwave::{Client, Server};
use std::time::Duration;
use tokio::{sync::mpsc::channel, time::sleep};

// Tests 1
#[tokio::test]
async fn test_server_disconnect_all() {
    let addr: &str = "127.0.0.1:9102";
    let server = Server::bind(addr);
    let ns = server.namespace("/");

    tokio::spawn(async move {
        let _ = server.run().await;
    });

    sleep(Duration::from_millis(200)).await;

    let client = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    sleep(Duration::from_millis(200)).await;

    assert_eq!(ns.get_client_count(), 1);

    let client2 = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    let client3 = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    ns.disconnect_all().await.unwrap();

    client.wait().await;
    client2.wait().await;
    client3.wait().await;

    assert_eq!(ns.get_client_count(), 0);
}

// Test 2
#[tokio::test]
async fn test_client_side_disconnect() {
    let addr = "127.0.0.1:9101";
    let server = Server::bind(addr);

    let (tx, mut rx) = channel::<()>(1);

    server.on("connection", move |_data, _ctx| async move {});

    server.on("disconnect", move |_data, _ctx| {
        let tx = tx.clone();
        async move {
            let _ = tx.send(()).await;
        }
    });

    tokio::spawn(async move {
        let _ = server.run().await;
    });

    sleep(Duration::from_millis(200)).await;

    let client = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    sleep(Duration::from_millis(200)).await;

    client.close().await;

    let result = tokio::time::timeout(Duration::from_secs(2), rx.recv())
        .await
        .expect("server never fired the disconnect handler");

    assert!(result.is_some());
}

// Test 3
#[tokio::test]
async fn test_disconnect_updates_server_state() {
    let addr = "127.0.0.1:9004";
    let server = Server::bind(addr);
    let root = server.namespace("/");

    let (id_tx, mut id_rx) = channel::<uuid::Uuid>(1);
    server.on("connection", move |_data, ctx| {
        let id_tx = id_tx.clone();
        async move {
            let _ = id_tx.send(ctx.get_socket_id()).await;
        }
    });

    tokio::spawn(async move {
        let _ = server.run().await;
    });

    sleep(Duration::from_millis(200)).await;

    let client = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    let socket_id = tokio::time::timeout(Duration::from_secs(2), id_rx.recv())
        .await
        .expect("did not receive connection event")
        .expect("channel closed");

    assert!(root.is_connected(&socket_id));
    assert_eq!(root.get_client_count(), 1);

    client.close().await;

    sleep(Duration::from_millis(300)).await;

    assert!(!root.is_connected(&socket_id));
    assert_eq!(root.get_client_count(), 0);
}

// Test 4
#[tokio::test]
async fn test_server_forces_client_disconnect() {
    let addr = "127.0.0.1:9005";
    let server = Server::bind(addr);
    let root = server.namespace("/");

    server.on("connection", move |_data, ctx| {
        let root = root.clone();
        async move {
            let socket_id = ctx.get_socket_id();
            sleep(Duration::from_millis(100)).await;
            let _ = root.disconnect(&socket_id).await;
        }
    });

    tokio::spawn(async move {
        let _ = server.run().await;
    });

    sleep(Duration::from_millis(200)).await;

    let client = Client::connect(&format!("ws://{}", addr)).await.unwrap();

    let (tx, mut rx) = channel::<()>(1);
    client.on("disconnect", move |_data| {
        let tx = tx.clone();
        async move {
            let _ = tx.send(()).await;
        }
    });

    let result = tokio::time::timeout(Duration::from_secs(2), rx.recv()).await;

    assert!(
        result.is_ok(),
        "client never observed a disconnect after server called ns.disconnect()"
    );
}