use super::*; use crate::{ fs::mocks::*, io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}, }; use mockall::{predicate::eq, Sequence}; use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok, task}; const HELLO: &[u8] = b"hello world..."; const FOO: &[u8] = b"foo bar baz..."; #[test] fn open_read() { let mut file = MockFile::default(); file.expect_inner_read().once().returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); let mut buf = [0; 1024]; let mut t = task::spawn(file.read(&mut buf)); assert_eq!(0, pool::len()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); let n = assert_ready_ok!(t.poll()); assert_eq!(n, HELLO.len()); assert_eq!(&buf[..n], HELLO); } #[test] fn read_twice_before_dispatch() { let mut file = MockFile::default(); file.expect_inner_read().once().returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); let mut buf = [0; 1024]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); assert_pending!(t.poll()); assert_eq!(pool::len(), 1); pool::run_one(); assert!(t.is_woken()); let n = assert_ready_ok!(t.poll()); assert_eq!(&buf[..n], HELLO); } #[test] fn read_with_smaller_buf() { let mut file = MockFile::default(); file.expect_inner_read().once().returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); { let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); } pool::run_one(); { let mut buf = [0; 4]; let mut t = task::spawn(file.read(&mut buf)); let n = assert_ready_ok!(t.poll()); assert_eq!(n, 4); assert_eq!(&buf[..], &HELLO[..n]); } // Calling again immediately succeeds with the rest of the buffer let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); let n = assert_ready_ok!(t.poll()); assert_eq!(n, 10); assert_eq!(&buf[..n], &HELLO[4..]); assert_eq!(0, pool::len()); } #[test] fn read_with_bigger_buf() { let mut seq = Sequence::new(); let mut file = MockFile::default(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..4].copy_from_slice(&HELLO[..4]); Ok(4) }); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len() - 4].copy_from_slice(&HELLO[4..]); Ok(HELLO.len() - 4) }); let mut file = File::from_std(file); { let mut buf = [0; 4]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); } pool::run_one(); { let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); let n = assert_ready_ok!(t.poll()); assert_eq!(n, 4); assert_eq!(&buf[..n], &HELLO[..n]); } // Calling again immediately succeeds with the rest of the buffer let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); let n = assert_ready_ok!(t.poll()); assert_eq!(n, 10); assert_eq!(&buf[..n], &HELLO[4..]); assert_eq!(0, pool::len()); } #[test] fn read_err_then_read_success() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|_| Err(io::ErrorKind::Other.into())); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); { let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); assert_ready_err!(t.poll()); } { let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let n = assert_ready_ok!(t.poll()); assert_eq!(n, HELLO.len()); assert_eq!(&buf[..n], HELLO); } } #[test] fn open_write() { let mut file = MockFile::default(); file.expect_inner_write() .once() .with(eq(HELLO)) .returning(|buf| Ok(buf.len())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_eq!(0, pool::len()); assert_ready_ok!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(!t.is_woken()); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); } #[test] fn flush_while_idle() { let file = MockFile::default(); let mut file = File::from_std(file); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); } #[test] fn read_with_buffer_larger_than_max() { // Chunks let chunk_a = 16 * 1024; let chunk_b = chunk_a * 2; let chunk_c = chunk_a * 3; let chunk_d = chunk_a * 4; assert_eq!(chunk_d / 1024, 64); let mut data = vec![]; for i in 0..(chunk_d - 1) { data.push((i % 151) as u8); } let data = Arc::new(data); let d0 = data.clone(); let d1 = data.clone(); let d2 = data.clone(); let d3 = data.clone(); let mut seq = Sequence::new(); let mut file = MockFile::default(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(move |buf| { buf[0..chunk_a].copy_from_slice(&d0[0..chunk_a]); Ok(chunk_a) }); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(move |buf| { buf[..chunk_a].copy_from_slice(&d1[chunk_a..chunk_b]); Ok(chunk_b - chunk_a) }); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(move |buf| { buf[..chunk_a].copy_from_slice(&d2[chunk_b..chunk_c]); Ok(chunk_c - chunk_b) }); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(move |buf| { buf[..chunk_a - 1].copy_from_slice(&d3[chunk_c..]); Ok(chunk_a - 1) }); let mut file = File::from_std(file); let mut actual = vec![0; chunk_d]; let mut pos = 0; while pos < data.len() { let mut t = task::spawn(file.read(&mut actual[pos..])); assert_pending!(t.poll()); pool::run_one(); assert!(t.is_woken()); let n = assert_ready_ok!(t.poll()); assert!(n <= chunk_a); pos += n; } assert_eq!(&data[..], &actual[..data.len()]); } #[test] fn write_with_buffer_larger_than_max() { // Chunks let chunk_a = 16 * 1024; let chunk_b = chunk_a * 2; let chunk_c = chunk_a * 3; let chunk_d = chunk_a * 4; assert_eq!(chunk_d / 1024, 64); let mut data = vec![]; for i in 0..(chunk_d - 1) { data.push((i % 151) as u8); } let data = Arc::new(data); let d0 = data.clone(); let d1 = data.clone(); let d2 = data.clone(); let d3 = data.clone(); let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .withf(move |buf| buf == &d0[0..chunk_a]) .returning(|buf| Ok(buf.len())); file.expect_inner_write() .once() .in_sequence(&mut seq) .withf(move |buf| buf == &d1[chunk_a..chunk_b]) .returning(|buf| Ok(buf.len())); file.expect_inner_write() .once() .in_sequence(&mut seq) .withf(move |buf| buf == &d2[chunk_b..chunk_c]) .returning(|buf| Ok(buf.len())); file.expect_inner_write() .once() .in_sequence(&mut seq) .withf(move |buf| buf == &d3[chunk_c..chunk_d - 1]) .returning(|buf| Ok(buf.len())); let mut file = File::from_std(file); let mut rem = &data[..]; let mut first = true; while !rem.is_empty() { let mut task = task::spawn(file.write(rem)); if !first { assert_pending!(task.poll()); pool::run_one(); assert!(task.is_woken()); } first = false; let n = assert_ready_ok!(task.poll()); rem = &rem[n..]; } pool::run_one(); } #[test] fn write_twice_before_dispatch() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|buf| Ok(buf.len())); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(FOO)) .returning(|buf| Ok(buf.len())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.write(FOO)); assert_pending!(t.poll()); assert_eq!(pool::len(), 1); pool::run_one(); assert!(t.is_woken()); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.flush()); assert_pending!(t.poll()); assert_eq!(pool::len(), 1); pool::run_one(); assert!(t.is_woken()); assert_ready_ok!(t.poll()); } #[test] fn incomplete_read_followed_by_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); file.expect_inner_seek() .once() .with(eq(SeekFrom::Current(-(HELLO.len() as i64)))) .in_sequence(&mut seq) .returning(|_| Ok(0)); file.expect_inner_write() .once() .with(eq(FOO)) .returning(|_| Ok(FOO.len())); let mut file = File::from_std(file); let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let mut t = task::spawn(file.write(FOO)); assert_ready_ok!(t.poll()); assert_eq!(pool::len(), 1); pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); } #[test] fn incomplete_partial_read_followed_by_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); file.expect_inner_seek() .once() .in_sequence(&mut seq) .with(eq(SeekFrom::Current(-10))) .returning(|_| Ok(0)); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(FOO)) .returning(|_| Ok(FOO.len())); let mut file = File::from_std(file); let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let mut buf = [0; 4]; let mut t = task::spawn(file.read(&mut buf)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.write(FOO)); assert_ready_ok!(t.poll()); assert_eq!(pool::len(), 1); pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); } #[test] fn incomplete_read_followed_by_flush() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); file.expect_inner_seek() .once() .in_sequence(&mut seq) .with(eq(SeekFrom::Current(-(HELLO.len() as i64)))) .returning(|_| Ok(0)); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(FOO)) .returning(|_| Ok(FOO.len())); let mut file = File::from_std(file); let mut buf = [0; 32]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.write(FOO)); assert_ready_ok!(t.poll()); pool::run_one(); } #[test] fn incomplete_flush_followed_by_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|_| Ok(HELLO.len())); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(FOO)) .returning(|_| Ok(FOO.len())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); let n = assert_ready_ok!(t.poll()); assert_eq!(n, HELLO.len()); let mut t = task::spawn(file.flush()); assert_pending!(t.poll()); // TODO: Move under write pool::run_one(); let mut t = task::spawn(file.write(FOO)); assert_ready_ok!(t.poll()); pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_ok!(t.poll()); } #[test] fn read_err() { let mut file = MockFile::default(); file.expect_inner_read() .once() .returning(|_| Err(io::ErrorKind::Other.into())); let mut file = File::from_std(file); let mut buf = [0; 1024]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); assert!(t.is_woken()); assert_ready_err!(t.poll()); } #[test] fn write_write_err() { let mut file = MockFile::default(); file.expect_inner_write() .once() .returning(|_| Err(io::ErrorKind::Other.into())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); pool::run_one(); let mut t = task::spawn(file.write(FOO)); assert_ready_err!(t.poll()); } #[test] fn write_read_write_err() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .returning(|_| Err(io::ErrorKind::Other.into())); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); pool::run_one(); let mut buf = [0; 1024]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let mut t = task::spawn(file.write(FOO)); assert_ready_err!(t.poll()); } #[test] fn write_read_flush_err() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .returning(|_| Err(io::ErrorKind::Other.into())); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); pool::run_one(); let mut buf = [0; 1024]; let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_err!(t.poll()); } #[test] fn write_seek_write_err() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .returning(|_| Err(io::ErrorKind::Other.into())); file.expect_inner_seek() .once() .with(eq(SeekFrom::Start(0))) .in_sequence(&mut seq) .returning(|_| Ok(0)); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); pool::run_one(); { let mut t = task::spawn(file.seek(SeekFrom::Start(0))); assert_pending!(t.poll()); } pool::run_one(); let mut t = task::spawn(file.write(FOO)); assert_ready_err!(t.poll()); } #[test] fn write_seek_flush_err() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .returning(|_| Err(io::ErrorKind::Other.into())); file.expect_inner_seek() .once() .with(eq(SeekFrom::Start(0))) .in_sequence(&mut seq) .returning(|_| Ok(0)); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); pool::run_one(); { let mut t = task::spawn(file.seek(SeekFrom::Start(0))); assert_pending!(t.poll()); } pool::run_one(); let mut t = task::spawn(file.flush()); assert_ready_err!(t.poll()); } #[test] fn sync_all_ordered_after_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|_| Ok(HELLO.len())); file.expect_sync_all().once().returning(|| Ok(())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.sync_all()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_ready_ok!(t.poll()); } #[test] fn sync_all_err_ordered_after_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|_| Ok(HELLO.len())); file.expect_sync_all() .once() .returning(|| Err(io::ErrorKind::Other.into())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.sync_all()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_ready_err!(t.poll()); } #[test] fn sync_data_ordered_after_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|_| Ok(HELLO.len())); file.expect_sync_data().once().returning(|| Ok(())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.sync_data()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_ready_ok!(t.poll()); } #[test] fn sync_data_err_ordered_after_write() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_write() .once() .in_sequence(&mut seq) .with(eq(HELLO)) .returning(|_| Ok(HELLO.len())); file.expect_sync_data() .once() .returning(|| Err(io::ErrorKind::Other.into())); let mut file = File::from_std(file); let mut t = task::spawn(file.write(HELLO)); assert_ready_ok!(t.poll()); let mut t = task::spawn(file.sync_data()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_pending!(t.poll()); assert_eq!(1, pool::len()); pool::run_one(); assert!(t.is_woken()); assert_ready_err!(t.poll()); } #[test] fn open_set_len_ok() { let mut file = MockFile::default(); file.expect_set_len().with(eq(123)).returning(|_| Ok(())); let file = File::from_std(file); let mut t = task::spawn(file.set_len(123)); assert_pending!(t.poll()); pool::run_one(); assert!(t.is_woken()); assert_ready_ok!(t.poll()); } #[test] fn open_set_len_err() { let mut file = MockFile::default(); file.expect_set_len() .with(eq(123)) .returning(|_| Err(io::ErrorKind::Other.into())); let file = File::from_std(file); let mut t = task::spawn(file.set_len(123)); assert_pending!(t.poll()); pool::run_one(); assert!(t.is_woken()); assert_ready_err!(t.poll()); } #[test] fn partial_read_set_len_ok() { let mut file = MockFile::default(); let mut seq = Sequence::new(); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..HELLO.len()].copy_from_slice(HELLO); Ok(HELLO.len()) }); file.expect_inner_seek() .once() .with(eq(SeekFrom::Current(-(HELLO.len() as i64)))) .in_sequence(&mut seq) .returning(|_| Ok(0)); file.expect_set_len() .once() .in_sequence(&mut seq) .with(eq(123)) .returning(|_| Ok(())); file.expect_inner_read() .once() .in_sequence(&mut seq) .returning(|buf| { buf[0..FOO.len()].copy_from_slice(FOO); Ok(FOO.len()) }); let mut buf = [0; 32]; let mut file = File::from_std(file); { let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); } pool::run_one(); { let mut t = task::spawn(file.set_len(123)); assert_pending!(t.poll()); pool::run_one(); assert_ready_ok!(t.poll()); } let mut t = task::spawn(file.read(&mut buf)); assert_pending!(t.poll()); pool::run_one(); let n = assert_ready_ok!(t.poll()); assert_eq!(n, FOO.len()); assert_eq!(&buf[..n], FOO); }