Skip to content

Commit 9e58091

Browse files
committed
test(cancellation): added read_cancellation test
Signed-off-by: Jad K. Haddad <jadkhaddad@gmail.com>
1 parent 37f49e1 commit 9e58091

4 files changed

Lines changed: 161 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ bytes = "1"
3434
hyper = "1"
3535
futures = "0.3"
3636
hyper-util = "0.1"
37+
pin-project-lite = "0.2.17"
3738

3839
[profile.release]
3940
opt-level = 3

src/codec.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ mod tests {
434434
}
435435

436436
mod encode {
437+
use std::println;
438+
437439
use rand::{
438440
SeedableRng,
439441
rngs::{StdRng, SysRng},
@@ -452,5 +454,23 @@ mod tests {
452454

453455
assert!(matches!(error, FrameEncodeError::BufferTooSmall));
454456
}
457+
458+
#[test]
459+
#[ignore = "print"]
460+
fn print() {
461+
let dst = &mut [0u8; 1024];
462+
let message = Message::Text(
463+
"hello hello hello hello hello hello hello hello hello hello hello hello",
464+
);
465+
466+
let mut codec =
467+
FramesCodec::new(StdRng::try_from_rng(&mut SysRng).unwrap()).into_client();
468+
469+
let size = codec
470+
.encode(message, dst)
471+
.expect("Failed to encode message");
472+
473+
println!("Encoded frame ({} bytes): {:?}", size, &dst[..size]);
474+
}
455475
}
456476
}

src/tests.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use core::{
2+
convert::Infallible,
3+
pin::Pin,
4+
task::{Context, Poll},
5+
};
6+
17
use embedded_io_adapters::tokio_1::FromTokio;
28
use rand::{
39
SeedableRng,
@@ -1258,3 +1264,134 @@ mod protocol {
12581264
quick_protocol_error!(FRAME, InvalidContinuationFrame);
12591265
}
12601266
}
1267+
1268+
mod cancellation {
1269+
use super::*;
1270+
1271+
#[tokio::test]
1272+
async fn read_cancellation() {
1273+
use embedded_io_async::{ErrorType, Read, Write};
1274+
use pin_project_lite::pin_project;
1275+
1276+
let message = "hello hello hello hello hello hello hello hello hello hello hello hello";
1277+
1278+
let client_frame = &[
1279+
129, 199, 50, 247, 26, 102, 90, 146, 118, 10, 93, 215, 114, 3, 94, 155, 117, 70, 90,
1280+
146, 118, 10, 93, 215, 114, 3, 94, 155, 117, 70, 90, 146, 118, 10, 93, 215, 114, 3, 94,
1281+
155, 117, 70, 90, 146, 118, 10, 93, 215, 114, 3, 94, 155, 117, 70, 90, 146, 118, 10,
1282+
93, 215, 114, 3, 94, 155, 117, 70, 90, 146, 118, 10, 93, 215, 114, 3, 94, 155, 117,
1283+
];
1284+
1285+
struct Reader<'a> {
1286+
buf: &'a [u8],
1287+
bytes_per_read_call: usize,
1288+
yield_next: bool, // Add this flag
1289+
}
1290+
1291+
impl ErrorType for Reader<'_> {
1292+
type Error = Infallible;
1293+
}
1294+
1295+
impl Write for Reader<'_> {
1296+
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1297+
Ok(buf.len())
1298+
}
1299+
1300+
async fn flush(&mut self) -> Result<(), Self::Error> {
1301+
Ok(())
1302+
}
1303+
}
1304+
1305+
impl Read for Reader<'_> {
1306+
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1307+
if self.yield_next {
1308+
self.yield_next = false;
1309+
tokio::task::yield_now().await;
1310+
}
1311+
1312+
let bytes_to_read = self.bytes_per_read_call.min(self.buf.len());
1313+
if bytes_to_read == 0 {
1314+
return Ok(0);
1315+
}
1316+
1317+
buf[..bytes_to_read].copy_from_slice(&self.buf[..bytes_to_read]);
1318+
self.buf = &self.buf[bytes_to_read..];
1319+
1320+
self.yield_next = true;
1321+
1322+
Ok(bytes_to_read)
1323+
}
1324+
}
1325+
1326+
let reader = Reader {
1327+
buf: client_frame,
1328+
bytes_per_read_call: 8,
1329+
yield_next: false,
1330+
};
1331+
1332+
pin_project! {
1333+
struct DropFutureCounter<'a, F> {
1334+
count: &'a mut usize,
1335+
#[pin]
1336+
f: F,
1337+
}
1338+
1339+
impl<F> PinnedDrop for DropFutureCounter<'_, F> {
1340+
fn drop(this: Pin<&mut Self>) {
1341+
**this.project().count += 1;
1342+
}
1343+
}
1344+
}
1345+
1346+
impl<'a, F> DropFutureCounter<'a, F> {
1347+
fn new(count: &'a mut usize, f: F) -> Self {
1348+
Self { f, count }
1349+
}
1350+
}
1351+
1352+
impl<'a, F: Future> Future for DropFutureCounter<'a, F> {
1353+
type Output = F::Output;
1354+
1355+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1356+
let this = self.project();
1357+
this.f.poll(cx)
1358+
}
1359+
}
1360+
1361+
let read_buf = &mut [0u8; SIZE];
1362+
let write_buf = &mut [0u8; SIZE];
1363+
let fragments_buf = &mut [0u8; SIZE];
1364+
1365+
let mut websocketz = WebSocket::server(
1366+
reader,
1367+
StdRng::try_from_rng(&mut SysRng).unwrap(),
1368+
read_buf,
1369+
write_buf,
1370+
fragments_buf,
1371+
);
1372+
1373+
let mut drop_count = 0usize;
1374+
1375+
loop {
1376+
let fut = DropFutureCounter::new(&mut drop_count, async {
1377+
match next!(websocketz) {
1378+
Some(Ok(Message::Text(payload))) => {
1379+
assert_eq!(payload, message);
1380+
}
1381+
message => panic!("Unexpected message: {message:?}"),
1382+
}
1383+
});
1384+
1385+
tokio::select! {
1386+
biased;
1387+
_ = fut => break,
1388+
_ = async {} => {}
1389+
}
1390+
}
1391+
1392+
assert!(
1393+
drop_count > 0,
1394+
"Expected future to be dropped at least once, but it was not dropped"
1395+
);
1396+
}
1397+
}

0 commit comments

Comments
 (0)