Skip to main content

actix_http/test/
test_seq_buffer.rs

1use std::{
2    cell::{Ref, RefCell},
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/// Async I/O test buffer with ability to incrementally add to the read buffer.
13#[derive(Clone)]
14pub struct TestSeqBuffer(Rc<RefCell<TestSeqInner>>);
15
16impl TestSeqBuffer {
17    /// Create new `TestBuffer` instance with initial read buffer.
18    pub fn new<T>(data: T) -> Self
19    where
20        T: Into<BytesMut>,
21    {
22        Self(Rc::new(RefCell::new(TestSeqInner {
23            read_buf: data.into(),
24            read_closed: false,
25            write_buf: BytesMut::new(),
26            err: None,
27        })))
28    }
29
30    /// Create new empty `TestBuffer` instance.
31    pub fn empty() -> Self {
32        Self::new(BytesMut::new())
33    }
34
35    pub fn read_buf(&self) -> Ref<'_, BytesMut> {
36        Ref::map(self.0.borrow(), |inner| &inner.read_buf)
37    }
38
39    pub fn write_buf(&self) -> Ref<'_, BytesMut> {
40        Ref::map(self.0.borrow(), |inner| &inner.write_buf)
41    }
42
43    pub fn take_write_buf(&self) -> Bytes {
44        self.0.borrow_mut().write_buf.split().freeze()
45    }
46
47    pub fn err(&self) -> Ref<'_, Option<io::Error>> {
48        Ref::map(self.0.borrow(), |inner| &inner.err)
49    }
50
51    /// Add data to read buffer.
52    ///
53    /// # Panics
54    ///
55    /// Panics if called after [`TestSeqBuffer::close_read`] has been called
56    pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
57        let mut inner = self.0.borrow_mut();
58        if inner.read_closed {
59            panic!("Tried to extend the read buffer after calling close_read");
60        }
61
62        inner.read_buf.extend_from_slice(data.as_ref())
63    }
64
65    /// Closes the [`AsyncRead`]/[`Read`] part of this test buffer.
66    ///
67    /// The current data in the buffer will still be returned by a call to read/poll_read, however,
68    /// after the buffer is empty, it will return `Ok(0)` to signify the EOF condition
69    pub fn close_read(&self) {
70        self.0.borrow_mut().read_closed = true;
71    }
72}
73
74pub struct TestSeqInner {
75    read_buf: BytesMut,
76    read_closed: bool,
77    write_buf: BytesMut,
78    err: Option<io::Error>,
79}
80
81impl io::Read for TestSeqBuffer {
82    fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
83        let mut inner = self.0.borrow_mut();
84
85        if inner.read_buf.is_empty() {
86            if let Some(err) = inner.err.take() {
87                Err(err)
88            } else if inner.read_closed {
89                Ok(0)
90            } else {
91                Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
92            }
93        } else {
94            let size = std::cmp::min(inner.read_buf.len(), dst.len());
95            let b = inner.read_buf.split_to(size);
96            dst[..size].copy_from_slice(&b);
97            Ok(size)
98        }
99    }
100}
101
102impl io::Write for TestSeqBuffer {
103    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
104        self.0.borrow_mut().write_buf.extend(buf);
105        Ok(buf.len())
106    }
107
108    fn flush(&mut self) -> io::Result<()> {
109        Ok(())
110    }
111}
112
113impl AsyncRead for TestSeqBuffer {
114    fn poll_read(
115        self: Pin<&mut Self>,
116        _: &mut Context<'_>,
117        buf: &mut ReadBuf<'_>,
118    ) -> Poll<io::Result<()>> {
119        let dst = buf.initialize_unfilled();
120        let r = self.get_mut().read(dst);
121        match r {
122            Ok(n) => {
123                buf.advance(n);
124                Poll::Ready(Ok(()))
125            }
126            Err(err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
127            Err(err) => Poll::Ready(Err(err)),
128        }
129    }
130}
131
132impl AsyncWrite for TestSeqBuffer {
133    fn poll_write(
134        self: Pin<&mut Self>,
135        _: &mut Context<'_>,
136        buf: &[u8],
137    ) -> Poll<io::Result<usize>> {
138        Poll::Ready(self.get_mut().write(buf))
139    }
140
141    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
142        Poll::Ready(Ok(()))
143    }
144
145    fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
146        Poll::Ready(Ok(()))
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use std::{io, task::Context};
153
154    use futures_util::task::noop_waker_ref;
155    use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok};
156
157    use super::*;
158
159    #[test]
160    fn buffer_read_write() {
161        let mut buffer = TestSeqBuffer::new("read");
162        let clone = buffer.clone();
163
164        assert_eq!(buffer.read_buf().as_ref(), b"read");
165        assert!(buffer.err().is_none());
166        buffer.extend_read_buf("!");
167
168        let mut read = [0; 5];
169        assert_eq!(io::Read::read(&mut buffer, &mut read).unwrap(), 5);
170        assert_eq!(&read, b"read!");
171
172        io::Write::write_all(&mut buffer, b"write").unwrap();
173        io::Write::flush(&mut buffer).unwrap();
174        assert_eq!(buffer.write_buf().as_ref(), b"write");
175        assert_eq!(clone.take_write_buf(), Bytes::from_static(b"write"));
176        assert!(buffer.write_buf().is_empty());
177
178        assert_eq!(
179            io::Read::read(&mut buffer, &mut []).unwrap_err().kind(),
180            io::ErrorKind::WouldBlock
181        );
182        buffer.close_read();
183        assert_eq!(io::Read::read(&mut buffer, &mut []).unwrap(), 0);
184
185        let mut error = TestSeqBuffer::empty();
186        error.0.borrow_mut().err = Some(io::Error::other("error"));
187        assert_eq!(
188            io::Read::read(&mut error, &mut []).unwrap_err().to_string(),
189            "error"
190        );
191    }
192
193    #[test]
194    fn buffer_async_io() {
195        let mut cx = Context::from_waker(noop_waker_ref());
196
197        let mut pending = TestSeqBuffer::empty();
198        let mut read = [];
199        let mut read_buf = ReadBuf::new(&mut read);
200        assert_pending!(Pin::new(&mut pending).poll_read(&mut cx, &mut read_buf));
201
202        let mut buffer = TestSeqBuffer::new("read");
203        let mut read = [0; 4];
204        let mut read_buf = ReadBuf::new(&mut read);
205        assert_ready_ok!(Pin::new(&mut buffer).poll_read(&mut cx, &mut read_buf));
206        assert_eq!(read_buf.filled(), b"read");
207
208        let mut error = TestSeqBuffer::empty();
209        error.0.borrow_mut().err = Some(io::Error::other("error"));
210        let mut read = [];
211        let mut read_buf = ReadBuf::new(&mut read);
212        let error = assert_ready_err!(
213            Pin::new(&mut error).poll_read(&mut cx, &mut read_buf),
214            "expected a ready error"
215        );
216        assert_eq!(error.to_string(), "error");
217
218        let mut buffer = TestSeqBuffer::empty();
219        let written = assert_ready_ok!(
220            Pin::new(&mut buffer).poll_write(&mut cx, b"write"),
221            "expected a successful write"
222        );
223        assert_eq!(written, 5);
224        assert_ready_ok!(Pin::new(&mut buffer).poll_flush(&mut cx));
225        assert_ready_ok!(Pin::new(&mut buffer).poll_shutdown(&mut cx));
226    }
227
228    #[test]
229    #[should_panic(expected = "Tried to extend the read buffer")]
230    fn extend_read_buf_after_close_panics() {
231        let mut buffer = TestSeqBuffer::empty();
232        buffer.close_read();
233        buffer.extend_read_buf("data");
234    }
235}