1use std::io::{self, Read, Write, Cursor};
2use std::net::{SocketAddr, Shutdown};
3use std::time::Duration;
4use std::cell::Cell;
5
6use crate::net::{NetworkStream, NetworkConnector, SslClient};
7
8#[derive(Clone, Debug)]
9pub struct MockStream {
10 pub read: Cursor<Vec<u8>>,
11 next_reads: Vec<Vec<u8>>,
12 pub write: Vec<u8>,
13 pub is_closed: bool,
14 pub error_on_write: bool,
15 pub error_on_read: bool,
16 pub read_timeout: Cell<Option<Duration>>,
17 pub write_timeout: Cell<Option<Duration>>,
18 pub id: u64,
19}
20
21impl PartialEq for MockStream {
22 fn eq(&self, other: &MockStream) -> bool {
23 self.read.get_ref() == other.read.get_ref() && self.write == other.write
24 }
25}
26
27impl MockStream {
28 pub fn new() -> MockStream {
29 MockStream::with_input(b"")
30 }
31
32 pub fn with_input(input: &[u8]) -> MockStream {
33 MockStream::with_responses(vec![input])
34 }
35
36 pub fn with_responses(mut responses: Vec<&[u8]>) -> MockStream {
37 MockStream {
38 read: Cursor::new(responses.remove(0).to_vec()),
39 next_reads: responses.into_iter().map(|arr| arr.to_vec()).collect(),
40 write: vec![],
41 is_closed: false,
42 error_on_write: false,
43 error_on_read: false,
44 read_timeout: Cell::new(None),
45 write_timeout: Cell::new(None),
46 id: 0,
47 }
48 }
49}
50
51impl Read for MockStream {
52 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
53 if self.error_on_read {
54 Err(io::Error::new(io::ErrorKind::Other, "mock error"))
55 } else {
56 match self.read.read(buf) {
57 Ok(n) => {
58 if self.read.position() as usize == self.read.get_ref().len() {
59 if self.next_reads.len() > 0 {
60 self.read = Cursor::new(self.next_reads.remove(0));
61 }
62 }
63 Ok(n)
64 }
65 r => r
66 }
67 }
68 }
69}
70
71impl Write for MockStream {
72 fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
73 if self.error_on_write {
74 Err(io::Error::new(io::ErrorKind::Other, "mock error"))
75 } else {
76 Write::write(&mut self.write, msg)
77 }
78 }
79
80 fn flush(&mut self) -> io::Result<()> {
81 Ok(())
82 }
83}
84
85impl NetworkStream for MockStream {
86 fn peer_addr(&mut self) -> io::Result<SocketAddr> {
87 Ok("127.0.0.1:1337".parse().unwrap())
88 }
89
90 fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
91 self.read_timeout.set(dur);
92 Ok(())
93 }
94
95 fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
96 self.write_timeout.set(dur);
97 Ok(())
98 }
99
100 fn close(&mut self, _how: Shutdown) -> io::Result<()> {
101 self.is_closed = true;
102 Ok(())
103 }
104
105 fn set_nonblocking(&self, b: bool) {}
106
107 fn reset_io(&self) {}
108
109 fn wait_io(&self) {}
110}
111
112pub struct MockConnector;
113
114impl NetworkConnector for MockConnector {
115 type Stream = MockStream;
116
117 fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> crate::Result<MockStream> {
118 Ok(MockStream::new())
119 }
120}
121
122macro_rules! mock_connector (
124 ($name:ident {
125 $($url:expr => $res:expr)*
126 }) => (
127
128 struct $name;
129
130 impl $crate::net::NetworkConnector for $name {
131 type Stream = crate::mock::MockStream;
132 fn connect(&self, host: &str, port: u16, scheme: &str)
133 -> $crate::Result<crate::mock::MockStream> {
134 use std::collections::HashMap;
135 debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
136 let mut map = HashMap::new();
137 $(map.insert($url, $res);)*
138
139
140 let key = format!("{}://{}", scheme, host);
141 match map.get(&*key) {
143 Some(&res) => Ok($crate::mock::MockStream::with_input(res.as_bytes())),
144 None => panic!("{:?} doesn't know url {}", stringify!($name), key)
145 }
146 }
147 }
148
149 );
150
151 ($name:ident { $($response:expr),+ }) => (
152 struct $name;
153
154 impl $crate::net::NetworkConnector for $name {
155 type Stream = $crate::mock::MockStream;
156 fn connect(&self, _: &str, _: u16, _: &str)
157 -> $crate::Result<$crate::mock::MockStream> {
158 Ok($crate::mock::MockStream::with_responses(vec![
159 $($response),+
160 ]))
161 }
162 }
163 );
164);
165
166#[derive(Debug, Default)]
167pub struct MockSsl;
168
169impl<T: NetworkStream + Send + Clone> SslClient<T> for MockSsl {
170 type Stream = T;
171 fn wrap_client(&self, stream: T, _host: &str) -> crate::Result<T> {
172 Ok(stream)
173 }
174}