aldrin_test/lib.rs
1//! Utilities for Aldrin server and client tests
2//!
3//! This crate provides a simple way to quickly setup a complete Aldrin bus with a broker and
4//! multiple clients and is intended to be used in unit tests.
5//!
6//! If you are using Tokio, it is strongly recommended to enable this crate's `tokio` feature and
7//! use the types in the `tokio` module instead of the crate-level types.
8
9#![deny(missing_debug_implementations)]
10#![deny(missing_docs)]
11
12#[cfg(test)]
13mod test;
14
15#[cfg(feature = "tokio")]
16pub mod tokio;
17
18use aldrin::{Client, Handle};
19use aldrin_broker::{Broker, BrokerHandle, Connection, ConnectionHandle};
20use aldrin_core::channel::{self, Disconnected};
21use aldrin_core::transport::{AsyncTransportExt, BoxedTransport};
22use futures_util::future;
23use std::ops::{Deref, DerefMut};
24
25// For tests directly in aldrin_broker and aldrin.
26#[doc(hidden)]
27pub use {aldrin, aldrin_broker};
28
29/// Broker for use in tests.
30///
31/// This type is a simple wrapper around [`aldrin_broker::Broker`] and
32/// [`aldrin_broker::BrokerHandle`]. All method of [`BrokerHandle`] can be called on this type as
33/// well due to its [`Deref`] implementation.
34///
35/// The underlying [`Broker`] is not automatically started. Users must
36/// [take the `broker`](TestBroker::take_broker) and [run](Broker::run) it manually.
37///
38/// See the [crate-level documentation](crate) for usage examples.
39#[derive(Debug)]
40pub struct TestBroker {
41 handle: BrokerHandle,
42 broker: Option<Broker>,
43}
44
45impl TestBroker {
46 /// Creates a new broker.
47 pub fn new() -> Self {
48 let broker = Broker::new();
49
50 Self {
51 handle: broker.handle().clone(),
52 broker: Some(broker),
53 }
54 }
55
56 /// Returns a handle to the broker.
57 pub fn handle(&self) -> &BrokerHandle {
58 &self.handle
59 }
60
61 /// Takes the broker out of this struct.
62 ///
63 /// After creating a [`TestBroker`], the actual [`Broker`] must be taken out and
64 /// [run](Broker::run).
65 ///
66 /// # Panics
67 ///
68 /// This function panics when the [`Broker`] has already been taken out. It must be called only
69 /// once.
70 pub fn take_broker(&mut self) -> Broker {
71 self.broker.take().expect("broker already taken")
72 }
73
74 /// Add a new client to the broker.
75 pub async fn add_client(&mut self) -> TestClient {
76 let (t1, t2) = channel::unbounded();
77
78 let client = Client::connect(t1.boxed());
79 let conn = self.handle.connect(t2.boxed());
80
81 let (client, conn) = future::join(client, conn).await;
82 let client = client.expect("client failed to connect");
83 let handle = client.handle().clone();
84 let conn = conn.expect("connection failed to establish");
85 let connection_handle = conn.handle().clone();
86
87 TestClient::new(handle, connection_handle, client, conn)
88 }
89}
90
91impl Default for TestBroker {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl Deref for TestBroker {
98 type Target = BrokerHandle;
99
100 fn deref(&self) -> &BrokerHandle {
101 &self.handle
102 }
103}
104
105impl DerefMut for TestBroker {
106 fn deref_mut(&mut self) -> &mut BrokerHandle {
107 &mut self.handle
108 }
109}
110
111/// Client for use in tests.
112///
113/// After creating a [`TestClient`], it is fully connected to the [`TestBroker`], but neither the
114/// underlying [`Client`] nor the [`Connection`] are running. This must be done manually by taking
115/// both parts out and calling their respective `run` methods (see
116/// [`take_client`](Self::take_client) and [`take_connection`](Self::take_connection).
117///
118/// [`TestClient`] dereferences to [`aldrin::Handle`] and thus all methods on [`Handle`] can
119/// be called on [`TestClient`] as well.
120#[derive(Debug)]
121pub struct TestClient {
122 handle: Handle,
123 connection_handle: ConnectionHandle,
124 client: Option<Client<BoxedTransport<'static, Disconnected>>>,
125 conn: Option<Connection<BoxedTransport<'static, Disconnected>>>,
126}
127
128impl TestClient {
129 fn new(
130 handle: Handle,
131 connection_handle: ConnectionHandle,
132 client: Client<BoxedTransport<'static, Disconnected>>,
133 conn: Connection<BoxedTransport<'static, Disconnected>>,
134 ) -> Self {
135 Self {
136 handle,
137 connection_handle,
138 client: Some(client),
139 conn: Some(conn),
140 }
141 }
142
143 /// Returns a handle to the client.
144 pub fn handle(&self) -> &Handle {
145 &self.handle
146 }
147
148 /// Returns a handle to the connection.
149 pub fn connection(&self) -> &ConnectionHandle {
150 &self.connection_handle
151 }
152
153 /// Takes the `Client` out of this struct.
154 ///
155 /// After creating a [`TestClient`], the actual [`Client`] must be taken out and
156 /// [run](Client::run).
157 ///
158 /// # Panics
159 ///
160 /// This function panics when the [`Client`] has already been taken out. It must be called only
161 /// once.
162 pub fn take_client(&mut self) -> Client<BoxedTransport<'static, Disconnected>> {
163 self.client.take().expect("client already taken")
164 }
165
166 /// Takes the `Connection` out of this struct.
167 ///
168 /// After creating a [`TestClient`], the actual [`Connection`] must be taken out and
169 /// [run](Connection::run).
170 ///
171 /// # Panics
172 ///
173 /// This function panics when the [`Connection`] has already been taken out. It must be called
174 /// only once.
175 pub fn take_connection(&mut self) -> Connection<BoxedTransport<'static, Disconnected>> {
176 self.conn.take().expect("connection already taken")
177 }
178}
179
180impl Deref for TestClient {
181 type Target = Handle;
182
183 fn deref(&self) -> &Handle {
184 &self.handle
185 }
186}