Simplify ReadWrite interface (#530)
Previously, ReadWrite had methods `is_poolable` and `written_bytes`, which were solely for the use of unittests. This replaces `written_bytes` and `TestStream` with a `struct Recorder` that implements `ReadWrite` and allows unittests to access its recorded bytes via an `Arc<Mutex<Vec<u8>>>`. It eliminates `is_poolable`; it's fine to pool a Stream of any kind. The new `Recorder` also has some convenience methods that abstract away boilerplate code from many of our unittests. I got rid of `Stream::from_vec` and `Stream::from_vec_poolable` because they depended on `TestStream`. They've been replaced by `NoopStream` for the pool.rs tests, and `ReadOnlyStream` for constructing `Response`s from `&str` and some test cases.
This commit is contained in:
committed by
GitHub
parent
0cf1f8dbb9
commit
9908c446d6
117
src/stream.rs
117
src/stream.rs
@@ -20,22 +20,12 @@ use crate::unit::Unit;
|
||||
/// Trait for things implementing [std::io::Read] + [std::io::Write]. Used in [TlsConnector].
|
||||
pub trait ReadWrite: Read + Write + Send + Sync + fmt::Debug + 'static {
|
||||
fn socket(&self) -> Option<&TcpStream>;
|
||||
fn is_poolable(&self) -> bool;
|
||||
|
||||
/// The bytes written to the stream as a Vec<u8>. This is used for tests only.
|
||||
#[cfg(test)]
|
||||
fn written_bytes(&self) -> Vec<u8> {
|
||||
panic!("written_bytes on non Test stream");
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadWrite for TcpStream {
|
||||
fn socket(&self) -> Option<&TcpStream> {
|
||||
Some(self)
|
||||
}
|
||||
fn is_poolable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TlsConnector: Send + Sync {
|
||||
@@ -54,51 +44,6 @@ impl<T: ReadWrite + ?Sized> ReadWrite for Box<T> {
|
||||
fn socket(&self) -> Option<&TcpStream> {
|
||||
ReadWrite::socket(self.as_ref())
|
||||
}
|
||||
fn is_poolable(&self) -> bool {
|
||||
ReadWrite::is_poolable(self.as_ref())
|
||||
}
|
||||
#[cfg(test)]
|
||||
fn written_bytes(&self) -> Vec<u8> {
|
||||
ReadWrite::written_bytes(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
struct TestStream(Box<dyn Read + Send + Sync>, Vec<u8>, bool);
|
||||
|
||||
impl ReadWrite for TestStream {
|
||||
fn is_poolable(&self) -> bool {
|
||||
self.2
|
||||
}
|
||||
fn socket(&self) -> Option<&TcpStream> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn written_bytes(&self) -> Vec<u8> {
|
||||
self.1.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for TestStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for TestStream {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.1.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TestStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("TestStream").finish()
|
||||
}
|
||||
}
|
||||
|
||||
// DeadlineStream wraps a stream such that read() will return an error
|
||||
@@ -187,6 +132,37 @@ pub(crate) fn io_err_timeout(error: String) -> io::Error {
|
||||
io::Error::new(io::ErrorKind::TimedOut, error)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadOnlyStream(Cursor<Vec<u8>>);
|
||||
|
||||
impl ReadOnlyStream {
|
||||
pub(crate) fn new(v: Vec<u8>) -> Self {
|
||||
Self(Cursor::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for ReadOnlyStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Write for ReadOnlyStream {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadWrite for ReadOnlyStream {
|
||||
fn socket(&self) -> Option<&std::net::TcpStream> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Stream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.inner.get_ref().socket() {
|
||||
@@ -197,7 +173,7 @@ impl fmt::Debug for Stream {
|
||||
}
|
||||
|
||||
impl Stream {
|
||||
fn new(t: impl ReadWrite) -> Stream {
|
||||
pub(crate) fn new(t: impl ReadWrite) -> Stream {
|
||||
Stream::logged_create(Stream {
|
||||
inner: BufReader::new(Box::new(t)),
|
||||
})
|
||||
@@ -208,23 +184,6 @@ impl Stream {
|
||||
stream
|
||||
}
|
||||
|
||||
pub(crate) fn from_vec(v: Vec<u8>) -> Stream {
|
||||
Stream::logged_create(Stream {
|
||||
inner: BufReader::new(Box::new(TestStream(
|
||||
Box::new(Cursor::new(v)),
|
||||
vec![],
|
||||
false,
|
||||
))),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn from_vec_poolable(v: Vec<u8>) -> Stream {
|
||||
Stream::logged_create(Stream {
|
||||
inner: BufReader::new(Box::new(TestStream(Box::new(Cursor::new(v)), vec![], true))),
|
||||
})
|
||||
}
|
||||
|
||||
fn from_tcp_stream(t: TcpStream) -> Stream {
|
||||
Stream::logged_create(Stream {
|
||||
inner: BufReader::new(Box::new(t)),
|
||||
@@ -270,9 +229,6 @@ impl Stream {
|
||||
None => Ok(false),
|
||||
}
|
||||
}
|
||||
pub fn is_poolable(&self) -> bool {
|
||||
self.inner.get_ref().is_poolable()
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&mut self) -> io::Result<()> {
|
||||
// When we are turning this back into a regular, non-deadline Stream,
|
||||
@@ -296,11 +252,6 @@ impl Stream {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn written_bytes(&self) -> Vec<u8> {
|
||||
self.inner.get_ref().written_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Stream {
|
||||
@@ -693,10 +644,6 @@ mod tests {
|
||||
fn socket(&self) -> Option<&TcpStream> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn is_poolable(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// Test that when a DeadlineStream wraps a Stream, and the user performs a series of
|
||||
|
||||
Reference in New Issue
Block a user