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
106pub struct MockConnector;
107
108impl NetworkConnector for MockConnector {
109 type Stream = MockStream;
110
111 fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> crate::Result<MockStream> {
112 Ok(MockStream::new())
113 }
114}
115
116macro_rules! mock_connector (
118 ($name:ident {
119 $($url:expr => $res:expr)*
120 }) => (
121
122 struct $name;
123
124 impl $crate::net::NetworkConnector for $name {
125 type Stream = crate::mock::MockStream;
126 fn connect(&self, host: &str, port: u16, scheme: &str)
127 -> $crate::Result<crate::mock::MockStream> {
128 use std::collections::HashMap;
129 debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
130 let mut map = HashMap::new();
131 $(map.insert($url, $res);)*
132
133
134 let key = format!("{}://{}", scheme, host);
135 match map.get(&*key) {
137 Some(&res) => Ok($crate::mock::MockStream::with_input(res.as_bytes())),
138 None => panic!("{:?} doesn't know url {}", stringify!($name), key)
139 }
140 }
141 }
142
143 );
144
145 ($name:ident { $($response:expr),+ }) => (
146 struct $name;
147
148 impl $crate::net::NetworkConnector for $name {
149 type Stream = $crate::mock::MockStream;
150 fn connect(&self, _: &str, _: u16, _: &str)
151 -> $crate::Result<$crate::mock::MockStream> {
152 Ok($crate::mock::MockStream::with_responses(vec![
153 $($response),+
154 ]))
155 }
156 }
157 );
158);
159
160#[derive(Debug, Default)]
161pub struct MockSsl;
162
163impl<T: NetworkStream + Send + Clone> SslClient<T> for MockSsl {
164 type Stream = T;
165 fn wrap_client(&self, stream: T, _host: &str) -> crate::Result<T> {
166 Ok(stream)
167 }
168}