blob: 24f5daff4ea964aff4706cf47fa500900c43fc25 [file] [log] [blame]
Wyatt Heplerb7609542020-01-24 10:29:54 -08001// 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
Wyatt Hepler16b04522020-02-07 16:00:14 -080015#define DUMP_KVS_STATE_TO_FILE 0
16#define USE_MEMORY_BUFFER 1
Wyatt Hepler16b04522020-02-07 16:00:14 -080017
Wyatt Heplerb7609542020-01-24 10:29:54 -080018#include "pw_kvs/key_value_store.h"
19
Wyatt Hepleracaacf92020-01-24 10:58:30 -080020#include <array>
21#include <cstdio>
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080022#include <cstring>
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070023#include <span>
Wyatt Heplerbc6332c2020-02-10 16:34:19 -080024
25#if DUMP_KVS_STATE_TO_FILE
Wyatt Hepler16b04522020-02-07 16:00:14 -080026#include <vector>
Wyatt Heplerbc6332c2020-02-10 16:34:19 -080027#endif // DUMP_KVS_STATE_TO_FILE
Wyatt Hepler2ad60672020-01-21 08:00:16 -080028
29#include "gtest/gtest.h"
Wyatt Hepler6b3a6c92020-08-03 10:15:56 -070030#include "pw_bytes/array.h"
Wyatt Hepler12f66a12020-09-02 15:43:02 -070031#include "pw_checksum/crc16_ccitt.h"
Wyatt Heplerec4b9352020-01-31 15:51:50 -080032#include "pw_kvs/crc16_checksum.h"
David Rogers6a262b42020-07-09 03:27:41 -070033#include "pw_kvs/fake_flash_memory.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080034#include "pw_kvs/flash_memory.h"
Wyatt Heplerbdd8e5a2020-02-20 19:27:26 -080035#include "pw_kvs/internal/entry.h"
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080036#include "pw_log/log.h"
Wyatt Hepler0cdb1a32021-03-05 14:16:13 -080037#include "pw_log/shorter.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080038#include "pw_status/status.h"
Keir Mierle8c352dc2020-02-02 13:58:19 -080039#include "pw_string/string_builder.h"
Wyatt Heplerb7609542020-01-24 10:29:54 -080040
Wyatt Hepler2ad60672020-01-21 08:00:16 -080041namespace pw::kvs {
Wyatt Heplerb7609542020-01-24 10:29:54 -080042namespace {
43
Wyatt Hepler1fc11042020-02-19 17:17:51 -080044using internal::EntryHeader;
Wyatt Hepleracaacf92020-01-24 10:58:30 -080045
Wyatt Hepler38ce30f2020-02-19 11:48:31 -080046constexpr size_t kMaxEntries = 256;
47constexpr size_t kMaxUsableSectors = 256;
48
Keir Mierle8c352dc2020-02-02 13:58:19 -080049// This is a self contained flash unit with both memory and a single partition.
Ewout van Bekkum5ea33402021-03-31 11:00:02 -070050template <uint32_t kSectorSizeBytes, uint16_t kSectorCount>
Keir Mierle8c352dc2020-02-02 13:58:19 -080051struct FlashWithPartitionFake {
52 // Default to 16 byte alignment, which is common in practice.
53 FlashWithPartitionFake() : FlashWithPartitionFake(16) {}
54 FlashWithPartitionFake(size_t alignment_bytes)
55 : memory(alignment_bytes), partition(&memory, 0, memory.sector_count()) {}
56
Ewout van Bekkum5ea33402021-03-31 11:00:02 -070057 FakeFlashMemoryBuffer<kSectorSizeBytes, kSectorCount> memory;
Keir Mierle8c352dc2020-02-02 13:58:19 -080058 FlashPartition partition;
59
60 public:
Wyatt Hepler16b04522020-02-07 16:00:14 -080061#if DUMP_KVS_STATE_TO_FILE
Keir Mierle8c352dc2020-02-02 13:58:19 -080062 Status Dump(const char* filename) {
63 std::FILE* out_file = std::fopen(filename, "w+");
64 if (out_file == nullptr) {
65 PW_LOG_ERROR("Failed to dump to %s", filename);
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070066 return Status::DataLoss();
Keir Mierle8c352dc2020-02-02 13:58:19 -080067 }
68 std::vector<std::byte> out_vec(memory.size_bytes());
69 Status status =
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070070 memory.Read(0, std::span<std::byte>(out_vec.data(), out_vec.size()));
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080071 if (status != OkStatus()) {
Keir Mierle8c352dc2020-02-02 13:58:19 -080072 fclose(out_file);
73 return status;
74 }
75
76 size_t written =
77 std::fwrite(out_vec.data(), 1, memory.size_bytes(), out_file);
78 if (written != memory.size_bytes()) {
79 PW_LOG_ERROR("Failed to dump to %s, written=%u",
80 filename,
81 static_cast<unsigned>(written));
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070082 status = Status::DataLoss();
Keir Mierle8c352dc2020-02-02 13:58:19 -080083 } else {
84 PW_LOG_INFO("Dumped to %s", filename);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080085 status = OkStatus();
Keir Mierle8c352dc2020-02-02 13:58:19 -080086 }
87
88 fclose(out_file);
89 return status;
90 }
91#else
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080092 Status Dump(const char*) { return OkStatus(); }
Wyatt Hepler16b04522020-02-07 16:00:14 -080093#endif // DUMP_KVS_STATE_TO_FILE
Keir Mierle8c352dc2020-02-02 13:58:19 -080094};
95
96typedef FlashWithPartitionFake<4 * 128 /*sector size*/, 6 /*sectors*/> Flash;
97
David Rogersd64cc012020-05-26 12:37:37 -070098FakeFlashMemoryBuffer<1024, 60> large_test_flash(8);
Wyatt Heplerb7609542020-01-24 10:29:54 -080099FlashPartition large_test_partition(&large_test_flash,
100 0,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800101 large_test_flash.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800102
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800103constexpr std::array<const char*, 3> keys{"TestKey1", "Key2", "TestKey3"};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800104
Wyatt Hepler2e568872020-02-03 18:00:00 -0800105ChecksumCrc16 checksum;
David Rogers436b3aa2020-08-03 08:44:10 -0700106// For KVS magic value always use a random 32 bit integer rather than a
107// human readable 4 bytes. See pw_kvs/format.h for more information.
108constexpr EntryFormat default_format{.magic = 0xa6cb3c16,
Armando Montanez888370d2020-05-01 18:29:22 -0700109 .checksum = &checksum};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800110
Wyatt Heplerb7609542020-01-24 10:29:54 -0800111} // namespace
112
David Rogers178002a2020-06-16 13:52:54 -0700113TEST(InitCheck, TooFewSectors) {
114 // Use test flash with 1 x 4k sectors, 16 byte alignment
115 FakeFlashMemoryBuffer<4 * 1024, 1> test_flash(16);
116 FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
117
David Rogers436b3aa2020-08-03 08:44:10 -0700118 // For KVS magic value always use a random 32 bit integer rather than a
119 // human readable 4 bytes. See pw_kvs/format.h for more information.
120 constexpr EntryFormat format{.magic = 0x89bb14d2, .checksum = nullptr};
David Rogers178002a2020-06-16 13:52:54 -0700121 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&test_partition,
122 format);
123
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700124 EXPECT_EQ(kvs.Init(), Status::FailedPrecondition());
David Rogers178002a2020-06-16 13:52:54 -0700125}
126
127TEST(InitCheck, ZeroSectors) {
128 // Use test flash with 1 x 4k sectors, 16 byte alignment
129 FakeFlashMemoryBuffer<4 * 1024, 1> test_flash(16);
130
131 // Set FlashPartition to have 0 sectors.
132 FlashPartition test_partition(&test_flash, 0, 0);
133
David Rogers436b3aa2020-08-03 08:44:10 -0700134 // For KVS magic value always use a random 32 bit integer rather than a
135 // human readable 4 bytes. See pw_kvs/format.h for more information.
136 constexpr EntryFormat format{.magic = 0xd1da57c1, .checksum = nullptr};
David Rogers178002a2020-06-16 13:52:54 -0700137 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&test_partition,
138 format);
139
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700140 EXPECT_EQ(kvs.Init(), Status::FailedPrecondition());
David Rogers178002a2020-06-16 13:52:54 -0700141}
142
143TEST(InitCheck, TooManySectors) {
144 // Use test flash with 1 x 4k sectors, 16 byte alignment
145 FakeFlashMemoryBuffer<4 * 1024, 5> test_flash(16);
146
147 // Set FlashPartition to have 0 sectors.
148 FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
149
David Rogers436b3aa2020-08-03 08:44:10 -0700150 // For KVS magic value always use a random 32 bit integer rather than a
151 // human readable 4 bytes. See pw_kvs/format.h for more information.
152 constexpr EntryFormat format{.magic = 0x610f6d17, .checksum = nullptr};
David Rogers178002a2020-06-16 13:52:54 -0700153 KeyValueStoreBuffer<kMaxEntries, 2> kvs(&test_partition, format);
154
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700155 EXPECT_EQ(kvs.Init(), Status::FailedPrecondition());
David Rogers178002a2020-06-16 13:52:54 -0700156}
157
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800158#define ASSERT_OK(expr) ASSERT_EQ(OkStatus(), expr)
159#define EXPECT_OK(expr) EXPECT_EQ(OkStatus(), expr)
Keir Mierle8c352dc2020-02-02 13:58:19 -0800160
Wyatt Hepler595cf012020-02-05 09:31:02 -0800161TEST(InMemoryKvs, WriteOneKeyMultipleTimes) {
Keir Mierle8c352dc2020-02-02 13:58:19 -0800162 // Create and erase the fake flash. It will persist across reloads.
163 Flash flash;
164 ASSERT_OK(flash.partition.Erase());
165
166 int num_reloads = 2;
167 for (int reload = 0; reload < num_reloads; ++reload) {
168 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
169 DBG("xxx xxxx");
170 DBG("xxx Reload %2d xxxx", reload);
171 DBG("xxx xxxx");
172 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
173
David Rogers436b3aa2020-08-03 08:44:10 -0700174 // Create and initialize the KVS. For KVS magic value always use a random 32
175 // bit integer rather than a human readable 4 bytes. See pw_kvs/format.h for
176 // more information.
177 constexpr EntryFormat format{.magic = 0x83a9257, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800178 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
179 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800180 ASSERT_OK(kvs.Init());
181
182 // Write the same entry many times.
183 const char* key = "abcd";
Wyatt Heplere3288e12020-02-26 13:05:07 -0800184 const size_t num_writes = 99;
Keir Mierle8c352dc2020-02-02 13:58:19 -0800185 uint32_t written_value;
186 EXPECT_EQ(kvs.size(), (reload == 0) ? 0 : 1u);
187 for (uint32_t i = 0; i < num_writes; ++i) {
Wyatt Heplere3288e12020-02-26 13:05:07 -0800188 DBG("PUT #%zu for key %s with value %zu", size_t(i), key, size_t(i));
Keir Mierle8c352dc2020-02-02 13:58:19 -0800189
190 written_value = i + 0xfc; // Prevent accidental pass with zero.
191 EXPECT_OK(kvs.Put(key, written_value));
192 EXPECT_EQ(kvs.size(), 1u);
193 }
194
195 // Verify that we can read the value back.
Wyatt Heplere3288e12020-02-26 13:05:07 -0800196 DBG("GET final value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800197 uint32_t actual_value;
198 EXPECT_OK(kvs.Get(key, &actual_value));
199 EXPECT_EQ(actual_value, written_value);
200
Keir Mierle8c352dc2020-02-02 13:58:19 -0800201 char fname_buf[64] = {'\0'};
202 snprintf(&fname_buf[0],
203 sizeof(fname_buf),
204 "WriteOneKeyMultipleTimes_%d.bin",
205 reload);
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +0000206 flash.Dump(fname_buf)
207 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Keir Mierle8c352dc2020-02-02 13:58:19 -0800208 }
209}
210
211TEST(InMemoryKvs, WritingMultipleKeysIncreasesSize) {
212 // Create and erase the fake flash.
213 Flash flash;
214 ASSERT_OK(flash.partition.Erase());
215
David Rogers436b3aa2020-08-03 08:44:10 -0700216 // Create and initialize the KVS. For KVS magic value always use a random 32
217 // bit integer rather than a human readable 4 bytes. See pw_kvs/format.h for
218 // more information.
219 constexpr EntryFormat format{.magic = 0x2ed3a058, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800220 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
221 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800222 ASSERT_OK(kvs.Init());
223
224 // Write the same entry many times.
225 const size_t num_writes = 10;
226 EXPECT_EQ(kvs.size(), 0u);
227 for (size_t i = 0; i < num_writes; ++i) {
228 StringBuffer<150> key;
229 key << "key_" << i;
Wyatt Heplere3288e12020-02-26 13:05:07 -0800230 DBG("PUT #%zu for key %s with value %zu", i, key.c_str(), i);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800231
232 size_t value = i + 77; // Prevent accidental pass with zero.
233 EXPECT_OK(kvs.Put(key.view(), value));
234 EXPECT_EQ(kvs.size(), i + 1);
235 }
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +0000236 flash.Dump("WritingMultipleKeysIncreasesSize.bin")
237 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Keir Mierle8c352dc2020-02-02 13:58:19 -0800238}
239
240TEST(InMemoryKvs, WriteAndReadOneKey) {
241 // Create and erase the fake flash.
242 Flash flash;
243 ASSERT_OK(flash.partition.Erase());
244
245 // Create and initialize the KVS.
David Rogers436b3aa2020-08-03 08:44:10 -0700246 // For KVS magic value always use a random 32 bit integer rather than a
247 // human readable 4 bytes. See pw_kvs/format.h for more information.
248 constexpr EntryFormat format{.magic = 0x5d70896, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800249 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
250 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800251 ASSERT_OK(kvs.Init());
252
David Rogersc0104462020-05-08 15:50:23 -0700253 // Add one entry.
Keir Mierle8c352dc2020-02-02 13:58:19 -0800254 const char* key = "Key1";
Wyatt Heplere3288e12020-02-26 13:05:07 -0800255 DBG("PUT value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800256 uint8_t written_value = 0xDA;
257 ASSERT_OK(kvs.Put(key, written_value));
258 EXPECT_EQ(kvs.size(), 1u);
259
Wyatt Heplere3288e12020-02-26 13:05:07 -0800260 DBG("GET value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800261 uint8_t actual_value;
262 ASSERT_OK(kvs.Get(key, &actual_value));
263 EXPECT_EQ(actual_value, written_value);
264
265 EXPECT_EQ(kvs.size(), 1u);
266}
267
David Rogersc0104462020-05-08 15:50:23 -0700268TEST(InMemoryKvs, WriteOneKeyValueMultipleTimes) {
269 // Create and erase the fake flash.
270 Flash flash;
271 ASSERT_OK(flash.partition.Erase());
272
273 // Create and initialize the KVS.
David Rogersc0104462020-05-08 15:50:23 -0700274 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
David Rogersd50eb1c2020-05-12 17:46:36 -0700275 default_format);
David Rogersc0104462020-05-08 15:50:23 -0700276 ASSERT_OK(kvs.Init());
277
278 // Add one entry, with the same key and value, multiple times.
279 const char* key = "Key1";
280 uint8_t written_value = 0xDA;
281 for (int i = 0; i < 50; i++) {
282 DBG("PUT [%d] value for key: %s", i, key);
283 ASSERT_OK(kvs.Put(key, written_value));
284 EXPECT_EQ(kvs.size(), 1u);
285 }
286
287 DBG("GET value for key: %s", key);
288 uint8_t actual_value;
289 ASSERT_OK(kvs.Get(key, &actual_value));
290 EXPECT_EQ(actual_value, written_value);
291
292 // Verify that only one entry was written to the KVS.
293 EXPECT_EQ(kvs.size(), 1u);
294 EXPECT_EQ(kvs.transaction_count(), 1u);
295 KeyValueStore::StorageStats stats = kvs.GetStorageStats();
296 EXPECT_EQ(stats.reclaimable_bytes, 0u);
297}
298
Keir Mierle8c352dc2020-02-02 13:58:19 -0800299TEST(InMemoryKvs, Basic) {
300 const char* key1 = "Key1";
301 const char* key2 = "Key2";
302
303 // Create and erase the fake flash.
304 Flash flash;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800305 ASSERT_EQ(OkStatus(), flash.partition.Erase());
Keir Mierle8c352dc2020-02-02 13:58:19 -0800306
307 // Create and initialize the KVS.
David Rogers436b3aa2020-08-03 08:44:10 -0700308 // For KVS magic value always use a random 32 bit integer rather than a
309 // human readable 4 bytes. See pw_kvs/format.h for more information.
310 constexpr EntryFormat format{.magic = 0x7bf19895, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800311 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
312 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800313 ASSERT_OK(kvs.Init());
314
315 // Add two entries with different keys and values.
Keir Mierle8c352dc2020-02-02 13:58:19 -0800316 uint8_t value1 = 0xDA;
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700317 ASSERT_OK(kvs.Put(key1, std::as_bytes(std::span(&value1, sizeof(value1)))));
Keir Mierle8c352dc2020-02-02 13:58:19 -0800318 EXPECT_EQ(kvs.size(), 1u);
319
Keir Mierle8c352dc2020-02-02 13:58:19 -0800320 uint32_t value2 = 0xBAD0301f;
321 ASSERT_OK(kvs.Put(key2, value2));
322 EXPECT_EQ(kvs.size(), 2u);
323
Keir Mierle8c352dc2020-02-02 13:58:19 -0800324 // Verify data
325 uint32_t test2;
326 EXPECT_OK(kvs.Get(key2, &test2));
327
Keir Mierle8c352dc2020-02-02 13:58:19 -0800328 uint8_t test1;
329 ASSERT_OK(kvs.Get(key1, &test1));
330
331 EXPECT_EQ(test1, value1);
332 EXPECT_EQ(test2, value2);
333
334 EXPECT_EQ(kvs.size(), 2u);
335}
336
David Rogers6a262b42020-07-09 03:27:41 -0700337TEST(InMemoryKvs, CallingEraseTwice_NothingWrittenToFlash) {
338 // Create and erase the fake flash.
339 Flash flash;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800340 ASSERT_EQ(OkStatus(), flash.partition.Erase());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800341
David Rogers6a262b42020-07-09 03:27:41 -0700342 // Create and initialize the KVS.
343 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
344 default_format);
345 ASSERT_OK(kvs.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800346
Wyatt Heplerb7609542020-01-24 10:29:54 -0800347 const uint8_t kValue = 0xDA;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800348 ASSERT_EQ(OkStatus(), kvs.Put(keys[0], kValue));
349 ASSERT_EQ(OkStatus(), kvs.Delete(keys[0]));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800350
David Rogers6a262b42020-07-09 03:27:41 -0700351 // Compare before / after checksums to verify that nothing was written.
Wyatt Heplereb8a34c2020-09-02 13:11:03 -0700352 const uint16_t crc = checksum::Crc16Ccitt::Calculate(flash.memory.buffer());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800353
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700354 EXPECT_EQ(kvs.Delete(keys[0]), Status::NotFound());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800355
Wyatt Heplereb8a34c2020-09-02 13:11:03 -0700356 EXPECT_EQ(crc, checksum::Crc16Ccitt::Calculate(flash.memory.buffer()));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800357}
358
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800359class LargeEmptyInitializedKvs : public ::testing::Test {
360 protected:
Armando Montanez888370d2020-05-01 18:29:22 -0700361 LargeEmptyInitializedKvs() : kvs_(&large_test_partition, default_format) {
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800362 ASSERT_EQ(OkStatus(), large_test_partition.Erase());
363 ASSERT_EQ(OkStatus(), kvs_.Init());
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800364 }
365
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800366 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_;
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800367};
368
369TEST_F(LargeEmptyInitializedKvs, Basic) {
370 const uint8_t kValue1 = 0xDA;
371 const uint8_t kValue2 = 0x12;
372 uint8_t value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800373 ASSERT_EQ(OkStatus(), kvs_.Put(keys[0], kValue1));
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800374 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800375 ASSERT_EQ(OkStatus(), kvs_.Delete(keys[0]));
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700376 EXPECT_EQ(kvs_.Get(keys[0], &value), Status::NotFound());
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800377 ASSERT_EQ(OkStatus(), kvs_.Put(keys[1], kValue1));
378 ASSERT_EQ(OkStatus(), kvs_.Put(keys[2], kValue2));
379 ASSERT_EQ(OkStatus(), kvs_.Delete(keys[1]));
380 EXPECT_EQ(OkStatus(), kvs_.Get(keys[2], &value));
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800381 EXPECT_EQ(kValue2, value);
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700382 ASSERT_EQ(kvs_.Get(keys[1], &value), Status::NotFound());
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800383 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800384}
385
David Rogers3c298372020-10-12 14:15:39 -0700386TEST_F(LargeEmptyInitializedKvs, FullMaintenance) {
387 const uint8_t kValue1 = 0xDA;
388 const uint8_t kValue2 = 0x12;
389
390 // Write a key and write again with a different value, resulting in a stale
391 // entry from the first write.
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800392 ASSERT_EQ(OkStatus(), kvs_.Put(keys[0], kValue1));
393 ASSERT_EQ(OkStatus(), kvs_.Put(keys[0], kValue2));
David Rogers3c298372020-10-12 14:15:39 -0700394 EXPECT_EQ(kvs_.size(), 1u);
395
396 KeyValueStore::StorageStats stats = kvs_.GetStorageStats();
397 EXPECT_EQ(stats.sector_erase_count, 0u);
398 EXPECT_GT(stats.reclaimable_bytes, 0u);
399
400 // Do regular FullMaintenance, which should not touch the sector with valid
401 // data.
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800402 EXPECT_EQ(OkStatus(), kvs_.FullMaintenance());
David Rogers3c298372020-10-12 14:15:39 -0700403 stats = kvs_.GetStorageStats();
404 EXPECT_EQ(stats.sector_erase_count, 0u);
405 EXPECT_GT(stats.reclaimable_bytes, 0u);
406
407 // Do aggressive FullMaintenance, which should GC the sector with valid data,
408 // resulting in no reclaimable bytes and an erased sector.
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800409 EXPECT_EQ(OkStatus(), kvs_.HeavyMaintenance());
David Rogers3c298372020-10-12 14:15:39 -0700410 stats = kvs_.GetStorageStats();
411 EXPECT_EQ(stats.sector_erase_count, 1u);
412 EXPECT_EQ(stats.reclaimable_bytes, 0u);
413}
414
David Rogers6a262b42020-07-09 03:27:41 -0700415TEST(InMemoryKvs, Put_MaxValueSize) {
416 // Create and erase the fake flash.
417 Flash flash;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800418 ASSERT_EQ(OkStatus(), flash.partition.Erase());
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800419
David Rogers6a262b42020-07-09 03:27:41 -0700420 // Create and initialize the KVS.
421 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
422 default_format);
423 ASSERT_OK(kvs.Init());
Wyatt Heplere3288e12020-02-26 13:05:07 -0800424
David Rogers1f1ebb62020-07-17 18:21:32 -0700425 size_t max_key_value_size = kvs.max_key_value_size_bytes();
426 EXPECT_EQ(max_key_value_size,
427 KeyValueStore::max_key_value_size_bytes(
428 flash.partition.sector_size_bytes()));
429
David Rogers6a262b42020-07-09 03:27:41 -0700430 size_t max_value_size =
431 flash.partition.sector_size_bytes() - sizeof(EntryHeader) - 1;
David Rogers1f1ebb62020-07-17 18:21:32 -0700432 EXPECT_EQ(max_key_value_size, (max_value_size + 1));
Wyatt Heplere3288e12020-02-26 13:05:07 -0800433
David Rogers6a262b42020-07-09 03:27:41 -0700434 // Use the large_test_flash as a big chunk of data for the Put statement.
435 ASSERT_GT(sizeof(large_test_flash), max_value_size + 2 * sizeof(EntryHeader));
436 auto big_data = std::as_bytes(std::span(&large_test_flash, 1));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800437
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800438 EXPECT_EQ(OkStatus(), kvs.Put("K", big_data.subspan(0, max_value_size)));
David Rogers6a262b42020-07-09 03:27:41 -0700439
440 // Larger than maximum is rejected.
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700441 EXPECT_EQ(Status::InvalidArgument(),
David Rogers6a262b42020-07-09 03:27:41 -0700442 kvs.Put("K", big_data.subspan(0, max_value_size + 1)));
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700443 EXPECT_EQ(Status::InvalidArgument(), kvs.Put("K", big_data));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800444}
445
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800446} // namespace pw::kvs