Skip to main content

dnet_tests/
lib.rs

1//! Common tests for `dnet` transport implementations.
2
3#![warn(missing_docs)]
4
5use std::fmt::Debug;
6use std::time::Duration;
7
8use dnet_base::{Messages, Receive, Transport};
9
10use futures::{stream, SinkExt, StreamExt};
11
12/// Convenience attribute macro for marking tests that need to run for both native and WASM targets.
13pub use dportable::test::dtest;
14
15/// Configure WASM tests to run in browser.
16pub use dportable::test::dtest_configure;
17
18/// Test transport by sending strings and integers between two connected instances.
19pub async fn test_transport<L, R, E1, E2>(mut left: L, mut right: R)
20where
21    L: Transport<u32, String, E1> + Unpin,
22    R: Transport<String, u32, E2> + Unpin,
23    E1: Debug,
24    E2: Debug,
25{
26    init_logging(&mut left, &mut right);
27
28    left.send("Hello World!".to_string()).await.unwrap();
29    left.send("Hello World again!".to_string()).await.unwrap();
30    right.send(128).await.unwrap();
31    right.send(1).await.unwrap();
32
33    assert_eq!(right.receive().await.unwrap(), "Hello World!");
34    assert_eq!(right.receive().await.unwrap(), "Hello World again!");
35    assert_eq!(left.receive().await.unwrap(), 128);
36    assert_eq!(left.receive().await.unwrap(), 1);
37}
38
39/// Test transport by sending units (`()`) between two connected instances.
40///
41/// When used with `BincodeCodec` it can verify sending message of length 0 (in bytes) works.
42pub async fn test_unit_message<L, R, E1, E2>(mut left: L, mut right: R)
43where
44    L: Transport<(), (), E1> + Unpin,
45    R: Transport<(), (), E2> + Unpin,
46    E1: Debug,
47    E2: Debug,
48{
49    init_logging(&mut left, &mut right);
50
51    left.send(()).await.unwrap();
52    left.send(()).await.unwrap();
53    right.send(()).await.unwrap();
54    right.send(()).await.unwrap();
55
56    right.receive().await.unwrap();
57    right.receive().await.unwrap();
58    left.receive().await.unwrap();
59    left.receive().await.unwrap();
60}
61
62/// Test transport by collecting received messages while treating transport as a stream.
63///
64/// It verifies if transport closing (or dropping) on one side is
65/// communicated to the other side - without it, stream would never complete.
66pub async fn test_stream<L, R, E1, E2>(left: L, right: R)
67where
68    L: Transport<(), u32, E1> + Unpin,
69    R: Transport<u32, (), E2> + Unpin,
70    E1: Debug,
71    E2: Debug,
72{
73    test_stream_with_sleep_before_drop(left, right, Duration::ZERO).await
74}
75
76/// Same as [test_stream] except we [sleep](dportable::time::sleep) for specified
77/// duration before dropping the sending transport.
78///
79/// Used by unreliable QUIC transport - there is no mechanism for the underlying
80/// unreliable transport to wait for messages to be flushed.
81pub async fn test_stream_with_sleep_before_drop<L, R, E1, E2>(
82    mut left: L,
83    mut right: R,
84    duration: Duration,
85) where
86    L: Transport<(), u32, E1> + Unpin,
87    R: Transport<u32, (), E2> + Unpin,
88    E1: Debug,
89    E2: Debug,
90{
91    init_logging(&mut left, &mut right);
92
93    left.send_all(&mut stream::iter(vec![1, 2, 3].into_iter().map(Ok)))
94        .await
95        .unwrap();
96    if !duration.is_zero() {
97        dportable::time::sleep(duration).await;
98    }
99    drop(left);
100
101    assert_eq!(right.messages().collect::<Vec<u32>>().await, vec![1, 2, 3]);
102}
103
104/// Init tracing subscriber and enable logging for given transports.
105pub fn init_logging<T1, T2, T1I, T1O, T2I, T2O, E1, E2>(left: &mut T1, right: &mut T2)
106where
107    T1: Transport<T1I, T1O, E1>,
108    T2: Transport<T2I, T2O, E2>,
109{
110    #[cfg(not(feature = "logging"))]
111    {
112        let _ = (left, right);
113    }
114
115    #[cfg(feature = "logging")]
116    {
117        init_subscriber();
118
119        left.enable_logging();
120        left.set_logging_name("left");
121
122        right.enable_logging();
123        right.set_logging_name("right");
124    }
125}
126
127/// Init tracing subscriber.
128#[cfg(feature = "logging")]
129pub fn init_subscriber() {
130    use std::sync::Once;
131
132    static INIT: Once = Once::new();
133    INIT.call_once(|| {
134        #[cfg(target_arch = "wasm32")]
135        wasm_tracing::set_as_global_default();
136
137        #[cfg(not(target_arch = "wasm32"))]
138        tracing_subscriber::fmt().with_env_filter("trace").init();
139    });
140}