Skip to content

Commit 0d028ad

Browse files
nits
1 parent b27a1c9 commit 0d028ad

5 files changed

Lines changed: 297 additions & 302 deletions

File tree

client/src/lib.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,104 @@ pub struct Client<S: Strategy, C: Scheme> {
197197
ws_connector: WsConnector,
198198
strategy: S,
199199
}
200+
201+
#[cfg(test)]
202+
mod tests {
203+
use super::{ClientBuilder, Error};
204+
use alto_types::{Identity, StandardScheme, NAMESPACE};
205+
use commonware_math::algebra::CryptoGroup;
206+
use commonware_parallel::Sequential;
207+
use futures::StreamExt;
208+
use std::time::Duration;
209+
use tokio::{io::AsyncWriteExt, net::TcpListener};
210+
use tokio_tungstenite::tungstenite::{error::CapacityError, Error as WsError};
211+
212+
/// Send raw frames through a real client and return its transport or artifact error.
213+
async fn receive_error(block_size: Option<u32>, frames: Vec<u8>) -> Error {
214+
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
215+
let addr = listener.local_addr().unwrap();
216+
let server = tokio::spawn(async move {
217+
let (socket, _) = listener.accept().await.unwrap();
218+
let mut socket = tokio_tungstenite::accept_async(socket).await.unwrap();
219+
socket.get_mut().write_all(&frames).await.unwrap();
220+
socket.get_mut().shutdown().await.unwrap();
221+
});
222+
let mut builder = ClientBuilder::new(
223+
&format!("http://{addr}"),
224+
StandardScheme::certificate_verifier(NAMESPACE, Identity::generator()),
225+
Sequential,
226+
);
227+
if let Some(block_size) = block_size {
228+
builder = builder.with_block_size(block_size);
229+
}
230+
let client = builder.build();
231+
let mut stream = client.listen().await.unwrap();
232+
let result = tokio::time::timeout(Duration::from_secs(5), stream.next())
233+
.await
234+
.expect("frame processing stalled")
235+
.expect("frame did not produce a result");
236+
server.await.unwrap();
237+
match result {
238+
Err(error) => error,
239+
Ok(_) => panic!("unexpected consensus artifact"),
240+
}
241+
}
242+
243+
#[tokio::test]
244+
async fn oversized_frames_are_rejected_from_the_header() {
245+
for (block_size, limit) in [
246+
(None, 5 * 1024 * 1024 + 1),
247+
(Some(0), 1024 * 1024 + 1),
248+
(Some(4096), 1024 * 1024 + 4097),
249+
] {
250+
for fragmented in [false, true] {
251+
// Announce one byte beyond the receive limit, without sending its payload.
252+
let mut frames = Vec::new();
253+
if fragmented {
254+
frames.extend_from_slice(&[0x02, 0x01, 0x00]);
255+
}
256+
frames.extend_from_slice(&[if fragmented { 0x80 } else { 0x82 }, 0x7f]);
257+
frames.extend_from_slice(&((limit + 1) as u64).to_be_bytes());
258+
assert!(matches!(
259+
receive_error(block_size, frames).await,
260+
Error::Tungstenite(WsError::Capacity(CapacityError::MessageTooLong {
261+
size,
262+
max_size,
263+
})) if size == limit + 1 && max_size == limit
264+
));
265+
}
266+
}
267+
}
268+
269+
#[tokio::test]
270+
async fn streaming_budget_includes_the_message_kind() {
271+
// An HTTP artifact can fill the entire encoding allowance. Its stream adds one kind byte.
272+
let length = 1024 * 1024 + 1;
273+
let mut frame = vec![0x82, 0x7f];
274+
frame.extend_from_slice(&(length as u64).to_be_bytes());
275+
frame.resize(frame.len() + length, 0xff);
276+
277+
// Reaching kind dispatch proves that the complete message passed the transport limit.
278+
assert!(matches!(
279+
receive_error(Some(0), frame).await,
280+
Error::UnexpectedResponse
281+
));
282+
}
283+
284+
#[tokio::test]
285+
async fn fragmented_messages_share_the_receive_budget() {
286+
// Each frame fits by itself, but their combined payload exceeds the message budget.
287+
let length = 1024 * 1024;
288+
let mut frames = vec![0x02, 0x7f];
289+
frames.extend_from_slice(&(length as u64).to_be_bytes());
290+
frames.resize(frames.len() + length, 0xff);
291+
frames.extend_from_slice(&[0x80, 0x02, 0xff, 0xff]);
292+
assert!(matches!(
293+
receive_error(Some(0), frames).await,
294+
Error::Tungstenite(WsError::Capacity(CapacityError::MessageTooLong {
295+
size,
296+
max_size,
297+
})) if size == length + 2 && max_size == length + 1
298+
));
299+
}
300+
}

client/tests/websocket.rs

Lines changed: 0 additions & 97 deletions
This file was deleted.

0 commit comments

Comments
 (0)