Skip to content

Commit f956b3a

Browse files
committed
test(auto): added tests for auto close
Signed-off-by: Jad K. Haddad <jadkhaddad@gmail.com>
1 parent 7065578 commit f956b3a

5 files changed

Lines changed: 157 additions & 10 deletions

File tree

src/functions.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use framez::state::{ReadState, WriteState};
33
use rand::RngCore;
44

55
use crate::{
6-
Frame, Message, OnFrame, WebSocketCore,
6+
ConnectionState, Frame, Message, OnFrame, WebSocketCore,
77
codec::FramesCodec,
88
error::{Error, ProtocolError, ReadError, WriteError},
99
websocket_core::FragmentsState,
@@ -89,12 +89,15 @@ pub async fn send<RW, Rng>(
8989
codec: &mut FramesCodec<Rng>,
9090
inner: &mut RW,
9191
write_state: &mut WriteState<'_>,
92+
state: &mut ConnectionState,
9293
message: Message<'_>,
9394
) -> Result<(), Error<RW::Error>>
9495
where
9596
RW: Write,
9697
Rng: RngCore,
9798
{
99+
state.closed = message.is_close();
100+
98101
framez::functions::send(write_state, codec, inner, message)
99102
.await
100103
.map_err(|err| Error::Write(WriteError::WriteFrame(err)))?;

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use opcode::OpCode;
4040
pub mod options;
4141

4242
mod websocket_core;
43-
use websocket_core::{FragmentsState, OnFrame, WebSocketCore};
43+
use websocket_core::{ConnectionState, FragmentsState, OnFrame, WebSocketCore};
4444

4545
mod websocket;
4646
pub use websocket::{WebSocket, WebSocketRead, WebSocketWrite};

src/macros.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ macro_rules! send {
3030
&mut $websocketz.core.framed.core.codec,
3131
&mut $websocketz.core.framed.core.inner,
3232
&mut $websocketz.core.framed.core.state.write,
33+
&mut $websocketz.core.state,
3334
$message,
3435
)
3536
.await

src/tests.rs

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,5 +955,119 @@ mod fragmentation {
955955
}
956956
}
957957

958+
mod auto {
959+
use crate::CloseFrame;
960+
961+
use super::*;
962+
963+
#[tokio::test]
964+
async fn pong() {
965+
let (client, server) = tokio::io::duplex(16);
966+
967+
let client = async move {
968+
let read_buf = &mut [0u8; SIZE];
969+
let write_buf = &mut [0u8; SIZE];
970+
let fragments_buf = &mut [0u8; SIZE];
971+
972+
let mut websocketz = WebSocket::client(
973+
FromTokio::new(client),
974+
StdRng::from_os_rng(),
975+
read_buf,
976+
write_buf,
977+
fragments_buf,
978+
);
979+
980+
// Send a ping frame
981+
websocketz
982+
.send(Message::Ping(b"ping"))
983+
.await
984+
.expect("Failed to send ping message");
985+
986+
// Expect a pong frame in response
987+
match next!(websocketz) {
988+
Some(Ok(Message::Pong(payload))) => {
989+
assert_eq!(payload, b"ping");
990+
}
991+
message => panic!("Unexpected message: {message:?}"),
992+
}
993+
};
994+
995+
let server = async move {
996+
let read_buf = &mut [0u8; SIZE];
997+
let write_buf = &mut [0u8; SIZE];
998+
let fragments_buf = &mut [0u8; SIZE];
999+
1000+
let mut websocketz = WebSocket::server(
1001+
FromTokio::new(server),
1002+
StdRng::from_os_rng(),
1003+
read_buf,
1004+
write_buf,
1005+
fragments_buf,
1006+
);
1007+
1008+
while next!(websocketz).is_some() {}
1009+
};
1010+
1011+
tokio::join!(server, client);
1012+
}
1013+
1014+
#[tokio::test]
1015+
async fn close() {
1016+
let (client, server) = tokio::io::duplex(16);
1017+
1018+
let client = async move {
1019+
let read_buf = &mut [0u8; SIZE];
1020+
let write_buf = &mut [0u8; SIZE];
1021+
let fragments_buf = &mut [0u8; SIZE];
1022+
1023+
let mut websocketz = WebSocket::client(
1024+
FromTokio::new(client),
1025+
StdRng::from_os_rng(),
1026+
read_buf,
1027+
write_buf,
1028+
fragments_buf,
1029+
);
1030+
1031+
// Send a close frame
1032+
websocketz
1033+
.send(Message::Close(Some(CloseFrame::new(
1034+
CloseCode::Normal,
1035+
"close",
1036+
))))
1037+
.await
1038+
.expect("Failed to send close message");
1039+
1040+
// Expect a close frame in response
1041+
match next!(websocketz) {
1042+
Some(Ok(Message::Close(Some(frame)))) => {
1043+
assert_eq!(frame.code(), CloseCode::Normal);
1044+
assert_eq!(frame.reason(), "close");
1045+
}
1046+
message => panic!("Unexpected message: {message:?}"),
1047+
}
1048+
1049+
// Ensure the connection is closed
1050+
assert!(next!(websocketz).is_none());
1051+
};
1052+
1053+
let server = async move {
1054+
let read_buf = &mut [0u8; SIZE];
1055+
let write_buf = &mut [0u8; SIZE];
1056+
let fragments_buf = &mut [0u8; SIZE];
1057+
1058+
let mut websocketz = WebSocket::server(
1059+
FromTokio::new(server),
1060+
StdRng::from_os_rng(),
1061+
read_buf,
1062+
write_buf,
1063+
fragments_buf,
1064+
);
1065+
1066+
while next!(websocketz).is_some() {}
1067+
};
1068+
1069+
tokio::join!(server, client);
1070+
}
1071+
}
1072+
9581073
// TODO: test for read errors
959-
// TODO: test auto ping and auto close

src/websocket_core.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ struct Fragmented {
4747

4848
#[derive(Debug, Clone, Copy)]
4949
struct Auto {
50+
/// Auto pong frame handling.
5051
pong: bool,
52+
/// Auto close frame handling.
5153
close: bool,
5254
}
5355

@@ -61,12 +63,38 @@ impl Auto {
6163
}
6264
}
6365

66+
#[derive(Debug, Clone, Copy)]
67+
#[doc(hidden)]
68+
pub struct ConnectionState {
69+
/// If the user sends a close frame, we should not send a close frame back.
70+
///
71+
/// Must be set to `true` if the user sends a close frame.
72+
pub closed: bool,
73+
/// Auto handling of ping/pong and close frames.
74+
auto: Auto,
75+
}
76+
77+
// TODO: add a new write error: ConnectionClosed. closed must be set to true if the user sends a close frame, if the reader read a close frame.
78+
// Then the closed field must be set to true. Every read will then return (None, means connection closed) and every write will return a write error with ConnectionClosed.
79+
// And then add the tests for that. If the user closes the connection or the server closed the connection, and then the user tries to read or write a frame
80+
81+
impl ConnectionState {
82+
#[inline]
83+
#[allow(clippy::new_without_default)]
84+
pub const fn new() -> Self {
85+
Self {
86+
closed: false,
87+
auto: Auto::positive(),
88+
}
89+
}
90+
}
91+
6492
#[derive(Debug)]
6593
#[doc(hidden)]
6694
pub struct WebSocketCore<'buf, RW, Rng> {
6795
pub framed: Framed<'buf, FramesCodec<Rng>, RW>,
6896
pub fragments_state: FragmentsState<'buf>,
69-
auto: Auto,
97+
pub state: ConnectionState,
7098
}
7199

