This is an automated email from the ASF dual-hosted git repository. xuanwo pushed a commit to branch refactor-tests in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
commit f3cbe2577e1fdadd931b2f58ce2543332be6f6d0 Author: Xuanwo <[email protected]> AuthorDate: Tue Jan 2 20:03:21 2024 +0800 Refactor tests Signed-off-by: Xuanwo <[email protected]> --- core/tests/behavior/append.rs | 28 +--- core/tests/behavior/blocking_append.rs | 28 +--- core/tests/behavior/blocking_write.rs | 247 ---------------------------- core/tests/behavior/main.rs | 1 + core/tests/behavior/utils.rs | 261 ----------------------------- core/tests/behavior/write.rs | 292 --------------------------------- 6 files changed, 3 insertions(+), 854 deletions(-) diff --git a/core/tests/behavior/append.rs b/core/tests/behavior/append.rs index 5f535e4c11..85d923dd43 100644 --- a/core/tests/behavior/append.rs +++ b/core/tests/behavior/append.rs @@ -39,8 +39,7 @@ pub fn behavior_append_tests(op: &Operator) -> Vec<Trial> { test_append_with_cache_control, test_append_with_content_type, test_append_with_content_disposition, - test_appender_futures_copy, - test_fuzz_appender + test_appender_futures_copy ) } @@ -196,28 +195,3 @@ pub async fn test_appender_futures_copy(op: Operator) -> Result<()> { op.delete(&path).await.expect("delete must succeed"); Ok(()) } - -/// Test for fuzzing appender. -pub async fn test_fuzz_appender(op: Operator) -> Result<()> { - let path = uuid::Uuid::new_v4().to_string(); - - let mut fuzzer = ObjectWriterFuzzer::new(&path, None); - - let mut a = op.writer_with(&path).append(true).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectWriterAction::Write(bs) => { - a.write(bs).await?; - } - } - } - a.close().await?; - - let content = op.read(&path).await?; - fuzzer.check(&content); - - op.delete(&path).await.expect("delete file must success"); - - Ok(()) -} diff --git a/core/tests/behavior/blocking_append.rs b/core/tests/behavior/blocking_append.rs index 8161f825a3..fae3448d3d 100644 --- a/core/tests/behavior/blocking_append.rs +++ b/core/tests/behavior/blocking_append.rs @@ -39,8 +39,7 @@ pub fn behavior_blocking_append_tests(op: &Operator) -> Vec<Trial> { test_blocking_append_with_cache_control, test_blocking_append_with_content_type, test_blocking_append_with_content_disposition, - test_blocking_appender_std_copy, - test_blocking_fuzz_appender + test_blocking_appender_std_copy ) } @@ -193,28 +192,3 @@ pub fn test_blocking_appender_std_copy(op: BlockingOperator) -> Result<()> { op.delete(&path).expect("delete must succeed"); Ok(()) } - -/// Test for fuzzing appender. -pub fn test_blocking_fuzz_appender(op: BlockingOperator) -> Result<()> { - let path = uuid::Uuid::new_v4().to_string(); - - let mut fuzzer = ObjectWriterFuzzer::new(&path, None); - - let mut a = op.writer_with(&path).append(true).call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectWriterAction::Write(bs) => { - a.write(bs)?; - } - } - } - a.close()?; - - let content = op.read(&path)?; - fuzzer.check(&content); - - op.delete(&path).expect("delete file must success"); - - Ok(()) -} diff --git a/core/tests/behavior/blocking_write.rs b/core/tests/behavior/blocking_write.rs index 3b890655ab..3b01593ed7 100644 --- a/core/tests/behavior/blocking_write.rs +++ b/core/tests/behavior/blocking_write.rs @@ -15,9 +15,6 @@ // specific language governing permissions and limitations // under the License. -use std::io::Read; -use std::io::Seek; - use anyhow::Result; use log::debug; use log::warn; @@ -48,12 +45,6 @@ pub fn behavior_blocking_write_tests(op: &Operator) -> Vec<Trial> { test_blocking_read_range, test_blocking_read_large_range, test_blocking_read_not_exist, - test_blocking_fuzz_range_reader, - test_blocking_fuzz_range_reader_with_buffer, - test_blocking_fuzz_offset_reader, - test_blocking_fuzz_offset_reader_with_buffer, - test_blocking_fuzz_part_reader, - test_blocking_fuzz_part_reader_with_buffer, test_blocking_delete_file, test_blocking_remove_one_file ) @@ -310,244 +301,6 @@ pub fn test_blocking_read_not_exist(op: BlockingOperator) -> Result<()> { Ok(()) } -pub fn test_blocking_fuzz_range_reader(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op - .reader_with(&path) - .range(0..content.len() as u64) - .call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - -pub fn test_blocking_fuzz_range_reader_with_buffer(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op - .reader_with(&path) - .range(0..content.len() as u64) - .buffer(4096) - .call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - -pub fn test_blocking_fuzz_offset_reader(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op.reader_with(&path).range(0..).call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - -pub fn test_blocking_fuzz_offset_reader_with_buffer(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op.reader_with(&path).range(0..).buffer(4096).call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - -pub fn test_blocking_fuzz_part_reader(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, size) = gen_bytes(op.info().full_capability()); - let (offset, length) = gen_offset_length(size); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content, offset as usize, length as usize); - let mut o = op - .reader_with(&path) - .range(offset..offset + length) - .call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - -pub fn test_blocking_fuzz_part_reader_with_buffer(op: BlockingOperator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, size) = gen_bytes(op.info().full_capability()); - let (offset, length) = gen_offset_length(size); - - op.write(&path, content.clone()) - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content, offset as usize, length as usize); - let mut o = op - .reader_with(&path) - .range(offset..offset + length) - .buffer(4096) - .call()?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs)?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos)?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o.next().map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).expect("delete must succeed"); - Ok(()) -} - // Delete existing file should succeed. pub fn test_blocking_delete_file(op: BlockingOperator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); diff --git a/core/tests/behavior/main.rs b/core/tests/behavior/main.rs index a47d17c6ef..dab9c9632f 100644 --- a/core/tests/behavior/main.rs +++ b/core/tests/behavior/main.rs @@ -54,6 +54,7 @@ use blocking_list::behavior_blocking_list_tests; use blocking_read_only::behavior_blocking_read_only_tests; use blocking_rename::behavior_blocking_rename_tests; use blocking_write::behavior_blocking_write_tests; + // External dependencies use libtest_mimic::Arguments; use libtest_mimic::Trial; diff --git a/core/tests/behavior/utils.rs b/core/tests/behavior/utils.rs index 0bb0ed607f..00384747d3 100644 --- a/core/tests/behavior/utils.rs +++ b/core/tests/behavior/utils.rs @@ -15,23 +15,15 @@ // specific language governing permissions and limitations // under the License. -use std::fmt; -use std::fmt::Debug; -use std::fmt::Formatter; -use std::io::SeekFrom; use std::usize; -use bytes::Bytes; use futures::Future; use libtest_mimic::Failed; use libtest_mimic::Trial; -use log::debug; use opendal::raw::tests::TEST_RUNTIME; use opendal::*; use rand::distributions::uniform::SampleRange; use rand::prelude::*; -use sha2::Digest; -use sha2::Sha256; pub fn gen_bytes_with_range(range: impl SampleRange<usize>) -> (Vec<u8>, usize) { let mut rng = thread_rng(); @@ -109,256 +101,3 @@ macro_rules! blocking_trials { )*] }; } - -/// ObjectReaderFuzzer is the fuzzer for object readers. -/// -/// We will generate random read/seek/next operations to operate on object -/// reader to check if the output is expected. -/// -/// # TODO -/// -/// This fuzzer only generate valid operations. -/// -/// In the future, we need to generate invalid operations to check if we -/// handled correctly. -pub struct ObjectReaderFuzzer { - name: String, - bs: Vec<u8>, - - offset: usize, - size: usize, - cur: usize, - rng: ThreadRng, - actions: Vec<ObjectReaderAction>, -} - -#[derive(Debug, Clone, Copy)] -pub enum ObjectReaderAction { - Read(usize), - Seek(SeekFrom), - Next, -} - -impl ObjectReaderFuzzer { - /// Create a new fuzzer. - pub fn new(name: &str, bs: Vec<u8>, offset: usize, size: usize) -> Self { - Self { - name: name.to_string(), - bs, - - offset, - size, - cur: 0, - - rng: thread_rng(), - actions: vec![], - } - } - - /// Generate a new action. - pub fn fuzz(&mut self) -> ObjectReaderAction { - let action = match self.rng.gen_range(0..3) { - // Generate a read action. - 0 => { - if self.cur >= self.size { - ObjectReaderAction::Read(0) - } else { - let size = self.rng.gen_range(0..self.size - self.cur); - ObjectReaderAction::Read(size) - } - } - // Generate a seek action. - 1 => match self.rng.gen_range(0..3) { - // Generate a SeekFrom::Start action. - 0 => { - let offset = self.rng.gen_range(0..self.size as u64); - ObjectReaderAction::Seek(SeekFrom::Start(offset)) - } - // Generate a SeekFrom::End action. - 1 => { - let offset = self.rng.gen_range(-(self.size as i64)..0); - ObjectReaderAction::Seek(SeekFrom::End(offset)) - } - // Generate a SeekFrom::Current action. - 2 => { - let offset = self - .rng - .gen_range(-(self.cur as i64)..(self.size - self.cur) as i64); - ObjectReaderAction::Seek(SeekFrom::Current(offset)) - } - _ => unreachable!(), - }, - // Generate a next action. - 2 => ObjectReaderAction::Next, - _ => unreachable!(), - }; - - debug!("{} perform fuzz action: {:?}", self.name, action); - self.actions.push(action); - - action - } - - /// Check if read operation is expected. - pub fn check_read(&mut self, output_n: usize, output_bs: &[u8]) { - assert!( - self.cur + output_n <= self.size, - "check read failed: output bs is larger than remaining bs: actions: {:?}", - self.actions - ); - - let current_size = self.offset + self.cur; - let expected_bs = &self.bs[current_size..current_size + output_n]; - - assert_eq!( - format!("{:x}", Sha256::digest(output_bs)), - format!("{:x}", Sha256::digest(expected_bs)), - "check read failed: output bs is different with expected bs, actions: {:?}", - self.actions, - ); - - // Update current pos. - self.cur += output_n; - } - - /// Check if seek operation is expected. - pub fn check_seek(&mut self, input_pos: SeekFrom, output_pos: u64) { - let expected_pos = match input_pos { - SeekFrom::Start(offset) => offset as i64, - SeekFrom::End(offset) => self.size as i64 + offset, - SeekFrom::Current(offset) => self.cur as i64 + offset, - }; - - assert_eq!( - output_pos, expected_pos as u64, - "check seek failed: output pos is different with expected pos, actions: {:?}", - self.actions - ); - - // Update current pos. - self.cur = expected_pos as usize; - } - - /// Check if next operation is expected. - pub fn check_next(&mut self, output_bs: Option<Bytes>) { - if let Some(output_bs) = output_bs { - assert!( - self.cur + output_bs.len() <= self.size, - "check next failed: output bs is larger than remaining bs, actions: {:?}", - self.actions - ); - - let current_size = self.offset + self.cur; - let expected_bs = &self.bs[current_size..current_size + output_bs.len()]; - - assert_eq!( - format!("{:x}", Sha256::digest(&output_bs)), - format!("{:x}", Sha256::digest(expected_bs)), - "check next failed: output bs is different with expected bs, actions: {:?}", - self.actions - ); - - // Update current pos. - self.cur += output_bs.len(); - } else { - assert!( - self.cur >= self.size, - "check next failed: output bs is None, we still have bytes to read, actions: {:?}", - self.actions - ) - } - } -} - -/// ObjectWriterFuzzer is the fuzzer for object writer. -/// -/// We will generate random write operations to operate on object -/// write to check if the output is expected. -/// -/// # TODO -/// -/// This fuzzer only generate valid operations. -/// -/// In the future, we need to generate invalid operations to check if we -/// handled correctly. -pub struct ObjectWriterFuzzer { - name: String, - bs: Vec<u8>, - - size: Option<usize>, - cur: usize, - rng: ThreadRng, - actions: Vec<ObjectWriterAction>, -} - -#[derive(Clone)] -pub enum ObjectWriterAction { - Write(Bytes), -} - -impl Debug for ObjectWriterAction { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - ObjectWriterAction::Write(bs) => write!(f, "Write({})", bs.len()), - } - } -} - -impl ObjectWriterFuzzer { - /// Create a new fuzzer. - pub fn new(name: &str, size: Option<usize>) -> Self { - Self { - name: name.to_string(), - bs: Vec::new(), - - size, - cur: 0, - - rng: thread_rng(), - actions: vec![], - } - } - - /// Generate a new action. - pub fn fuzz(&mut self) -> ObjectWriterAction { - let max = if let Some(size) = self.size { - size - self.cur - } else { - // Set max to 1MiB - 1024 * 1024 - }; - - let size = self.rng.gen_range(0..max); - - let mut bs = vec![0; size]; - self.rng.fill_bytes(&mut bs); - - let bs = Bytes::from(bs); - self.bs.extend_from_slice(&bs); - self.cur += bs.len(); - - let action = ObjectWriterAction::Write(bs); - debug!("{} perform fuzz action: {:?}", self.name, action); - - self.actions.push(action.clone()); - - action - } - - /// Check if read operation is expected. - pub fn check(&mut self, actual_bs: &[u8]) { - assert_eq!( - self.bs.len(), - actual_bs.len(), - "check failed: expected len is different with actual len, actions: {:?}", - self.actions - ); - - assert_eq!( - format!("{:x}", Sha256::digest(&self.bs)), - format!("{:x}", Sha256::digest(actual_bs)), - "check failed: expected bs is different with actual bs, actions: {:?}", - self.actions, - ); - } -} diff --git a/core/tests/behavior/write.rs b/core/tests/behavior/write.rs index 6c3114820f..3bce58c0e1 100644 --- a/core/tests/behavior/write.rs +++ b/core/tests/behavior/write.rs @@ -78,12 +78,6 @@ pub fn behavior_write_tests(op: &Operator) -> Vec<Trial> { test_read_not_exist, test_read_with_if_match, test_read_with_if_none_match, - test_fuzz_reader_with_range, - test_fuzz_reader_with_range_and_buffer, - test_fuzz_offset_reader, - test_fuzz_offset_reader_with_buffer, - test_fuzz_part_reader, - test_fuzz_part_reader_with_buffer, test_read_with_dir_path, test_read_with_special_chars, test_read_with_override_cache_control, @@ -100,7 +94,6 @@ pub fn behavior_write_tests(op: &Operator) -> Vec<Trial> { test_writer_copy, test_writer_abort, test_writer_futures_copy, - test_fuzz_unsized_writer, test_invalid_reader_seek ) } @@ -1015,264 +1008,6 @@ pub async fn test_read_with_if_none_match(op: Operator) -> Result<()> { Ok(()) } -pub async fn test_fuzz_reader_with_range(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op.reader_with(&path).range(0..content.len() as u64).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - -pub async fn test_fuzz_reader_with_range_and_buffer(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op - .reader_with(&path) - .range(0..content.len() as u64) - .buffer(4096) - .await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - -pub async fn test_fuzz_offset_reader(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op.reader_with(&path).range(0..).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - -pub async fn test_fuzz_offset_reader_with_buffer(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(op.info().full_capability()); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = ObjectReaderFuzzer::new(&path, content.clone(), 0, content.len()); - let mut o = op.reader_with(&path).range(0..).buffer(4096).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - -pub async fn test_fuzz_part_reader(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, size) = gen_bytes(op.info().full_capability()); - let (offset, length) = gen_offset_length(size); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = - ObjectReaderFuzzer::new(&path, content.clone(), offset as usize, length as usize); - let mut o = op.reader_with(&path).range(offset..offset + length).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - -pub async fn test_fuzz_part_reader_with_buffer(op: Operator) -> Result<()> { - if !op.info().full_capability().read_with_range { - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, size) = gen_bytes(op.info().full_capability()); - let (offset, length) = gen_offset_length(size); - - op.write(&path, content.clone()) - .await - .expect("write must succeed"); - - let mut fuzzer = - ObjectReaderFuzzer::new(&path, content.clone(), offset as usize, length as usize); - let mut o = op - .reader_with(&path) - .range(offset..offset + length) - .buffer(4096) - .await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectReaderAction::Read(size) => { - let mut bs = vec![0; size]; - let n = o.read(&mut bs).await?; - fuzzer.check_read(n, &bs[..n]) - } - ObjectReaderAction::Seek(input_pos) => { - let actual_pos = o.seek(input_pos).await?; - fuzzer.check_seek(input_pos, actual_pos) - } - ObjectReaderAction::Next => { - let actual_bs = o - .next() - .await - .map(|v| v.expect("next should not return error")); - fuzzer.check_next(actual_bs) - } - } - } - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - /// Read with dir path should return an error. pub async fn test_read_with_dir_path(op: Operator) -> Result<()> { if !op.info().full_capability().create_dir { @@ -1772,33 +1507,6 @@ pub async fn test_writer_futures_copy(op: Operator) -> Result<()> { Ok(()) } -/// Add test for unsized writer -pub async fn test_fuzz_unsized_writer(op: Operator) -> Result<()> { - if !op.info().full_capability().write_can_multi { - warn!("{op:?} doesn't support write without content length, test skip"); - return Ok(()); - } - - let path = uuid::Uuid::new_v4().to_string(); - - let mut fuzzer = ObjectWriterFuzzer::new(&path, None); - - let mut w = op.writer_with(&path).buffer(8 * 1024 * 1024).await?; - - for _ in 0..100 { - match fuzzer.fuzz() { - ObjectWriterAction::Write(bs) => w.write(bs).await?, - } - } - w.close().await?; - - let content = op.read(&path).await?; - fuzzer.check(&content); - - op.delete(&path).await.expect("delete must succeed"); - Ok(()) -} - /// seeking a negative position should return a InvalidInput error pub async fn test_invalid_reader_seek(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string();
