1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use rhai::{Engine, NativeCallContext};
use crate::scenario_executor::utils1::SimpleErr;
use super::{
types::{Handle, StreamRead, StreamSocket, StreamWrite},
utils1::RhResult,
};
//@ Create special testing stream socket that emits user-specified data in user-specified chunks
//@ and verifies that incoming data matches specified samples.
//@
//@ If something is unexpected, Websocat will exit (panic).
//@
//@ Argument is a specially formatted string describing operations, separated by `|` character.
//@
//@ Operations:
//@
//@ * `R` - make the socket return specified chunk of data
//@ * `W` - make the socket wait for incoming data and check if it matches the sample
//@ * `ER` / `EW` - inject read or write error
//@ * `T0` ... `T9` - sleep for some time interval, from small to large.
//@ * `N` - set name of the mock object
//@
//@ Example: `R hello|R world|W ping |R pong|T5|R zero byte \0 other escapes \| \xff \r\n\t|EW`
fn mock_stream_socket(ctx: NativeCallContext, content: String) -> RhResult<Handle<StreamSocket>> {
let mut builder = tokio_io_mock_fork::Builder::new();
if let Err(e) = builder.text_scenario(&content) {
if let Some(c) = e.chararter {
return Err(ctx.err(format!(
"Invalid character `{}` at position {} in state `{:?}` when parsing content of a mock_stream_socket",
std::ascii::escape_default(c), e.position, e.state,
)));
} else {
return Err(ctx.err(format!(
"EOF unexpected in state `{:?}` when parsing content of a mock_stream_socket",
e.state,
)));
}
}
let io = builder.enable_shutdown_checking().build();
let (r, w) = tokio::io::split(io);
Ok(StreamSocket {
read: Some(StreamRead {
reader: Box::pin(r),
prefix: Default::default(),
}),
write: Some(StreamWrite {
writer: Box::pin(w),
}),
close: None,
fd: None,
}
.wrap())
}
pub fn register(engine: &mut Engine) {
engine.register_fn("mock_stream_socket", mock_stream_socket);
}