actix_http/test/
test_buffer.rs1use std::{
2 cell::{Ref, RefCell, RefMut},
3 io::{self, Read, Write},
4 pin::Pin,
5 rc::Rc,
6 task::{Context, Poll},
7};
8
9use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
10use bytes::{Bytes, BytesMut};
11
12#[derive(Debug)]
14pub struct TestBuffer {
15 pub read_buf: Rc<RefCell<BytesMut>>,
16 pub write_buf: Rc<RefCell<BytesMut>>,
17 pub err: Option<Rc<io::Error>>,
18}
19
20impl TestBuffer {
21 pub fn new<T>(data: T) -> Self
23 where
24 T: Into<BytesMut>,
25 {
26 Self {
27 read_buf: Rc::new(RefCell::new(data.into())),
28 write_buf: Rc::new(RefCell::new(BytesMut::new())),
29 err: None,
30 }
31 }
32
33 #[allow(dead_code)]
35 pub(crate) fn clone(&self) -> Self {
36 Self {
37 read_buf: Rc::clone(&self.read_buf),
38 write_buf: Rc::clone(&self.write_buf),
39 err: self.err.clone(),
40 }
41 }
42
43 pub fn empty() -> Self {
45 Self::new("")
46 }
47
48 #[allow(dead_code)]
49 pub(crate) fn read_buf_slice(&self) -> Ref<'_, [u8]> {
50 Ref::map(self.read_buf.borrow(), |b| b.as_ref())
51 }
52
53 #[allow(dead_code)]
54 pub(crate) fn read_buf_slice_mut(&self) -> RefMut<'_, [u8]> {
55 RefMut::map(self.read_buf.borrow_mut(), |b| b.as_mut())
56 }
57
58 #[allow(dead_code)]
59 pub(crate) fn write_buf_slice(&self) -> Ref<'_, [u8]> {
60 Ref::map(self.write_buf.borrow(), |b| b.as_ref())
61 }
62
63 #[allow(dead_code)]
64 pub(crate) fn write_buf_slice_mut(&self) -> RefMut<'_, [u8]> {
65 RefMut::map(self.write_buf.borrow_mut(), |b| b.as_mut())
66 }
67
68 #[allow(dead_code)]
69 pub(crate) fn take_write_buf(&self) -> Bytes {
70 self.write_buf.borrow_mut().split().freeze()
71 }
72
73 pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
75 self.read_buf.borrow_mut().extend_from_slice(data.as_ref())
76 }
77}
78
79impl io::Read for TestBuffer {
80 fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
81 if self.read_buf.borrow().is_empty() {
82 if self.err.is_some() {
83 Err(Rc::try_unwrap(self.err.take().unwrap()).unwrap())
84 } else {
85 Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
86 }
87 } else {
88 let size = std::cmp::min(self.read_buf.borrow().len(), dst.len());
89 let b = self.read_buf.borrow_mut().split_to(size);
90 dst[..size].copy_from_slice(&b);
91 Ok(size)
92 }
93 }
94}
95
96impl io::Write for TestBuffer {
97 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
98 self.write_buf.borrow_mut().extend(buf);
99 Ok(buf.len())
100 }
101
102 fn flush(&mut self) -> io::Result<()> {
103 Ok(())
104 }
105}
106
107impl AsyncRead for TestBuffer {
108 fn poll_read(
109 self: Pin<&mut Self>,
110 _: &mut Context<'_>,
111 buf: &mut ReadBuf<'_>,
112 ) -> Poll<io::Result<()>> {
113 let dst = buf.initialize_unfilled();
114 match self.get_mut().read(dst) {
115 Ok(n) => {
116 buf.advance(n);
117 Poll::Ready(Ok(()))
118 }
119 Err(err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
120 Err(err) => Poll::Ready(Err(err)),
121 }
122 }
123}
124
125impl AsyncWrite for TestBuffer {
126 fn poll_write(
127 self: Pin<&mut Self>,
128 _: &mut Context<'_>,
129 buf: &[u8],
130 ) -> Poll<io::Result<usize>> {
131 Poll::Ready(self.get_mut().write(buf))
132 }
133
134 fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
135 Poll::Ready(Ok(()))
136 }
137
138 fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
139 Poll::Ready(Ok(()))
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use std::{io, task::Context};
146
147 use futures_util::task::noop_waker_ref;
148 use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok};
149
150 use super::*;
151
152 #[test]
153 fn buffer_read_write() {
154 let mut buffer = TestBuffer::new("read");
155 let clone = buffer.clone();
156
157 assert_eq!(&*buffer.read_buf_slice(), b"read");
158 buffer.read_buf_slice_mut()[0] = b'R';
159 assert_eq!(&*buffer.read_buf_slice(), b"Read");
160
161 io::Write::write_all(&mut buffer, b"write").unwrap();
162 assert_eq!(&*buffer.write_buf_slice(), b"write");
163 buffer.write_buf_slice_mut()[0] = b'W';
164 assert_eq!(&*buffer.write_buf_slice(), b"Write");
165 io::Write::flush(&mut buffer).unwrap();
166 assert_eq!(clone.take_write_buf(), Bytes::from_static(b"Write"));
167 assert!(buffer.write_buf_slice().is_empty());
168
169 buffer.extend_read_buf("!");
170 let mut read = [0; 5];
171 assert_eq!(io::Read::read(&mut buffer, &mut read).unwrap(), 5);
172 assert_eq!(&read, b"Read!");
173 assert_eq!(
174 io::Read::read(&mut buffer, &mut read).unwrap_err().kind(),
175 io::ErrorKind::WouldBlock
176 );
177
178 let mut empty = TestBuffer::empty();
179 empty.err = Some(Rc::new(io::Error::other("error")));
180 assert_eq!(
181 io::Read::read(&mut empty, &mut []).unwrap_err().to_string(),
182 "error"
183 );
184 }
185
186 #[test]
187 fn buffer_async_io() {
188 let mut cx = Context::from_waker(noop_waker_ref());
189 let mut buffer = TestBuffer::new("read");
190 let mut read = [0; 4];
191 let mut read_buf = ReadBuf::new(&mut read);
192
193 assert_ready_ok!(Pin::new(&mut buffer).poll_read(&mut cx, &mut read_buf));
194 assert_eq!(read_buf.filled(), b"read");
195
196 let mut empty = TestBuffer::empty();
197 let mut read = [];
198 let mut read_buf = ReadBuf::new(&mut read);
199 assert_pending!(Pin::new(&mut empty).poll_read(&mut cx, &mut read_buf));
200
201 let mut error = TestBuffer::empty();
202 error.err = Some(Rc::new(io::Error::other("error")));
203 let mut read = [];
204 let mut read_buf = ReadBuf::new(&mut read);
205 let error = assert_ready_err!(
206 Pin::new(&mut error).poll_read(&mut cx, &mut read_buf),
207 "expected a ready error"
208 );
209 assert_eq!(error.to_string(), "error");
210
211 let mut buffer = TestBuffer::empty();
212 let written = assert_ready_ok!(
213 Pin::new(&mut buffer).poll_write(&mut cx, b"write"),
214 "expected a successful write"
215 );
216 assert_eq!(written, 5);
217 assert_ready_ok!(Pin::new(&mut buffer).poll_flush(&mut cx));
218 assert_ready_ok!(Pin::new(&mut buffer).poll_shutdown(&mut cx));
219 }
220}