72100
impl<'buf, RW, Rng> WebSocketCore<'buf, RW, Rng> {
@@ -78,7 +106,7 @@ impl<'buf, RW, Rng> WebSocketCore<'buf, RW, Rng> {
78106
Self {
79107
framed,
80108
fragments_state,
81-
auto: Auto::positive(),
109+
state: ConnectionState::new(),
82110
}
83111
}
84112

@@ -142,12 +170,12 @@ impl<'buf, RW, Rng> WebSocketCore<'buf, RW, Rng> {
142170

143171
#[inline]
144172
pub(crate) const fn set_auto_pong(&mut self, auto_pong: bool) {
145-
self.auto.pong = auto_pong;
173+
self.state.auto.pong = auto_pong;
146174
}
147175

148176
#[inline]
149177
pub(crate) const fn set_auto_close(&mut self, auto_close: bool) {
150-
self.auto.close = auto_close;
178+
self.state.auto.close = auto_close;
151179
}
152180

153181
/// Returns reference to the reader/writer.
@@ -401,14 +429,14 @@ impl<'buf, RW, Rng> WebSocketCore<'buf, RW, Rng> {
401429
pub const fn auto(
402430
&self,
403431
) -> impl FnOnce(Frame<'_>) -> Result<OnFrame<'_>, ProtocolError> + 'static {
404-
let auto = self.auto;
432+
let state = self.state;
405433

406434
move |frame| {
407-
if auto.pong && frame.opcode() == OpCode::Ping {
435+
if state.auto.pong && frame.opcode() == OpCode::Ping {
408436
return Ok(OnFrame::Send(Message::Pong(frame.payload())));
409437
}
410438

411-
if auto.close && frame.opcode() == OpCode::Close {
439+
if state.auto.close && frame.opcode() == OpCode::Close && !state.closed {
412440
let close_frame = match Self::extract_close_frame(&frame) {
413441
Ok(close_frame) => close_frame,
414442
Err(err) => return Err(err),
@@ -583,6 +611,7 @@ impl<'buf, RW, Rng> WebSocketCore<'buf, RW, Rng> {
583611
&mut self.framed.core.codec,
584612
&mut self.framed.core.inner,
585613
&mut self.framed.core.state.write,
614+
&mut self.state,
586615
message,
587616
)
588617
.await

0 commit comments

Comments
 (0)