| 
1 | 1 | #![warn(rust_2018_idioms)]  | 
2 | 2 | 
 
  | 
 | 3 | +use futures_test::task::{noop_context, panic_waker};  | 
 | 4 | +use futures_util::pin_mut;  | 
 | 5 | +use std::future::Future;  | 
3 | 6 | use std::io;  | 
 | 7 | +use std::task::{Context, Poll};  | 
 | 8 | +use tokio::io::AsyncWrite;  | 
4 | 9 | use tokio::io::{AsyncReadExt, AsyncWriteExt};  | 
5 | 10 | use tokio::time::{Duration, Instant};  | 
 | 11 | +use tokio_test::assert_pending;  | 
6 | 12 | use tokio_test::io::Builder;  | 
7 | 13 | 
 
  | 
8 | 14 | #[tokio::test]  | 
@@ -170,3 +176,84 @@ async fn multiple_wait() {  | 
170 | 176 |         start.elapsed().as_millis()  | 
171 | 177 |     );  | 
172 | 178 | }  | 
 | 179 | + | 
 | 180 | +// No matter which usecase, it doesn't make sense for a read  | 
 | 181 | +// hang forever. However, currently, if there is no sequenced read  | 
 | 182 | +// action, it will hang forever.  | 
 | 183 | +//  | 
 | 184 | +// Since we want be aware of the fixing of this bug,  | 
 | 185 | +// no matter intentionally or unintentionally,  | 
 | 186 | +// we add this test to catch the behavior change.  | 
 | 187 | +//  | 
 | 188 | +// It looks like fixing it is not hard, but not sure the downstream  | 
 | 189 | +// impact, which might be a breaking change due to the  | 
 | 190 | +// `Mock::inner::read_wait` field, so we keep it as is for now.  | 
 | 191 | +//  | 
 | 192 | +// TODO: fix this bug  | 
 | 193 | +#[test]  | 
 | 194 | +fn should_hang_forever_on_read_but_no_sequenced_read_action() {  | 
 | 195 | +    let mut mock = Builder::new()  | 
 | 196 | +        .write_error(io::Error::new(io::ErrorKind::Other, "cruel"))  | 
 | 197 | +        .build();  | 
 | 198 | + | 
 | 199 | +    let mut buf = [0; 1];  | 
 | 200 | +    let read_exact_fut = mock.read(&mut buf);  | 
 | 201 | +    pin_mut!(read_exact_fut);  | 
 | 202 | +    assert_pending!(read_exact_fut.poll(&mut Context::from_waker(&panic_waker())));  | 
 | 203 | +}  | 
 | 204 | + | 
 | 205 | +// The `Mock` is expected to always panic if there is an unconsumed error action,  | 
 | 206 | +// rather than silently ignoring it. However,  | 
 | 207 | +// currently it only panics on unconsumed read/write actions,  | 
 | 208 | +// not on error actions. Fixing this requires a breaking change.  | 
 | 209 | +//  | 
 | 210 | +// This test verifies that it does not panic yet,  | 
 | 211 | +// to prevent accidentally introducing the breaking change prematurely.  | 
 | 212 | +//  | 
 | 213 | +// TODO: fix this bug in the next major release  | 
 | 214 | +#[test]  | 
 | 215 | +fn do_not_panic_unconsumed_error() {  | 
 | 216 | +    let _mock = Builder::new()  | 
 | 217 | +        .read_error(io::Error::new(io::ErrorKind::Other, "cruel"))  | 
 | 218 | +        .build();  | 
 | 219 | +}  | 
 | 220 | + | 
 | 221 | +// The `Mock` must never panic, even if cloned multiple times.  | 
 | 222 | +// However, at present, cloning the builder under certain  | 
 | 223 | +// conditions causes a panic.  | 
 | 224 | +//  | 
 | 225 | +// Fixing this would require making `Mock` non-`Clone`,  | 
 | 226 | +// which is a breaking change.  | 
 | 227 | +//  | 
 | 228 | +// Since we want be aware of the fixing of this bug,  | 
 | 229 | +// no matter intentionally or unintentionally,  | 
 | 230 | +// we add this test to catch the behavior change.  | 
 | 231 | +//  | 
 | 232 | +// TODO: fix this bug in the next major release  | 
 | 233 | +#[tokio::test]  | 
 | 234 | +#[should_panic = "There are no other references.: Custom { kind: Other, error: \"cruel\" }"]  | 
 | 235 | +async fn panic_if_clone_the_build_with_error_action() {  | 
 | 236 | +    let mut builder = Builder::new();  | 
 | 237 | +    builder.write_error(io::Error::new(io::ErrorKind::Other, "cruel"));  | 
 | 238 | +    let mut builder2 = builder.clone();  | 
 | 239 | + | 
 | 240 | +    let mut mock = builder.build();  | 
 | 241 | +    let _mock2 = builder2.build();  | 
 | 242 | + | 
 | 243 | +    // this write_all will panic due to unwrapping the error from `Arc`  | 
 | 244 | +    mock.write_all(b"hello").await.unwrap();  | 
 | 245 | +    unreachable!();  | 
 | 246 | +}  | 
 | 247 | + | 
 | 248 | +#[tokio::test]  | 
 | 249 | +async fn should_not_hang_forever_on_zero_length_write() {  | 
 | 250 | +    let mock = Builder::new().write(b"write").build();  | 
 | 251 | +    pin_mut!(mock);  | 
 | 252 | +    match mock.as_mut().poll_write(&mut noop_context(), &[0u8; 0]) {  | 
 | 253 | +        // drain the remaining write action to avoid panic at drop of the `mock`  | 
 | 254 | +        Poll::Ready(Ok(0)) => mock.write_all(b"write").await.unwrap(),  | 
 | 255 | +        Poll::Ready(Ok(n)) => panic!("expected to write 0 bytes, wrote {n} bytes instead"),  | 
 | 256 | +        Poll::Ready(Err(e)) => panic!("expected to write 0 bytes, got error {e} instead"),  | 
 | 257 | +        Poll::Pending => panic!("expected to write 0 bytes immediately, but pending instead"),  | 
 | 258 | +    }  | 
 | 259 | +}  | 
0 commit comments