blob: b789c8d5b1279677d361ef5c5d2451d886ba1d17 [file] [log] [blame]
David Rogers10395842020-09-16 15:39:35 -07001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#include <array>
16#include <cstddef>
17#include <cstring>
18#include <span>
19
20#include "gtest/gtest.h"
21#include "pw_blob_store/blob_store.h"
22#include "pw_kvs/crc16_checksum.h"
23#include "pw_kvs/fake_flash_memory.h"
24#include "pw_kvs/flash_memory.h"
25#include "pw_kvs/test_key_value_store.h"
26#include "pw_log/log.h"
27#include "pw_random/xor_shift.h"
28
29namespace pw::blob_store {
30namespace {
31
32class BlobStoreChunkTest : public ::testing::Test {
33 protected:
34 BlobStoreChunkTest() : flash_(kFlashAlignment), partition_(&flash_) {}
35
36 void InitFlashTo(std::span<const std::byte> contents) {
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000037 partition_.Erase()
38 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
David Rogers10395842020-09-16 15:39:35 -070039 std::memcpy(flash_.buffer().data(), contents.data(), contents.size());
40 }
41
42 void InitSourceBufferToRandom(uint64_t seed) {
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000043 partition_.Erase()
44 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
David Rogers10395842020-09-16 15:39:35 -070045 random::XorShiftStarRng64 rng(seed);
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000046 rng.Get(source_buffer_)
47 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
David Rogers10395842020-09-16 15:39:35 -070048 }
49
50 void InitSourceBufferToFill(char fill) {
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000051 partition_.Erase()
52 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
David Rogers10395842020-09-16 15:39:35 -070053 std::memset(source_buffer_.data(), fill, source_buffer_.size());
54 }
55
56 // Fill the source buffer with random pattern based on given seed, written to
57 // BlobStore in specified chunk size.
58 void ChunkWriteTest(size_t chunk_size) {
59 constexpr size_t kBufferSize = 256;
60 kvs::ChecksumCrc16 checksum;
61
62 char name[16] = {};
63 snprintf(name, sizeof(name), "Blob%u", static_cast<unsigned>(chunk_size));
64
65 BlobStoreBuffer<kBufferSize> blob(
David Rogers1f08acb2020-11-17 23:11:58 -080066 name, partition_, &checksum, kvs::TestKvs(), kBufferSize);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080067 EXPECT_EQ(OkStatus(), blob.Init());
David Rogers10395842020-09-16 15:39:35 -070068
Armando Montanez28ad6f42021-08-30 16:23:57 -070069 BlobStore::BlobWriter writer(blob, metadata_buffer_);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080070 EXPECT_EQ(OkStatus(), writer.Open());
71 EXPECT_EQ(OkStatus(), writer.Erase());
David Rogers10395842020-09-16 15:39:35 -070072
73 ByteSpan source = source_buffer_;
74 while (source.size_bytes() > 0) {
75 const size_t write_size = std::min(source.size_bytes(), chunk_size);
76
77 PW_LOG_DEBUG("Do write of %u bytes, %u bytes remain",
78 static_cast<unsigned>(write_size),
79 static_cast<unsigned>(source.size_bytes()));
80
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080081 ASSERT_EQ(OkStatus(), writer.Write(source.first(write_size)));
David Rogers10395842020-09-16 15:39:35 -070082
83 source = source.subspan(write_size);
84 }
85
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080086 EXPECT_EQ(OkStatus(), writer.Close());
David Rogers10395842020-09-16 15:39:35 -070087
88 // Use reader to check for valid data.
89 BlobStore::BlobReader reader(blob);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080090 ASSERT_EQ(OkStatus(), reader.Open());
David Rogers0fadf442020-09-18 10:38:15 -070091 Result<ConstByteSpan> result = reader.GetMemoryMappedBlob();
David Rogers10395842020-09-16 15:39:35 -070092 ASSERT_TRUE(result.ok());
93 VerifyFlash(result.value());
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080094 EXPECT_EQ(OkStatus(), reader.Close());
David Rogers10395842020-09-16 15:39:35 -070095 }
96
David Rogers0fadf442020-09-18 10:38:15 -070097 void VerifyFlash(ConstByteSpan verify_bytes) {
David Rogers10395842020-09-16 15:39:35 -070098 // Should be defined as same size.
99 EXPECT_EQ(source_buffer_.size(), flash_.buffer().size_bytes());
100
101 // Can't allow it to march off the end of source_buffer_.
102 ASSERT_LE(verify_bytes.size_bytes(), source_buffer_.size());
103
104 for (size_t i = 0; i < verify_bytes.size_bytes(); i++) {
105 EXPECT_EQ(source_buffer_[i], verify_bytes[i]);
106 }
107 }
108
109 static constexpr size_t kFlashAlignment = 16;
110 static constexpr size_t kSectorSize = 2048;
111 static constexpr size_t kSectorCount = 2;
112 static constexpr size_t kBlobDataSize = (kSectorCount * kSectorSize);
Armando Montanez28ad6f42021-08-30 16:23:57 -0700113 static constexpr size_t kMetadataBufferSize =
114 BlobStore::BlobWriter::RequiredMetadataBufferSize(0);
David Rogers10395842020-09-16 15:39:35 -0700115
116 kvs::FakeFlashMemoryBuffer<kSectorSize, kSectorCount> flash_;
117 kvs::FlashPartition partition_;
Armando Montanez28ad6f42021-08-30 16:23:57 -0700118 std::array<std::byte, kMetadataBufferSize> metadata_buffer_;
David Rogers10395842020-09-16 15:39:35 -0700119 std::array<std::byte, kBlobDataSize> source_buffer_;
120};
121
122TEST_F(BlobStoreChunkTest, ChunkWrite1) {
123 InitSourceBufferToRandom(0x8675309);
124 ChunkWriteTest(1);
125}
126
127TEST_F(BlobStoreChunkTest, ChunkWrite2) {
128 InitSourceBufferToRandom(0x8675);
129 ChunkWriteTest(2);
130}
131
132TEST_F(BlobStoreChunkTest, ChunkWrite3) {
133 InitSourceBufferToFill(0);
134 ChunkWriteTest(3);
135}
136
137TEST_F(BlobStoreChunkTest, ChunkWrite4) {
138 InitSourceBufferToFill(1);
139 ChunkWriteTest(4);
140}
141
142TEST_F(BlobStoreChunkTest, ChunkWrite5) {
143 InitSourceBufferToFill(0xff);
144 ChunkWriteTest(5);
145}
146
147TEST_F(BlobStoreChunkTest, ChunkWrite16) {
148 InitSourceBufferToRandom(0x86);
149 ChunkWriteTest(16);
150}
151
152TEST_F(BlobStoreChunkTest, ChunkWrite64) {
153 InitSourceBufferToRandom(0x9);
154 ChunkWriteTest(64);
155}
156
157TEST_F(BlobStoreChunkTest, ChunkWrite256) {
158 InitSourceBufferToRandom(0x12345678);
159 ChunkWriteTest(256);
160}
161
162TEST_F(BlobStoreChunkTest, ChunkWrite512) {
163 InitSourceBufferToRandom(0x42);
164 ChunkWriteTest(512);
165}
166
167TEST_F(BlobStoreChunkTest, ChunkWrite4096) {
168 InitSourceBufferToRandom(0x89);
169 ChunkWriteTest(4096);
170}
171
172TEST_F(BlobStoreChunkTest, ChunkWriteSingleFull) {
173 InitSourceBufferToRandom(0x98765);
174 ChunkWriteTest(kBlobDataSize);
175}
176
177} // namespace
178} // namespace pw::blob_store