Skip to main content

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}