|
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