blob: 02491e6508eea9b05b0a654394e963c79c8e9aaf [file] [log] [blame]
David Rogers5aa32ab2020-09-08 14:39:24 -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 DeferredWriteTest : public ::testing::Test {
33 protected:
34 DeferredWriteTest() : flash_(kFlashAlignment), partition_(&flash_) {}
35
36 void InitFlashTo(std::span<const std::byte> contents) {
37 partition_.Erase();
38 std::memcpy(flash_.buffer().data(), contents.data(), contents.size());
39 }
40
41 void InitBufferToRandom(uint64_t seed) {
42 partition_.Erase();
43 random::XorShiftStarRng64 rng(seed);
44 rng.Get(buffer_);
45 }
46
47 void InitBufferToFill(char fill) {
48 partition_.Erase();
49 std::memset(buffer_.data(), fill, buffer_.size());
50 }
51
52 // Fill the source buffer with random pattern based on given seed, written to
53 // BlobStore in specified chunk size.
54 void ChunkWriteTest(size_t chunk_size, size_t flush_interval) {
David Rogers5aa32ab2020-09-08 14:39:24 -070055 constexpr size_t kWriteSize = 64;
56 kvs::ChecksumCrc16 checksum;
57
58 size_t bytes_since_flush = 0;
59
60 char name[16] = {};
61 snprintf(name, sizeof(name), "Blob%u", static_cast<unsigned>(chunk_size));
62
63 BlobStoreBuffer<kBufferSize> blob(
David Rogersa2131ab2020-09-21 13:38:09 -070064 name, partition_, &checksum, kvs::TestKvs(), kWriteSize);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080065 EXPECT_EQ(OkStatus(), blob.Init());
David Rogers5aa32ab2020-09-08 14:39:24 -070066
67 BlobStore::DeferredWriter writer(blob);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080068 EXPECT_EQ(OkStatus(), writer.Open());
David Rogers5aa32ab2020-09-08 14:39:24 -070069
70 ByteSpan source = buffer_;
71 while (source.size_bytes() > 0) {
72 const size_t write_size = std::min(source.size_bytes(), chunk_size);
73
74 PW_LOG_DEBUG("Do write of %u bytes, %u bytes remain",
75 static_cast<unsigned>(write_size),
76 static_cast<unsigned>(source.size_bytes()));
77
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080078 ASSERT_EQ(OkStatus(), writer.Write(source.first(write_size)));
David Rogers5aa32ab2020-09-08 14:39:24 -070079 // TODO: Add check that the write did not go to flash yet.
80
81 source = source.subspan(write_size);
82 bytes_since_flush += write_size;
83
84 if (bytes_since_flush >= flush_interval) {
85 bytes_since_flush = 0;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080086 ASSERT_EQ(OkStatus(), writer.Flush());
David Rogers5aa32ab2020-09-08 14:39:24 -070087 }
88 }
89
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080090 EXPECT_EQ(OkStatus(), writer.Close());
David Rogers5aa32ab2020-09-08 14:39:24 -070091
92 // Use reader to check for valid data.
David Rogers10395842020-09-16 15:39:35 -070093 BlobStore::BlobReader reader(blob);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080094 ASSERT_EQ(OkStatus(), reader.Open());
David Rogers0fadf442020-09-18 10:38:15 -070095 Result<ConstByteSpan> result = reader.GetMemoryMappedBlob();
David Rogers5aa32ab2020-09-08 14:39:24 -070096 ASSERT_TRUE(result.ok());
97 VerifyFlash(result.value());
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080098 EXPECT_EQ(OkStatus(), reader.Close());
David Rogers5aa32ab2020-09-08 14:39:24 -070099 }
100
David Rogers0fadf442020-09-18 10:38:15 -0700101 void VerifyFlash(ConstByteSpan verify_bytes) {
David Rogers5aa32ab2020-09-08 14:39:24 -0700102 // Should be defined as same size.
103 EXPECT_EQ(buffer_.size(), flash_.buffer().size_bytes());
104
105 // Can't allow it to march off the end of buffer_.
106 ASSERT_LE(verify_bytes.size_bytes(), buffer_.size());
107
108 for (size_t i = 0; i < verify_bytes.size_bytes(); i++) {
109 EXPECT_EQ(buffer_[i], verify_bytes[i]);
110 }
111 }
112
113 static constexpr size_t kFlashAlignment = 16;
David Rogers1f08acb2020-11-17 23:11:58 -0800114 static constexpr size_t kSectorSize = 1024;
115 static constexpr size_t kSectorCount = 4;
116 static constexpr size_t kBufferSize = 2 * kSectorSize;
David Rogers5aa32ab2020-09-08 14:39:24 -0700117
118 kvs::FakeFlashMemoryBuffer<kSectorSize, kSectorCount> flash_;
119 kvs::FlashPartition partition_;
120 std::array<std::byte, kSectorCount * kSectorSize> buffer_;
121};
122
123TEST_F(DeferredWriteTest, ChunkWrite1) {
124 InitBufferToRandom(0x8675309);
125 ChunkWriteTest(1, 16);
126}
127
128TEST_F(DeferredWriteTest, ChunkWrite2) {
129 InitBufferToRandom(0x8675);
130 ChunkWriteTest(2, 16);
131}
132
133TEST_F(DeferredWriteTest, ChunkWrite3) {
134 InitBufferToFill(0);
135 ChunkWriteTest(3, 16);
136}
137
138TEST_F(DeferredWriteTest, ChunkWrite4) {
139 InitBufferToFill(1);
140 ChunkWriteTest(4, 64);
141}
142
143TEST_F(DeferredWriteTest, ChunkWrite5) {
144 InitBufferToFill(0xff);
145 ChunkWriteTest(5, 64);
146}
147
148TEST_F(DeferredWriteTest, ChunkWrite16) {
149 InitBufferToRandom(0x86);
150 ChunkWriteTest(16, 128);
151}
152
153TEST_F(DeferredWriteTest, ChunkWrite64) {
154 InitBufferToRandom(0x9);
155 ChunkWriteTest(64, 128);
156}
157
158TEST_F(DeferredWriteTest, ChunkWrite64FullBufferFill) {
159 InitBufferToRandom(0x9);
David Rogers1f08acb2020-11-17 23:11:58 -0800160 ChunkWriteTest(64, kBufferSize);
David Rogers5aa32ab2020-09-08 14:39:24 -0700161}
162
163TEST_F(DeferredWriteTest, ChunkWrite256) {
164 InitBufferToRandom(0x12345678);
165 ChunkWriteTest(256, 256);
166}
167
168// TODO: test that has dirty flash, invalidated blob, open writer, invalidate
169// (not erase) and start writing (does the auto/implicit erase).
170
171// TODO: test that has dirty flash, invalidated blob, open writer, explicit
172// erase and start writing.
173
174// TODO: test start with dirty flash/invalid blob, open writer, write, close.
175// Verifies erase logic when write buffer has contents.
176
177} // namespace
178} // namespace pw::blob_store