opendal_testkit/write.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use bytes::Bytes;
19use bytes::BytesMut;
20use rand::Rng;
21use rand::rng;
22
23use crate::utils::sha256_digest;
24
25/// A writer operation used by write behavior tests.
26#[derive(Debug, Clone, Eq, PartialEq)]
27pub enum WriteAction {
28 /// Write a buffer with the given size.
29 ///
30 /// A writer can accept the buffer incrementally even though the action
31 /// supplies it as one logical chunk.
32 Write(usize),
33}
34
35/// Generates write chunks and verifies the combined stored data.
36pub struct WriteChecker {
37 chunks: Vec<Bytes>,
38 data: Bytes,
39}
40
41impl WriteChecker {
42 /// Create random chunks with the requested `sizes`.
43 pub fn new(sizes: Vec<usize>) -> Self {
44 let mut rng = rng();
45
46 let mut chunks = Vec::with_capacity(sizes.len());
47
48 for size in sizes {
49 let mut bs = vec![0u8; size];
50 rng.fill_bytes(&mut bs);
51 chunks.push(Bytes::from(bs));
52 }
53
54 let data = chunks.iter().fold(BytesMut::new(), |mut acc, x| {
55 acc.extend_from_slice(x);
56 acc
57 });
58
59 WriteChecker {
60 chunks,
61 data: data.freeze(),
62 }
63 }
64
65 /// Return the chunks to write, in order.
66 pub fn chunks(&self) -> &[Bytes] {
67 &self.chunks
68 }
69
70 /// Verify that `actual` equals the concatenated generated chunks.
71 pub fn check(&self, actual: &[u8]) {
72 if actual != self.data.as_ref() {
73 assert_eq!(
74 sha256_digest(actual),
75 sha256_digest(&self.data),
76 "check failed: result is not expected"
77 );
78 }
79 }
80}