blob: a373382cbb9f73e27eba1a57cacdded42c0a5efe [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
15#include "pw_kvs/key_value_store.h"
16
Wyatt Hepleracaacf92020-01-24 10:58:30 -080017#include <array>
18#include <cstdio>
Keir Mierle8c352dc2020-02-02 13:58:19 -080019#if defined(__linux__)
20#include <vector>
21#endif // defined(__linux__)
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080022#include <cstring>
23#include <type_traits>
Wyatt Hepleracaacf92020-01-24 10:58:30 -080024
Wyatt Hepler2ad60672020-01-21 08:00:16 -080025#include "pw_span/span.h"
26
Keir Mierle8c352dc2020-02-02 13:58:19 -080027#define PW_LOG_USE_ULTRA_SHORT_NAMES 1
28#include "pw_log/log.h"
29
Wyatt Hepler2ad60672020-01-21 08:00:16 -080030#define USE_MEMORY_BUFFER 1
31
32#include "gtest/gtest.h"
33#include "pw_checksum/ccitt_crc16.h"
Wyatt Heplerec4b9352020-01-31 15:51:50 -080034#include "pw_kvs/crc16_checksum.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080035#include "pw_kvs/flash_memory.h"
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080036#include "pw_kvs_private/format.h"
37#include "pw_kvs_private/macros.h"
38#include "pw_log/log.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080039#include "pw_status/status.h"
Keir Mierle8c352dc2020-02-02 13:58:19 -080040#include "pw_string/string_builder.h"
Wyatt Heplerb7609542020-01-24 10:29:54 -080041
42#if USE_MEMORY_BUFFER
Wyatt Hepler2ad60672020-01-21 08:00:16 -080043#include "pw_kvs/in_memory_fake_flash.h"
Wyatt Heplerb7609542020-01-24 10:29:54 -080044#endif // USE_MEMORY_BUFFER
45
Wyatt Hepler2ad60672020-01-21 08:00:16 -080046namespace pw::kvs {
Wyatt Heplerb7609542020-01-24 10:29:54 -080047namespace {
48
Wyatt Hepleracaacf92020-01-24 10:58:30 -080049using std::byte;
50
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080051template <typename... Args>
52constexpr auto ByteArray(Args... args) {
53 return std::array<byte, sizeof...(args)>{static_cast<byte>(args)...};
54}
Wyatt Hepleracaacf92020-01-24 10:58:30 -080055
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080056// Test that the ConvertsToSpan trait correctly idenitifies types that convert
57// to span.
58static_assert(!ConvertsToSpan<int>());
59static_assert(!ConvertsToSpan<void>());
60static_assert(!ConvertsToSpan<std::byte>());
61static_assert(!ConvertsToSpan<std::byte*>());
62
63static_assert(ConvertsToSpan<std::array<int, 5>>());
64static_assert(ConvertsToSpan<decltype("Hello!")>());
65
66static_assert(ConvertsToSpan<std::string_view>());
67static_assert(ConvertsToSpan<std::string_view&>());
68static_assert(ConvertsToSpan<std::string_view&&>());
69
70static_assert(ConvertsToSpan<const std::string_view>());
71static_assert(ConvertsToSpan<const std::string_view&>());
72static_assert(ConvertsToSpan<const std::string_view&&>());
73
74static_assert(ConvertsToSpan<span<int>>());
75static_assert(ConvertsToSpan<span<byte>>());
76static_assert(ConvertsToSpan<span<const int*>>());
77static_assert(ConvertsToSpan<span<bool>&&>());
78static_assert(ConvertsToSpan<const span<bool>&>());
79static_assert(ConvertsToSpan<span<bool>&&>());
Wyatt Hepleracaacf92020-01-24 10:58:30 -080080
Keir Mierle8c352dc2020-02-02 13:58:19 -080081// This is a self contained flash unit with both memory and a single partition.
82template <uint32_t sector_size_bytes, uint16_t sector_count>
83struct FlashWithPartitionFake {
84 // Default to 16 byte alignment, which is common in practice.
85 FlashWithPartitionFake() : FlashWithPartitionFake(16) {}
86 FlashWithPartitionFake(size_t alignment_bytes)
87 : memory(alignment_bytes), partition(&memory, 0, memory.sector_count()) {}
88
89 InMemoryFakeFlash<sector_size_bytes, sector_count> memory;
90 FlashPartition partition;
91
92 public:
93#if defined(__linux__)
94 Status Dump(const char* filename) {
95 std::FILE* out_file = std::fopen(filename, "w+");
96 if (out_file == nullptr) {
97 PW_LOG_ERROR("Failed to dump to %s", filename);
98 return Status::DATA_LOSS;
99 }
100 std::vector<std::byte> out_vec(memory.size_bytes());
101 Status status =
102 memory.Read(0, pw::span<std::byte>(out_vec.data(), out_vec.size()));
103 if (status != Status::OK) {
104 fclose(out_file);
105 return status;
106 }
107
108 size_t written =
109 std::fwrite(out_vec.data(), 1, memory.size_bytes(), out_file);
110 if (written != memory.size_bytes()) {
111 PW_LOG_ERROR("Failed to dump to %s, written=%u",
112 filename,
113 static_cast<unsigned>(written));
114 status = Status::DATA_LOSS;
115 } else {
116 PW_LOG_INFO("Dumped to %s", filename);
117 status = Status::OK;
118 }
119
120 fclose(out_file);
121 return status;
122 }
123#else
124 Status Dump(const char* filename) {
125 (void)(filename);
126 return Status::OK;
127 }
128#endif // defined(__linux__)
129};
130
131typedef FlashWithPartitionFake<4 * 128 /*sector size*/, 6 /*sectors*/> Flash;
132
Wyatt Heplerb7609542020-01-24 10:29:54 -0800133#if USE_MEMORY_BUFFER
134// Although it might be useful to test other configurations, some tests require
135// at least 3 sectors; therfore it should have this when checked in.
136InMemoryFakeFlash<4 * 1024, 4> test_flash(
137 16); // 4 x 4k sectors, 16 byte alignment
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800138FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800139InMemoryFakeFlash<1024, 60> large_test_flash(8);
140FlashPartition large_test_partition(&large_test_flash,
141 0,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800142 large_test_flash.sector_count());
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800143#else // TODO: Test with real flash
144FlashPartition& test_partition = FlashExternalTestPartition();
Wyatt Heplerb7609542020-01-24 10:29:54 -0800145#endif // USE_MEMORY_BUFFER
146
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800147std::array<byte, 512> buffer;
148constexpr std::array<const char*, 3> keys{"TestKey1", "Key2", "TestKey3"};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800149
Wyatt Hepler2e568872020-02-03 18:00:00 -0800150ChecksumCrc16 checksum;
151constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = &checksum};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800152
153size_t RoundUpForAlignment(size_t size) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800154 // TODO: THIS IS SO PADDEDWRITE APPEARS USED
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800155 uint16_t alignment = test_partition.alignment_bytes();
Wyatt Heplerb7609542020-01-24 10:29:54 -0800156 if (size % alignment != 0) {
157 return size + alignment - size % alignment;
158 }
159 return size;
160}
161
162// This class gives attributes of KVS that we are testing against
163class KvsAttributes {
164 public:
165 KvsAttributes(size_t key_size, size_t data_size)
166 : sector_header_meta_size_(
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800167 RoundUpForAlignment(sizeof(EntryHeader))), // TODO: not correct
Wyatt Heplerb7609542020-01-24 10:29:54 -0800168 sector_header_clean_size_(
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800169 RoundUpForAlignment(sizeof(EntryHeader))), // TODO: not correct
170 chunk_header_size_(RoundUpForAlignment(sizeof(EntryHeader))),
Wyatt Heplerb7609542020-01-24 10:29:54 -0800171 data_size_(RoundUpForAlignment(data_size)),
172 key_size_(RoundUpForAlignment(key_size)),
173 erase_size_(chunk_header_size_ + key_size_),
174 min_put_size_(chunk_header_size_ + key_size_ + data_size_) {}
175
176 size_t SectorHeaderSize() {
177 return sector_header_meta_size_ + sector_header_clean_size_;
178 }
179 size_t SectorHeaderMetaSize() { return sector_header_meta_size_; }
180 size_t ChunkHeaderSize() { return chunk_header_size_; }
181 size_t DataSize() { return data_size_; }
182 size_t KeySize() { return key_size_; }
183 size_t EraseSize() { return erase_size_; }
184 size_t MinPutSize() { return min_put_size_; }
185
186 private:
187 const size_t sector_header_meta_size_;
188 const size_t sector_header_clean_size_;
189 const size_t chunk_header_size_;
190 const size_t data_size_;
191 const size_t key_size_;
192 const size_t erase_size_;
193 const size_t min_put_size_;
194};
195
Wyatt Hepler2e568872020-02-03 18:00:00 -0800196// Use test fixture for logging support
197class KeyValueStoreTest : public ::testing::Test {
198 protected:
199 KeyValueStoreTest() : kvs_(&test_partition, format) {
200 test_partition.Erase(0, test_partition.sector_count());
201 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800202 }
Wyatt Hepler2e568872020-02-03 18:00:00 -0800203
204 // Intention of this is to put and erase key-val to fill up sectors. It's a
205 // helper function in testing how KVS handles cases where flash sector is full
206 // or near full.
207 void FillKvs(const char* key, size_t size_to_fill) {
208 constexpr size_t kTestDataSize = 8;
209 KvsAttributes kvs_attr(std::strlen(key), kTestDataSize);
210 const size_t kMaxPutSize =
211 buffer.size() + kvs_attr.ChunkHeaderSize() + kvs_attr.KeySize();
212
213 ASSERT_GE(size_to_fill, kvs_attr.MinPutSize() + kvs_attr.EraseSize());
214
215 // Saving enough space to perform erase after loop
216 size_to_fill -= kvs_attr.EraseSize();
217 // We start with possible small chunk to prevent too small of a Kvs.Put() at
218 // the end.
219 size_t chunk_len =
220 std::max(kvs_attr.MinPutSize(), size_to_fill % buffer.size());
221 std::memset(buffer.data(), 0, buffer.size());
222 while (size_to_fill > 0) {
223 // Changing buffer value so put actually does something
224 buffer[0] = static_cast<byte>(static_cast<uint8_t>(buffer[0]) + 1);
225 ASSERT_EQ(Status::OK,
226 kvs_.Put(key,
227 span(buffer.data(),
228 chunk_len - kvs_attr.ChunkHeaderSize() -
229 kvs_attr.KeySize())));
230 size_to_fill -= chunk_len;
231 chunk_len = std::min(size_to_fill, kMaxPutSize);
232 }
233 ASSERT_EQ(Status::OK, kvs_.Delete(key));
234 }
235
236 KeyValueStore kvs_;
237};
238
239Status PaddedWrite(FlashPartition* partition,
240 FlashPartition::Address address,
241 const std::byte* buf,
242 size_t size) {
243 static constexpr size_t kMaxAlignmentBytes = 128;
244 byte alignment_buffer[kMaxAlignmentBytes] = {};
245
246 size_t aligned_bytes = size - (size % partition->alignment_bytes());
247 TRY(partition->Write(address, span(buf, aligned_bytes)));
248
249 uint16_t remaining_bytes = size - aligned_bytes;
250 if (remaining_bytes > 0) {
251 std::memcpy(alignment_buffer, &buf[aligned_bytes], remaining_bytes);
252 if (Status status = partition->Write(
253 address + aligned_bytes,
254 span(alignment_buffer, partition->alignment_bytes()));
255 !status.ok()) {
256 return status;
257 }
258 }
259 return Status::OK;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800260}
261
262uint16_t CalcKvsCrc(const char* key, const void* data, size_t data_len) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800263 // TODO: remove this; it's only to prevent unused function warnings
264 (void)PaddedWrite;
265
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800266 uint16_t crc = checksum::CcittCrc16(as_bytes(span(key, std::strlen(key))));
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800267 return checksum::CcittCrc16(span(static_cast<const byte*>(data), data_len),
268 crc);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800269}
270
271uint16_t CalcTestPartitionCrc() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800272 byte buf[16]; // Read as 16 byte chunks
273 EXPECT_EQ(sizeof(buf) % test_partition.alignment_bytes(), 0u);
274 EXPECT_EQ(test_partition.size_bytes() % sizeof(buf), 0u);
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800275 uint16_t crc = checksum::kCcittCrc16DefaultInitialValue;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800276 for (size_t i = 0; i < test_partition.size_bytes(); i += sizeof(buf)) {
277 test_partition.Read(i, buf);
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800278 crc = checksum::CcittCrc16(as_bytes(span(buf)), crc);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800279 }
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800280 return crc;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800281}
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800282
Wyatt Heplerb7609542020-01-24 10:29:54 -0800283} // namespace
284
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800285TEST_F(KeyValueStoreTest, Delete_GetDeletedKey_ReturnsNotFound) {
286 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
287 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
288
289 EXPECT_EQ(Status::NOT_FOUND, kvs_.Get("kEy", {}).status());
290}
291
292TEST_F(KeyValueStoreTest, Delete_AddBackKey_PersistsAfterInitialization) {
293 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
294 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
295
296 EXPECT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("45678"))));
297 char data[6] = {};
298 ASSERT_EQ(Status::OK, kvs_.Get("kEy", &data));
299 EXPECT_STREQ(data, "45678");
300
301 // Ensure that the re-added key is still present after reinitialization.
302 KeyValueStore new_kvs(&test_partition, format);
303 ASSERT_EQ(Status::OK, new_kvs.Init());
304
305 EXPECT_EQ(Status::OK, new_kvs.Put("kEy", as_bytes(span("45678"))));
306 char new_data[6] = {};
307 EXPECT_EQ(Status::OK, new_kvs.Get("kEy", &new_data));
308 EXPECT_STREQ(data, "45678");
309}
310
311TEST_F(KeyValueStoreTest, Delete_AllItems_KvsIsEmpty) {
312 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
313 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
314
315 EXPECT_EQ(0u, kvs_.size());
316 EXPECT_TRUE(kvs_.empty());
317}
318
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800319TEST_F(KeyValueStoreTest, Iteration_Empty_ByReference) {
Wyatt Heplerce0da522020-02-04 16:56:44 -0800320 for (const KeyValueStore::Item& entry : kvs_) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800321 FAIL(); // The KVS is empty; this shouldn't execute.
322 static_cast<void>(entry);
323 }
324}
325
326TEST_F(KeyValueStoreTest, Iteration_Empty_ByValue) {
Wyatt Heplerce0da522020-02-04 16:56:44 -0800327 for (KeyValueStore::Item entry : kvs_) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800328 FAIL(); // The KVS is empty; this shouldn't execute.
329 static_cast<void>(entry);
330 }
331}
332
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800333TEST_F(KeyValueStoreTest, Iteration_OneItem) {
334 char value[] = "123";
335
336 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span(value))));
337
338 for (KeyValueStore::Item entry : kvs_) {
339 EXPECT_STREQ(entry.key().data(), "kEy"); // Make sure null-terminated.
340
341 char buffer[sizeof(value)] = {};
342 EXPECT_EQ(Status::OK, entry.Get(&buffer));
343 EXPECT_STREQ(value, buffer);
344 }
345}
346
347TEST_F(KeyValueStoreTest, Iteration_EmptyAfterDeletion) {
348 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
349 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
350
351 for (KeyValueStore::Item entry : kvs_) {
352 static_cast<void>(entry);
353 FAIL();
354 }
355}
356
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800357TEST_F(KeyValueStoreTest, DISABLED_FuzzTest) {
358 if (test_partition.sector_size_bytes() < 4 * 1024 ||
359 test_partition.sector_count() < 4) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800360 PW_LOG_INFO("Sectors too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800361 return; // TODO: Test could be generalized
362 }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800363 const char* key1 = "Buf1";
364 const char* key2 = "Buf2";
365 const size_t kLargestBufSize = 3 * 1024;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800366 static byte buf1[kLargestBufSize];
367 static byte buf2[kLargestBufSize];
368 std::memset(buf1, 1, sizeof(buf1));
369 std::memset(buf2, 2, sizeof(buf2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800370
371 // Start with things in KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -0800372 ASSERT_EQ(Status::OK, kvs_.Put(key1, buf1));
373 ASSERT_EQ(Status::OK, kvs_.Put(key2, buf2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800374 for (size_t j = 0; j < keys.size(); j++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800375 ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800376 }
377
378 for (size_t i = 0; i < 100; i++) {
379 // Vary two sizes
380 size_t size1 = (kLargestBufSize) / (i + 1);
381 size_t size2 = (kLargestBufSize) / (100 - i);
382 for (size_t j = 0; j < 50; j++) {
383 // Rewrite a single key many times, can fill up a sector
Wyatt Hepler2e568872020-02-03 18:00:00 -0800384 ASSERT_EQ(Status::OK, kvs_.Put("some_data", j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800385 }
386 // Delete and re-add everything
Wyatt Hepler2e568872020-02-03 18:00:00 -0800387 ASSERT_EQ(Status::OK, kvs_.Delete(key1));
388 ASSERT_EQ(Status::OK, kvs_.Put(key1, span(buf1, size1)));
389 ASSERT_EQ(Status::OK, kvs_.Delete(key2));
390 ASSERT_EQ(Status::OK, kvs_.Put(key2, span(buf2, size2)));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800391 for (size_t j = 0; j < keys.size(); j++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800392 ASSERT_EQ(Status::OK, kvs_.Delete(keys[j]));
393 ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800394 }
395
396 // Re-enable and verify
Wyatt Hepler2e568872020-02-03 18:00:00 -0800397 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800398 static byte buf[4 * 1024];
Wyatt Hepler2e568872020-02-03 18:00:00 -0800399 ASSERT_EQ(Status::OK, kvs_.Get(key1, span(buf, size1)).status());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800400 ASSERT_EQ(std::memcmp(buf, buf1, size1), 0);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800401 ASSERT_EQ(Status::OK, kvs_.Get(key2, span(buf, size2)).status());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800402 ASSERT_EQ(std::memcmp(buf2, buf2, size2), 0);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800403 for (size_t j = 0; j < keys.size(); j++) {
404 size_t ret = 1000;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800405 ASSERT_EQ(Status::OK, kvs_.Get(keys[j], &ret));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800406 ASSERT_EQ(ret, j);
407 }
408 }
409}
410
Wyatt Hepler595cf012020-02-05 09:31:02 -0800411TEST_F(KeyValueStoreTest, Basic) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800412 // Add some data
413 uint8_t value1 = 0xDA;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800414 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800415 kvs_.Put(keys[0], as_bytes(span(&value1, sizeof(value1)))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800416
417 uint32_t value2 = 0xBAD0301f;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800418 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], value2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800419
420 // Verify data
421 uint32_t test2;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800422 EXPECT_EQ(Status::OK, kvs_.Get(keys[1], &test2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800423 uint8_t test1;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800424 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &test1));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800425
426 EXPECT_EQ(test1, value1);
427 EXPECT_EQ(test2, value2);
428
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800429 // Delete a key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800430 EXPECT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800431
432 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800433 EXPECT_EQ(kvs_.Get(keys[0], &test1), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800434 test2 = 0;
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800435 ASSERT_EQ(
436 Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800437 kvs_.Get(keys[1], span(reinterpret_cast<byte*>(&test2), sizeof(test2)))
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800438 .status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800439 EXPECT_EQ(test2, value2);
440
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800441 // Delete other key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800442 kvs_.Delete(keys[1]);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800443
444 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800445 EXPECT_EQ(kvs_.size(), 0u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800446}
447
Keir Mierle8c352dc2020-02-02 13:58:19 -0800448#define ASSERT_OK(expr) ASSERT_EQ(Status::OK, expr)
449#define EXPECT_OK(expr) EXPECT_EQ(Status::OK, expr)
450
Wyatt Hepler595cf012020-02-05 09:31:02 -0800451TEST(InMemoryKvs, WriteOneKeyMultipleTimes) {
Keir Mierle8c352dc2020-02-02 13:58:19 -0800452 // Create and erase the fake flash. It will persist across reloads.
453 Flash flash;
454 ASSERT_OK(flash.partition.Erase());
455
456 int num_reloads = 2;
457 for (int reload = 0; reload < num_reloads; ++reload) {
458 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
459 DBG("xxx xxxx");
460 DBG("xxx Reload %2d xxxx", reload);
461 DBG("xxx xxxx");
462 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
463
464 // Create and initialize the KVS.
465 constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3,
466 .checksum = nullptr};
467 KeyValueStore kvs(&flash.partition, format);
468 ASSERT_OK(kvs.Init());
469
470 // Write the same entry many times.
471 const char* key = "abcd";
472 const size_t num_writes = 1; // TODO: Make this > 1 when things work.
473 uint32_t written_value;
474 EXPECT_EQ(kvs.size(), (reload == 0) ? 0 : 1u);
475 for (uint32_t i = 0; i < num_writes; ++i) {
Wyatt Hepler6e3a83b2020-02-04 07:36:45 -0800476 INF("PUT #%zu for key %s with value %zu", size_t(i), key, size_t(i));
Keir Mierle8c352dc2020-02-02 13:58:19 -0800477
478 written_value = i + 0xfc; // Prevent accidental pass with zero.
479 EXPECT_OK(kvs.Put(key, written_value));
480 EXPECT_EQ(kvs.size(), 1u);
481 }
482
483 // Verify that we can read the value back.
484 INF("GET final value for key: %s", key);
485 uint32_t actual_value;
486 EXPECT_OK(kvs.Get(key, &actual_value));
487 EXPECT_EQ(actual_value, written_value);
488
489 kvs.LogDebugInfo();
490
491 char fname_buf[64] = {'\0'};
492 snprintf(&fname_buf[0],
493 sizeof(fname_buf),
494 "WriteOneKeyMultipleTimes_%d.bin",
495 reload);
496 flash.Dump(fname_buf);
497 }
498}
499
500TEST(InMemoryKvs, WritingMultipleKeysIncreasesSize) {
501 // Create and erase the fake flash.
502 Flash flash;
503 ASSERT_OK(flash.partition.Erase());
504
505 // Create and initialize the KVS.
506 constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
507 KeyValueStore kvs(&flash.partition, format);
508 ASSERT_OK(kvs.Init());
509
510 // Write the same entry many times.
511 const size_t num_writes = 10;
512 EXPECT_EQ(kvs.size(), 0u);
513 for (size_t i = 0; i < num_writes; ++i) {
514 StringBuffer<150> key;
515 key << "key_" << i;
516 INF("PUT #%zu for key %s with value %zu", i, key.c_str(), i);
517
518 size_t value = i + 77; // Prevent accidental pass with zero.
519 EXPECT_OK(kvs.Put(key.view(), value));
520 EXPECT_EQ(kvs.size(), i + 1);
521 }
522 kvs.LogDebugInfo();
523 flash.Dump("WritingMultipleKeysIncreasesSize.bin");
524}
525
526TEST(InMemoryKvs, WriteAndReadOneKey) {
527 // Create and erase the fake flash.
528 Flash flash;
529 ASSERT_OK(flash.partition.Erase());
530
531 // Create and initialize the KVS.
532 constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
533 KeyValueStore kvs(&flash.partition, format);
534 ASSERT_OK(kvs.Init());
535
536 // Add two entries with different keys and values.
537 const char* key = "Key1";
538 INF("PUT value for key: %s", key);
539 uint8_t written_value = 0xDA;
540 ASSERT_OK(kvs.Put(key, written_value));
541 EXPECT_EQ(kvs.size(), 1u);
542
543 INF("GET value for key: %s", key);
544 uint8_t actual_value;
545 ASSERT_OK(kvs.Get(key, &actual_value));
546 EXPECT_EQ(actual_value, written_value);
547
548 EXPECT_EQ(kvs.size(), 1u);
549}
550
551TEST(InMemoryKvs, Basic) {
552 const char* key1 = "Key1";
553 const char* key2 = "Key2";
554
555 // Create and erase the fake flash.
556 Flash flash;
557 ASSERT_EQ(Status::OK, flash.partition.Erase());
558
559 // Create and initialize the KVS.
560 constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
561 KeyValueStore kvs(&flash.partition, format);
562 ASSERT_OK(kvs.Init());
563
564 // Add two entries with different keys and values.
565 INF("PUT first value");
566 uint8_t value1 = 0xDA;
567 ASSERT_OK(kvs.Put(key1, as_bytes(span(&value1, sizeof(value1)))));
568 EXPECT_EQ(kvs.size(), 1u);
569
570 INF("PUT second value");
571 uint32_t value2 = 0xBAD0301f;
572 ASSERT_OK(kvs.Put(key2, value2));
573 EXPECT_EQ(kvs.size(), 2u);
574
575 INF("--------------------------------");
576 INF("GET second value");
577 // Verify data
578 uint32_t test2;
579 EXPECT_OK(kvs.Get(key2, &test2));
580
581 INF("GET first value");
582 uint8_t test1;
583 ASSERT_OK(kvs.Get(key1, &test1));
584
585 EXPECT_EQ(test1, value1);
586 EXPECT_EQ(test2, value2);
587
588 EXPECT_EQ(kvs.size(), 2u);
589}
590
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800591TEST_F(KeyValueStoreTest, MaxKeyLength) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800592 // Add some data
593 char key[16] = "123456789abcdef"; // key length 15 (without \0)
594 int value = 1;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800595 ASSERT_EQ(Status::OK, kvs_.Put(key, value));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800596
597 // Verify data
598 int test = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800599 ASSERT_EQ(Status::OK, kvs_.Get(key, &test));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800600 EXPECT_EQ(test, value);
601
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800602 // Delete a key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800603 kvs_.Delete(key);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800604
605 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800606 EXPECT_EQ(kvs_.Get(key, &test), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800607}
608
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800609TEST_F(KeyValueStoreTest, LargeBuffers) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800610 // Note this assumes that no other keys larger then key0
611 static_assert(sizeof(keys[0]) >= sizeof(keys[1]) &&
612 sizeof(keys[0]) >= sizeof(keys[2]));
613 KvsAttributes kvs_attr(std::strlen(keys[0]), buffer.size());
614
615 // Verify the data will fit in this test partition. This checks that all the
616 // keys chunks will fit and a header for each sector will fit. It requires 1
617 // empty sector also.
618 const size_t kAllChunkSize = kvs_attr.MinPutSize() * keys.size();
619 const size_t kAllSectorHeaderSizes =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800620 kvs_attr.SectorHeaderSize() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800621 const size_t kMinSize = kAllChunkSize + kAllSectorHeaderSizes;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800622 const size_t kAvailSectorSpace =
623 test_partition.sector_size_bytes() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800624 if (kAvailSectorSpace < kMinSize) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800625 PW_LOG_INFO("KVS too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800626 return;
627 }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800628
629 // Add and verify
630 for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800631 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800632 ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer));
633 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800634 for (unsigned verify_idx = 0; verify_idx <= add_idx; verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800635 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800636 ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800637 for (unsigned i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800638 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800639 }
640 }
641 }
642
643 // Erase and verify
644 for (unsigned erase_idx = 0; erase_idx < keys.size(); erase_idx++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800645 ASSERT_EQ(Status::OK, kvs_.Delete(keys[erase_idx]));
646 EXPECT_EQ(kvs_.size(), keys.size() - erase_idx - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800647 for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800648 std::memset(buffer.data(), 0, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800649 if (verify_idx <= erase_idx) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800650 ASSERT_EQ(kvs_.Get(keys[verify_idx], buffer).status(),
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800651 Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800652 } else {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800653 ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800654 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800655 EXPECT_EQ(buffer[i], static_cast<byte>(verify_idx));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800656 }
657 }
658 }
659 }
660}
661
Wyatt Hepler595cf012020-02-05 09:31:02 -0800662TEST_F(KeyValueStoreTest, Enable) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800663 KvsAttributes kvs_attr(std::strlen(keys[0]), buffer.size());
664
665 // Verify the data will fit in this test partition. This checks that all the
666 // keys chunks will fit and a header for each sector will fit. It requires 1
667 // empty sector also.
668 const size_t kAllChunkSize = kvs_attr.MinPutSize() * keys.size();
669 const size_t kAllSectorHeaderSizes =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800670 kvs_attr.SectorHeaderSize() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800671 const size_t kMinSize = kAllChunkSize + kAllSectorHeaderSizes;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800672 const size_t kAvailSectorSpace =
673 test_partition.sector_size_bytes() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800674 if (kAvailSectorSpace < kMinSize) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800675 PW_LOG_INFO("KVS too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800676 return;
677 }
678
Wyatt Heplerb7609542020-01-24 10:29:54 -0800679 // Add some items
680 for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800681 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800682 ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer));
683 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800684 }
685
686 // Enable different KVS which should be able to properly setup the same map
687 // from what is stored in flash.
Wyatt Hepler2e568872020-02-03 18:00:00 -0800688 static KeyValueStore kvs_local(&test_partition, format);
689 ASSERT_EQ(Status::OK, kvs_local.Init());
690 EXPECT_EQ(kvs_local.size(), keys.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800691
692 // Ensure adding to new KVS works
693 uint8_t value = 0xDA;
694 const char* key = "new_key";
Wyatt Hepler2e568872020-02-03 18:00:00 -0800695 ASSERT_EQ(Status::OK, kvs_local.Put(key, value));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800696 uint8_t test;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800697 ASSERT_EQ(Status::OK, kvs_local.Get(key, &test));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800698 EXPECT_EQ(value, test);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800699 EXPECT_EQ(kvs_local.size(), keys.size() + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800700
701 // Verify previous data
702 for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800703 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800704 ASSERT_EQ(Status::OK, kvs_local.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800705 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800706 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800707 }
708 }
709}
710
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800711TEST_F(KeyValueStoreTest, MultiSector) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800712 // Calculate number of elements to ensure multiple sectors are required.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800713 uint16_t add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800714
Wyatt Hepler2e568872020-02-03 18:00:00 -0800715 if (kvs_.max_size() < add_count) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800716 PW_LOG_INFO("Sector size too large, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800717 return; // this chip has very large sectors, test won't work
718 }
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800719 if (test_partition.sector_count() < 3) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800720 PW_LOG_INFO("Not enough sectors, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800721 return; // need at least 3 sectors for multi-sector test
722 }
723
724 char key[20];
725 for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800726 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800727 snprintf(key, sizeof(key), "key_%u", add_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800728 ASSERT_EQ(Status::OK, kvs_.Put(key, buffer));
729 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800730 }
731
732 for (unsigned verify_idx = 0; verify_idx < add_count; verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800733 std::memset(buffer.data(), 0, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800734 snprintf(key, sizeof(key), "key_%u", verify_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800735 ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800736 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800737 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800738 }
739 }
740
741 // Check erase
742 for (unsigned erase_idx = 0; erase_idx < add_count; erase_idx++) {
743 snprintf(key, sizeof(key), "key_%u", erase_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800744 ASSERT_EQ(Status::OK, kvs_.Delete(key));
745 EXPECT_EQ(kvs_.size(), add_count - erase_idx - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800746 }
747}
748
Wyatt Hepler595cf012020-02-05 09:31:02 -0800749TEST_F(KeyValueStoreTest, RewriteValue) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800750 // Write first value
751 const uint8_t kValue1 = 0xDA;
752 const uint8_t kValue2 = 0x12;
753 const char* key = "the_key";
Wyatt Hepler2e568872020-02-03 18:00:00 -0800754 ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue1, 1))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800755
756 // Verify
757 uint8_t value;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800758 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800759 kvs_.Get(key, as_writable_bytes(span(&value, 1))).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800760 EXPECT_EQ(kValue1, value);
761
762 // Write new value for key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800763 ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue2, 1))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800764
765 // Verify
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800766 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800767 kvs_.Get(key, as_writable_bytes(span(&value, 1))).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800768 EXPECT_EQ(kValue2, value);
769
770 // Verify only 1 element exists
Wyatt Hepler2e568872020-02-03 18:00:00 -0800771 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800772}
773
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800774#if 0 // Offset reads are not yet supported
775
Wyatt Heplerb7609542020-01-24 10:29:54 -0800776TEST_F(KeyValueStoreTest, OffsetRead) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800777 const char* key = "the_key";
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800778 constexpr size_t kReadSize = 16; // needs to be a multiple of alignment
779 constexpr size_t kTestBufferSize = kReadSize * 10;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800780 ASSERT_GT(buffer.size(), kTestBufferSize);
781 ASSERT_LE(kTestBufferSize, 0xFF);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800782
783 // Write the entire buffer
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800784 for (size_t i = 0; i < kTestBufferSize; i++) {
785 buffer[i] = byte(i);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800786 }
Wyatt Hepler2e568872020-02-03 18:00:00 -0800787 ASSERT_EQ(Status::OK, kvs_.Put(key, span(buffer.data(), kTestBufferSize)));
788 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800789
790 // Read in small chunks and verify
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800791 for (unsigned i = 0; i < kTestBufferSize / kReadSize; i++) {
792 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800793 ASSERT_EQ(
794 Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800795 kvs_.Get(key, span(buffer.data(), kReadSize), i * kReadSize).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800796 for (unsigned j = 0; j < kReadSize; j++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800797 ASSERT_EQ(static_cast<unsigned>(buffer[j]), j + i * kReadSize);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800798 }
799 }
800}
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800801#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -0800802
Wyatt Hepler595cf012020-02-05 09:31:02 -0800803TEST_F(KeyValueStoreTest, MultipleRewrite) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800804 // Calculate number of elements to ensure multiple sectors are required.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800805 unsigned add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800806
807 const char* key = "the_key";
808 constexpr uint8_t kGoodVal = 0x60;
809 constexpr uint8_t kBadVal = 0xBA;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800810 std::memset(buffer.data(), kBadVal, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800811 for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
812 if (add_idx == add_count - 1) { // last value
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800813 std::memset(buffer.data(), kGoodVal, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800814 }
Wyatt Hepler2e568872020-02-03 18:00:00 -0800815 ASSERT_EQ(Status::OK, kvs_.Put(key, buffer));
816 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800817 }
818
819 // Verify
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800820 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800821 ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800822 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800823 ASSERT_EQ(buffer[i], static_cast<byte>(kGoodVal));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800824 }
825}
826
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800827TEST_F(KeyValueStoreTest, FillSector) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800828 ASSERT_EQ(std::strlen(keys[0]), 8U); // Easier for alignment
829 ASSERT_EQ(std::strlen(keys[2]), 8U); // Easier for alignment
830 constexpr size_t kTestDataSize = 8;
831 KvsAttributes kvs_attr(std::strlen(keys[2]), kTestDataSize);
832 int bytes_remaining =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800833 test_partition.sector_size_bytes() - kvs_attr.SectorHeaderSize();
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800834 constexpr byte kKey0Pattern = byte{0xBA};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800835
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800836 std::memset(
837 buffer.data(), static_cast<int>(kKey0Pattern), kvs_attr.DataSize());
838 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800839 kvs_.Put(keys[0], span(buffer.data(), kvs_attr.DataSize())));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800840 bytes_remaining -= kvs_attr.MinPutSize();
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800841 std::memset(buffer.data(), 1, kvs_attr.DataSize());
842 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800843 kvs_.Put(keys[2], span(buffer.data(), kvs_attr.DataSize())));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800844 bytes_remaining -= kvs_attr.MinPutSize();
Wyatt Hepler2e568872020-02-03 18:00:00 -0800845 EXPECT_EQ(kvs_.size(), 2u);
846 ASSERT_EQ(Status::OK, kvs_.Delete(keys[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800847 bytes_remaining -= kvs_attr.EraseSize();
Wyatt Hepler2e568872020-02-03 18:00:00 -0800848 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800849
850 // Intentionally adding erase size to trigger sector cleanup
851 bytes_remaining += kvs_attr.EraseSize();
852 FillKvs(keys[2], bytes_remaining);
853
854 // Verify key[0]
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800855 std::memset(buffer.data(), 0, kvs_attr.DataSize());
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800856 ASSERT_EQ(
857 Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800858 kvs_.Get(keys[0], span(buffer.data(), kvs_attr.DataSize())).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800859 for (uint32_t i = 0; i < kvs_attr.DataSize(); i++) {
860 EXPECT_EQ(buffer[i], kKey0Pattern);
861 }
862}
863
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800864TEST_F(KeyValueStoreTest, Interleaved) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800865 const uint8_t kValue1 = 0xDA;
866 const uint8_t kValue2 = 0x12;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800867 uint8_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800868 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue1));
869 EXPECT_EQ(kvs_.size(), 1u);
870 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
871 EXPECT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
872 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], as_bytes(span(&kValue1, 1))));
873 ASSERT_EQ(Status::OK, kvs_.Put(keys[2], kValue2));
874 ASSERT_EQ(Status::OK, kvs_.Delete(keys[1]));
875 EXPECT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800876 EXPECT_EQ(kValue2, value);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800877
Wyatt Hepler2e568872020-02-03 18:00:00 -0800878 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800879}
880
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800881TEST_F(KeyValueStoreTest, DISABLED_BadCrc) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800882 static constexpr uint32_t kTestPattern = 0xBAD0301f;
883 // clang-format off
884 // There is a top and bottom because for each because we don't want to write
885 // the erase 0xFF, especially on encrypted flash.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800886 static constexpr auto kKvsTestDataAligned1Top = ByteArray(
887 0xCD, 0xAB, 0x03, 0x00, 0x01, 0x00, 0xFF, 0xFF // Sector Header
888 );
889 static constexpr auto kKvsTestDataAligned1Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800890 0xAA, 0x55, 0xBA, 0xDD, 0x00, 0x00, 0x18, 0x00, // header (BAD CRC)
891 0x54, 0x65, 0x73, 0x74, 0x4B, 0x65, 0x79, 0x31, // Key (keys[0])
892 0xDA, // Value
893 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // Header (GOOD CRC)
894 0x4B, 0x65, 0x79, 0x32, // Key (keys[1])
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800895 0x1F, 0x30, 0xD0, 0xBA); // Value
896 static constexpr auto kKvsTestDataAligned2Top = ByteArray(
897 0xCD, 0xAB, 0x03, 0x00, 0x02, 0x00, 0xFF, 0xFF // Sector Header
898 );
899 static constexpr auto kKvsTestDataAligned2Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800900 0xAA, 0x55, 0xBA, 0xDD, 0x00, 0x00, 0x18, 0x00, // header (BAD CRC)
901 0x54, 0x65, 0x73, 0x74, 0x4B, 0x65, 0x79, 0x31, // Key (keys[0])
902 0xDA, 0x00, // Value + padding
903 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // Header (GOOD CRC)
904 0x4B, 0x65, 0x79, 0x32, // Key (keys[1])
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800905 0x1F, 0x30, 0xD0, 0xBA // Value
Keir Mierle8c352dc2020-02-02 13:58:19 -0800906 );
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800907 static constexpr auto kKvsTestDataAligned8Top = ByteArray(
908 0xCD, 0xAB, 0x03, 0x00, 0x08, 0x00, 0xFF, 0xFF // Sector Header
909 );
910 static constexpr auto kKvsTestDataAligned8Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800911 0xAA, 0x55, 0xBA, 0xDD, 0x00, 0x00, 0x18, 0x00, // header (BAD CRC)
912 0x54, 0x65, 0x73, 0x74, 0x4B, 0x65, 0x79, 0x31, // Key (keys[0])
913 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Value + padding
914 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // header (GOOD CRC)
915 0x4B, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, // Key (keys[1])
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800916 0x1F, 0x30, 0xD0, 0xBA, 0x00, 0x00, 0x00, 0x00 // Value + padding
917 );
918 static constexpr auto kKvsTestDataAligned16Top = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800919 0xCD, 0xAB, 0x03, 0x00, 0x10, 0x00, 0xFF, 0xFF, // Sector Header
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Alignment to 16
921 );
922 static constexpr auto kKvsTestDataAligned16Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800923 0xAA, 0x55, 0xBA, 0xDD, 0x00, 0x00, 0x18, 0x00, // header (BAD CRC)
924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
925 0x54, 0x65, 0x73, 0x74, 0x4B, 0x65, 0x79, 0x31, // Key (keys[0])
926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
927 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Value + padding
928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
929 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // header (GOOD CRC)
930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
931 0x4B, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, // Key (keys[1])
932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
933 0x1F, 0x30, 0xD0, 0xBA, 0x00, 0x00, 0x00, 0x00, // Value + padding
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Alignment to 16
935 );
Wyatt Heplerb7609542020-01-24 10:29:54 -0800936 // clang-format on
Wyatt Heplerb7609542020-01-24 10:29:54 -0800937
938 // We don't actually care about the size values provided, since we are only
939 // using kvs_attr to get Sector Size
940 KvsAttributes kvs_attr(8, 8);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800941 if (test_partition.alignment_bytes() == 1) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800942 ASSERT_EQ(Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800943 test_partition.Write(0, kKvsTestDataAligned1Top).status());
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800944 ASSERT_EQ(
945 Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800946 test_partition
947 .Write(kvs_attr.SectorHeaderSize(), kKvsTestDataAligned1Bottom)
948 .status());
949 } else if (test_partition.alignment_bytes() == 2) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800950 ASSERT_EQ(Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800951 test_partition.Write(0, kKvsTestDataAligned2Top).status());
952 ASSERT_EQ(
953 Status::OK,
954 test_partition
955 .Write(kvs_attr.SectorHeaderSize(), kKvsTestDataAligned2Bottom)
956 .status());
957 } else if (test_partition.alignment_bytes() == 8) {
958 ASSERT_EQ(Status::OK,
959 test_partition.Write(0, kKvsTestDataAligned8Top).status());
960 ASSERT_EQ(
961 Status::OK,
962 test_partition
963 .Write(kvs_attr.SectorHeaderSize(), kKvsTestDataAligned8Bottom)
964 .status());
965 } else if (test_partition.alignment_bytes() == 16) {
966 ASSERT_EQ(Status::OK,
967 test_partition.Write(0, kKvsTestDataAligned16Top).status());
968 ASSERT_EQ(
969 Status::OK,
970 test_partition
971 .Write(kvs_attr.SectorHeaderSize(), kKvsTestDataAligned16Bottom)
972 .status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800973 } else {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800974 PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
975 ASSERT_EQ(Status::OK, false);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800976 }
977
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800978 EXPECT_EQ(Status::DATA_LOSS,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800979 kvs_.Get(keys[0], span(buffer.data(), 1)).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800980
981 // Value with correct CRC should still be available.
982 uint32_t test2 = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800983 ASSERT_EQ(Status::OK, kvs_.Get(keys[1], &test2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800984 EXPECT_EQ(kTestPattern, test2);
985
986 // Test rewriting over corrupted data.
Wyatt Hepler2e568872020-02-03 18:00:00 -0800987 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kTestPattern));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800988 test2 = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800989 EXPECT_EQ(Status::OK, kvs_.Get(keys[0], &test2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800990 EXPECT_EQ(kTestPattern, test2);
991
992 // Check correct when re-enabled
Wyatt Hepler2e568872020-02-03 18:00:00 -0800993 EXPECT_EQ(kvs_.Init(), Status::OK);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800994 test2 = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800995 EXPECT_EQ(Status::OK, kvs_.Get(keys[0], &test2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800996 EXPECT_EQ(kTestPattern, test2);
997}
998
Wyatt Hepler595cf012020-02-05 09:31:02 -0800999TEST_F(KeyValueStoreTest, TestVersion2) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001000 static constexpr uint32_t kTestPattern = 0xBAD0301f;
1001 // Since this test is not run on encypted flash, we can write the clean
1002 // pending flag for just this test.
1003 static constexpr uint8_t kKvsTestDataAligned1[] = {
1004 0xCD, 0xAB, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, // Sector Header
1005 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Clean pending flag
1006 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // Header (GOOD CRC)
1007 0x4B, 0x65, 0x79, 0x32, // Key (keys[1])
1008 0x1F, 0x30, 0xD0, 0xBA}; // Value
1009
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001010 if (test_partition.alignment_bytes() == 1) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001011 // Test only runs on 1 byte alignment partitions
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001012 test_partition.Erase(0, test_partition.sector_count());
1013 test_partition.Write(0, as_bytes(span(kKvsTestDataAligned1)));
Wyatt Hepler2e568872020-02-03 18:00:00 -08001014 EXPECT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001015 uint32_t test2 = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001016 ASSERT_EQ(Status::OK,
1017 kvs_.Get(keys[1], as_writable_bytes(span(&test2, 1))).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001018 EXPECT_EQ(kTestPattern, test2);
1019 }
1020}
1021
Wyatt Hepler6c24c062020-02-05 15:30:49 -08001022TEST_F(KeyValueStoreTest, DeleteAndReinitialize) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001023 // Write value
1024 const uint8_t kValue = 0xDA;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001025 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001026
Wyatt Hepler2e568872020-02-03 18:00:00 -08001027 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001028 uint8_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001029 ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001030
1031 // Reset KVS, ensure captured at enable
Wyatt Hepler2e568872020-02-03 18:00:00 -08001032 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001033
Wyatt Hepler2e568872020-02-03 18:00:00 -08001034 ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001035}
1036
Wyatt Hepler595cf012020-02-05 09:31:02 -08001037TEST_F(KeyValueStoreTest, TemplatedPutAndGet) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001038 // Store a value with the convenience method.
1039 const uint32_t kValue = 0x12345678;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001040 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001041
1042 // Read it back with the other convenience method.
1043 uint32_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001044 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001045 ASSERT_EQ(kValue, value);
1046
1047 // Make sure we cannot get something where size isn't what we expect
1048 const uint8_t kSmallValue = 0xBA;
1049 uint8_t small_value = kSmallValue;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001050 ASSERT_EQ(kvs_.Get(keys[0], &small_value), Status::INVALID_ARGUMENT);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001051 ASSERT_EQ(small_value, kSmallValue);
1052}
1053
Wyatt Hepler6c24c062020-02-05 15:30:49 -08001054TEST_F(KeyValueStoreTest, Delete) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001055 static constexpr uint32_t kTestPattern = 0xBAD0301f;
1056 // clang-format off
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001057 static constexpr auto kKvsTestDataAligned1Top = ByteArray(
1058 0xCD, 0xAB, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF // Sector Header
1059 );
1060 static constexpr auto kKvsTestDataAligned1Bottom = ByteArray(
1061 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // Header (GOOD CRC)
1062 0x4B, 0x65, 0x79, 0x32, // Key (keys[1])
1063 0x1F, 0x30, 0xD0, 0xBA // Value
1064 );
1065 static constexpr auto kKvsTestDataAligned2Top = ByteArray(
1066 0xCD, 0xAB, 0x03, 0x00, 0x02, 0x00, 0xFF, 0xFF // Sector Header
1067 );
1068 static constexpr auto kKvsTestDataAligned2Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -08001069 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // Header (GOOD CRC)
1070 0x4B, 0x65, 0x79, 0x32, // Key (keys[1])
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001071 0x1F, 0x30, 0xD0, 0xBA // Value
1072 );
1073 static constexpr auto kKvsTestDataAligned8Top = ByteArray(
1074 0xCD, 0xAB, 0x03, 0x00, 0x08, 0x00, 0xFF, 0xFF // Sector Header
1075 );
1076 static constexpr auto kKvsTestDataAligned8Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -08001077 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // header (GOOD CRC)
1078 0x4B, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, // Key (keys[1])
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001079 0x1F, 0x30, 0xD0, 0xBA, 0x00, 0x00, 0x00, 0x00 // Value + padding
1080 );
1081 static constexpr auto kKvsTestDataAligned16Top = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -08001082 0xCD, 0xAB, 0x03, 0x00, 0x10, 0x00, 0xFF, 0xFF, // Sector Header
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Alignment to 16
1084 );
1085 static constexpr auto kKvsTestDataAligned16Bottom = ByteArray(
Wyatt Heplerb7609542020-01-24 10:29:54 -08001086 0xAA, 0x55, 0xB5, 0x87, 0x00, 0x00, 0x44, 0x00, // header (GOOD CRC)
1087 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
1088 0x4B, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, // Key (keys[1])
1089 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
1090 0x1F, 0x30, 0xD0, 0xBA, 0x00, 0x00, 0x00, 0x00, // Value + padding
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Alignment to 16
1092 );
Wyatt Heplerb7609542020-01-24 10:29:54 -08001093 // clang-format on
1094
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001095 ASSERT_EQ(Status::OK, test_partition.Erase(0, test_partition.sector_count()));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001096 // We don't actually care about the size values provided, since we are only
1097 // using kvs_attr to get Sector Size
1098 KvsAttributes kvs_attr(8, 8);
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001099 FlashPartition::Address address = kvs_attr.SectorHeaderSize();
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001100 if (test_partition.alignment_bytes() == 1) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001101 ASSERT_EQ(Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001102 test_partition.Write(0, kKvsTestDataAligned1Top).status());
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001103 ASSERT_EQ(
1104 Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001105 test_partition.Write(address, kKvsTestDataAligned1Bottom).status());
1106 address += sizeof(kKvsTestDataAligned1Bottom);
1107 } else if (test_partition.alignment_bytes() == 2) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001108 ASSERT_EQ(Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001109 test_partition.Write(0, kKvsTestDataAligned2Top).status());
1110 ASSERT_EQ(
1111 Status::OK,
1112 test_partition.Write(address, kKvsTestDataAligned2Bottom).status());
1113 address += sizeof(kKvsTestDataAligned2Bottom);
1114 } else if (test_partition.alignment_bytes() == 8) {
1115 ASSERT_EQ(Status::OK,
1116 test_partition.Write(0, kKvsTestDataAligned8Top).status());
1117 ASSERT_EQ(
1118 Status::OK,
1119 test_partition.Write(address, kKvsTestDataAligned8Bottom).status());
1120 address += sizeof(kKvsTestDataAligned8Bottom);
1121 } else if (test_partition.alignment_bytes() == 16) {
1122 ASSERT_EQ(Status::OK,
1123 test_partition.Write(0, kKvsTestDataAligned16Top).status());
1124 ASSERT_EQ(
1125 Status::OK,
1126 test_partition.Write(address, kKvsTestDataAligned16Bottom).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001127 address += sizeof(kKvsTestDataAligned16Bottom);
1128 } else {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001129 PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001130 ASSERT_EQ(true, false);
1131 }
1132
Wyatt Heplerb7609542020-01-24 10:29:54 -08001133 // Put in same key/value pair
Wyatt Hepler2e568872020-02-03 18:00:00 -08001134 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], kTestPattern));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001135
1136 bool is_erased = false;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001137 ASSERT_EQ(Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001138 test_partition.IsRegionErased(
1139 address, test_partition.alignment_bytes(), &is_erased));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001140 EXPECT_EQ(is_erased, true);
1141}
1142
1143// This test is derived from bug that was discovered. Testing this corner case
1144// relies on creating a new key-value just under the size that is left over in
1145// the sector.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001146TEST_F(KeyValueStoreTest, DISABLED_FillSector2) {
1147 if (test_partition.sector_count() < 3) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001148 PW_LOG_INFO("Not enough sectors, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001149 return; // need at least 3 sectors
1150 }
1151
Wyatt Heplerb7609542020-01-24 10:29:54 -08001152 // Start of by filling flash sector to near full
1153 constexpr int kHalfBufferSize = buffer.size() / 2;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001154 const int kSizeToFill = test_partition.sector_size_bytes() - kHalfBufferSize;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001155 constexpr size_t kTestDataSize = 8;
1156 KvsAttributes kvs_attr(std::strlen(keys[2]), kTestDataSize);
1157
1158 FillKvs(keys[2], kSizeToFill);
1159
1160 // Find out how much space is remaining for new key-value and confirm it
1161 // makes sense.
1162 size_t new_keyvalue_size = 0;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001163 size_t alignment = test_partition.alignment_bytes();
Wyatt Heplerb7609542020-01-24 10:29:54 -08001164 // Starts on second sector since it will try to keep first sector free
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001165 FlashPartition::Address read_address =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001166 2 * test_partition.sector_size_bytes() - alignment;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001167 for (; read_address > 0; read_address -= alignment) {
1168 bool is_erased = false;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001169 ASSERT_EQ(
1170 Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001171 test_partition.IsRegionErased(read_address, alignment, &is_erased));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001172 if (is_erased) {
1173 new_keyvalue_size += alignment;
1174 } else {
1175 break;
1176 }
1177 }
1178
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001179 size_t expected_remaining = test_partition.sector_size_bytes() -
Wyatt Heplerb7609542020-01-24 10:29:54 -08001180 kvs_attr.SectorHeaderSize() - kSizeToFill;
1181 ASSERT_EQ(new_keyvalue_size, expected_remaining);
1182
1183 const char* kNewKey = "NewKey";
1184 constexpr size_t kValueLessThanChunkHeaderSize = 2;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001185 constexpr auto kTestPattern = byte{0xBA};
Wyatt Heplerb7609542020-01-24 10:29:54 -08001186 new_keyvalue_size -= kValueLessThanChunkHeaderSize;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001187 std::memset(buffer.data(), static_cast<int>(kTestPattern), new_keyvalue_size);
1188 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001189 kvs_.Put(kNewKey, span(buffer.data(), new_keyvalue_size)));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001190
1191 // In failed corner case, adding new key is deceptively successful. It isn't
1192 // until KVS is disabled and reenabled that issue can be detected.
Wyatt Hepler2e568872020-02-03 18:00:00 -08001193 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001194
1195 // Might as well check that new key-value is what we expect it to be
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001196 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001197 kvs_.Get(kNewKey, span(buffer.data(), new_keyvalue_size)).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001198 for (size_t i = 0; i < new_keyvalue_size; i++) {
1199 EXPECT_EQ(buffer[i], kTestPattern);
1200 }
1201}
1202
Wyatt Heplered163b02020-02-03 17:49:32 -08001203TEST_F(KeyValueStoreTest, ValueSize_Positive) {
1204 constexpr auto kData = ByteArray('h', 'i', '!');
1205 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", kData));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001206
Wyatt Heplered163b02020-02-03 17:49:32 -08001207 auto result = kvs_.ValueSize("TheKey");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001208
Wyatt Heplered163b02020-02-03 17:49:32 -08001209 EXPECT_EQ(Status::OK, result.status());
1210 EXPECT_EQ(kData.size(), result.size());
1211}
Wyatt Heplerb7609542020-01-24 10:29:54 -08001212
Wyatt Heplered163b02020-02-03 17:49:32 -08001213TEST_F(KeyValueStoreTest, ValueSize_Zero) {
1214 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", as_bytes(span("123", 3))));
1215 auto result = kvs_.ValueSize("TheKey");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001216
Wyatt Heplered163b02020-02-03 17:49:32 -08001217 EXPECT_EQ(Status::OK, result.status());
1218 EXPECT_EQ(3u, result.size());
1219}
Wyatt Heplerb7609542020-01-24 10:29:54 -08001220
Wyatt Heplered163b02020-02-03 17:49:32 -08001221TEST_F(KeyValueStoreTest, ValueSize_InvalidKey) {
1222 EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.ValueSize("").status());
1223}
1224
1225TEST_F(KeyValueStoreTest, ValueSize_MissingKey) {
1226 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("Not in there").status());
1227}
1228
Wyatt Hepler6c24c062020-02-05 15:30:49 -08001229TEST_F(KeyValueStoreTest, ValueSize_DeletedKey) {
Wyatt Heplered163b02020-02-03 17:49:32 -08001230 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", as_bytes(span("123", 3))));
1231 ASSERT_EQ(Status::OK, kvs_.Delete("TheKey"));
1232
1233 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("TheKey").status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001234}
1235
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001236#if 0 // TODO: not CanFitEntry function yet
1237TEST_F(KeyValueStoreTest, DISABLED_CanFitEntryTests) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001238 // Get exactly the number of bytes that can fit in the space remaining for
1239 // a large value, accounting for alignment.
1240 constexpr uint16_t kTestKeySize = 2;
1241 size_t space_remaining =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001242 test_partition.sector_size_bytes() //
1243 - RoundUpForAlignment(sizeof(EntryHeader)) // TODO: Sector Header
1244 - RoundUpForAlignment(sizeof(EntryHeader)) // Cleaning Header
1245 - RoundUpForAlignment(sizeof(EntryHeader)) // TODO: Chunk Header
Wyatt Heplerb7609542020-01-24 10:29:54 -08001246 - RoundUpForAlignment(kTestKeySize);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001247 space_remaining -= test_partition.alignment_bytes() / 2;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001248 space_remaining = RoundUpForAlignment(space_remaining);
1249
Wyatt Hepler2e568872020-02-03 18:00:00 -08001250 EXPECT_TRUE(kvs_.CanFitEntry(kTestKeySize, space_remaining));
1251 EXPECT_FALSE(kvs_.CanFitEntry(kTestKeySize, space_remaining + 1));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001252}
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001253#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001254
Wyatt Hepler6e3a83b2020-02-04 07:36:45 -08001255TEST_F(KeyValueStoreTest, DifferentValueSameCrc16) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001256 const char kKey[] = "k";
1257 // With the key and our CRC16 algorithm these both have CRC of 0x82AE
1258 // Given they are the same size and same key, the KVS will need to check
1259 // the actual bits to know they are different.
1260 const char kValue1[] = {'d', 'a', 't'};
1261 const char kValue2[] = {'u', 'c', 'd'};
1262
1263 // Verify the CRC matches
1264 ASSERT_EQ(CalcKvsCrc(kKey, kValue1, sizeof(kValue1)),
1265 CalcKvsCrc(kKey, kValue2, sizeof(kValue2)));
1266
Wyatt Hepler2e568872020-02-03 18:00:00 -08001267 ASSERT_EQ(Status::OK, kvs_.Put(kKey, kValue1));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001268
1269 // Now try to rewrite with the similar value.
Wyatt Hepler2e568872020-02-03 18:00:00 -08001270 ASSERT_EQ(Status::OK, kvs_.Put(kKey, kValue2));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001271
1272 // Read it back and check it is correct
Wyatt Hepler6e3a83b2020-02-04 07:36:45 -08001273 char value[3] = {};
Wyatt Hepler2e568872020-02-03 18:00:00 -08001274 ASSERT_EQ(Status::OK, kvs_.Get(kKey, &value));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001275 ASSERT_EQ(std::memcmp(value, kValue2, sizeof(value)), 0);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001276}
1277
Wyatt Hepler6c24c062020-02-05 15:30:49 -08001278TEST_F(KeyValueStoreTest, CallingEraseTwice) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001279 const uint8_t kValue = 0xDA;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001280 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
1281 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001282 uint16_t crc = CalcTestPartitionCrc();
Wyatt Hepler2e568872020-02-03 18:00:00 -08001283 EXPECT_EQ(kvs_.Delete(keys[0]), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001284 // Verify the flash has not changed
1285 EXPECT_EQ(crc, CalcTestPartitionCrc());
1286}
1287
1288void __attribute__((noinline)) StackHeavyPartialClean() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001289#if 0 // TODO: No FlashSubPartition
1290
1291 ASSERT_GE(test_partition.sector_count(), 2);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001292 FlashSubPartition test_partition_sector1(&test_partition, 0, 1);
1293 FlashSubPartition test_partition_sector2(&test_partition, 1, 1);
1294
1295 KeyValueStore kvs1(&test_partition_sector1);
1296 KeyValueStore kvs2(&test_partition_sector2);
1297
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001298 test_partition.Erase(0, test_partition.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001299
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001300 ASSERT_EQ(Status::OK, kvs1.Enable());
1301 ASSERT_EQ(Status::OK, kvs2.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001302
1303 int values1[3] = {100, 101, 102};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001304 ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
1305 ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
1306 ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001307
1308 int values2[3] = {200, 201, 202};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001309 ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
1310 ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001311 ASSERT_EQ(Status::OK, kvs2.Delete(keys[1]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001312
1313 kvs1.Disable();
1314 kvs2.Disable();
1315
1316 // Key 0 is value1 in first sector, value 2 in second
1317 // Key 1 is value1 in first sector, erased in second
1318 // key 2 is only in first sector
1319
1320 uint64_t mark_clean_count = 5;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001321 ASSERT_EQ(Status::OK,
1322 PaddedWrite(&test_partition_sector1,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001323 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1324 reinterpret_cast<uint8_t*>(&mark_clean_count),
1325 sizeof(uint64_t)));
1326
1327 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001328 kvs_.Disable();
1329 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001330 int value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001331 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001332 ASSERT_EQ(values2[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001333 ASSERT_EQ(kvs_.Get(keys[1], &value), Status::NOT_FOUND);
1334 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001335 ASSERT_EQ(values1[2], value);
1336
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001337 if (test_partition.sector_count() == 2) {
Wyatt Hepler2e568872020-02-03 18:00:00 -08001338 EXPECT_EQ(kvs_.PendingCleanCount(), 0u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001339 // Has forced a clean, mark again for next test
1340 return; // Not enough sectors to test 2 partial cleans.
1341 } else {
Wyatt Hepler2e568872020-02-03 18:00:00 -08001342 EXPECT_EQ(kvs_.PendingCleanCount(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001343 }
1344
1345 mark_clean_count--;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001346 ASSERT_EQ(Status::OK,
1347 PaddedWrite(&test_partition_sector2,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001348 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1349 reinterpret_cast<uint8_t*>(&mark_clean_count),
1350 sizeof(uint64_t)));
1351 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001352 kvs_.Disable();
1353 ASSERT_EQ(Status::OK, kvs_.Init());
1354 EXPECT_EQ(kvs_.PendingCleanCount(), 2u);
1355 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001356 ASSERT_EQ(values1[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001357 ASSERT_EQ(Status::OK, kvs_.Get(keys[1], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001358 ASSERT_EQ(values1[1], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001359 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001360 ASSERT_EQ(values1[2], value);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001361#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001362}
1363
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001364// TODO: This doesn't do anything, and would be unreliable anyway.
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001365size_t CurrentTaskStackFree() { return -1; }
1366
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001367TEST_F(KeyValueStoreTest, DISABLED_PartialClean) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001368 if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001369 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001370 return;
1371 }
1372 StackHeavyPartialClean();
1373}
1374
1375void __attribute__((noinline)) StackHeavyCleanAll() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001376#if 0 // TODO: no FlashSubPartition
1377 ASSERT_GE(test_partition.sector_count(), 2);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001378 FlashSubPartition test_partition_sector1(&test_partition, 0, 1);
1379
1380 KeyValueStore kvs1(&test_partition_sector1);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001381 test_partition.Erase(0, test_partition.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001382
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001383 ASSERT_EQ(Status::OK, kvs1.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001384
1385 int values1[3] = {100, 101, 102};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001386 ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
1387 ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
1388 ASSERT_EQ(Status::OK,
1389 kvs1.Put(keys[2], values1[2] - 100)); // force a rewrite
1390 ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001391
1392 kvs1.Disable();
1393
1394 uint64_t mark_clean_count = 5;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001395 ASSERT_EQ(Status::OK,
1396 PaddedWrite(&test_partition_sector1,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001397 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1398 reinterpret_cast<uint8_t*>(&mark_clean_count),
1399 sizeof(uint64_t)));
1400
1401 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001402 kvs_.Disable();
1403 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001404 int value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001405 EXPECT_EQ(kvs_.PendingCleanCount(), 1u);
1406 ASSERT_EQ(Status::OK, kvs_.CleanAll());
1407 EXPECT_EQ(kvs_.PendingCleanCount(), 0u);
1408 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001409 ASSERT_EQ(values1[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001410 ASSERT_EQ(Status::OK, kvs_.Get(keys[1], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001411 ASSERT_EQ(values1[1], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001412 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001413 ASSERT_EQ(values1[2], value);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001414#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001415}
1416
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001417TEST_F(KeyValueStoreTest, DISABLED_CleanAll) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001418 if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 1) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001419 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001420 return;
1421 }
1422 StackHeavyCleanAll();
1423}
1424
1425void __attribute__((noinline)) StackHeavyPartialCleanLargeCounts() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001426#if 0
1427 ASSERT_GE(test_partition.sector_count(), 2);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001428 FlashSubPartition test_partition_sector1(&test_partition, 0, 1);
1429 FlashSubPartition test_partition_sector2(&test_partition, 1, 1);
1430
1431 KeyValueStore kvs1(&test_partition_sector1);
1432 KeyValueStore kvs2(&test_partition_sector2);
1433
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001434 test_partition.Erase(0, test_partition.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001435
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001436 ASSERT_EQ(Status::OK, kvs1.Enable());
1437 ASSERT_EQ(Status::OK, kvs2.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001438
1439 int values1[3] = {100, 101, 102};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001440 ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
1441 ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
1442 ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001443
1444 int values2[3] = {200, 201, 202};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001445 ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
1446 ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001447 ASSERT_EQ(Status::OK, kvs2.Delete(keys[1]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001448
1449 kvs1.Disable();
1450 kvs2.Disable();
Wyatt Hepler2e568872020-02-03 18:00:00 -08001451 kvs_.Disable();
Wyatt Heplerb7609542020-01-24 10:29:54 -08001452
1453 // Key 0 is value1 in first sector, value 2 in second
1454 // Key 1 is value1 in first sector, erased in second
1455 // key 2 is only in first sector
1456
1457 uint64_t mark_clean_count = 4569877515;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001458 ASSERT_EQ(Status::OK,
1459 PaddedWrite(&test_partition_sector1,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001460 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1461 reinterpret_cast<uint8_t*>(&mark_clean_count),
1462 sizeof(uint64_t)));
1463
1464 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001465 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001466 int value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001467 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001468 ASSERT_EQ(values2[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001469 ASSERT_EQ(kvs_.Get(keys[1], &value), Status::NOT_FOUND);
1470 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001471 ASSERT_EQ(values1[2], value);
1472
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001473 if (test_partition.sector_count() == 2) {
Wyatt Hepler2e568872020-02-03 18:00:00 -08001474 EXPECT_EQ(kvs_.PendingCleanCount(), 0u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001475 // Has forced a clean, mark again for next test
1476 // Has forced a clean, mark again for next test
1477 return; // Not enough sectors to test 2 partial cleans.
1478 } else {
Wyatt Hepler2e568872020-02-03 18:00:00 -08001479 EXPECT_EQ(kvs_.PendingCleanCount(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001480 }
Wyatt Hepler2e568872020-02-03 18:00:00 -08001481 kvs_.Disable();
Wyatt Heplerb7609542020-01-24 10:29:54 -08001482
1483 mark_clean_count--;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001484 ASSERT_EQ(Status::OK,
1485 PaddedWrite(&test_partition_sector2,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001486 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1487 reinterpret_cast<uint8_t*>(&mark_clean_count),
1488 sizeof(uint64_t)));
1489 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001490 ASSERT_EQ(Status::OK, kvs_.Init());
1491 EXPECT_EQ(kvs_.PendingCleanCount(), 2u);
1492 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001493 ASSERT_EQ(values1[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001494 ASSERT_EQ(Status::OK, kvs_.Get(keys[1], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001495 ASSERT_EQ(values1[1], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001496 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001497 ASSERT_EQ(values1[2], value);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001498#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001499}
1500
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001501TEST_F(KeyValueStoreTest, DISABLED_PartialCleanLargeCounts) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001502 if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001503 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001504 return;
1505 }
1506 StackHeavyPartialCleanLargeCounts();
1507}
1508
1509void __attribute__((noinline)) StackHeavyRecoverNoFreeSectors() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001510#if 0 // TODO: no FlashSubPartition
1511 ASSERT_GE(test_partition.sector_count(), 2);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001512 FlashSubPartition test_partition_sector1(&test_partition, 0, 1);
1513 FlashSubPartition test_partition_sector2(&test_partition, 1, 1);
1514 FlashSubPartition test_partition_both(&test_partition, 0, 2);
1515
1516 KeyValueStore kvs1(&test_partition_sector1);
1517 KeyValueStore kvs2(&test_partition_sector2);
1518 KeyValueStore kvs_both(&test_partition_both);
1519
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001520 test_partition.Erase(0, test_partition.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001521
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001522 ASSERT_EQ(Status::OK, kvs1.Enable());
1523 ASSERT_EQ(Status::OK, kvs2.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001524
1525 int values[3] = {100, 101};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001526 ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001527 ASSERT_FALSE(kvs1.HasEmptySector());
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001528 ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values[1]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001529 ASSERT_FALSE(kvs2.HasEmptySector());
1530
1531 kvs1.Disable();
1532 kvs2.Disable();
1533
1534 // Reset KVS
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001535 ASSERT_EQ(Status::OK, kvs_both.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001536 ASSERT_TRUE(kvs_both.HasEmptySector());
1537 int value;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001538 ASSERT_EQ(Status::OK, kvs_both.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001539 ASSERT_EQ(values[0], value);
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001540 ASSERT_EQ(Status::OK, kvs_both.Get(keys[1], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001541 ASSERT_EQ(values[1], value);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001542#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001543}
1544
1545TEST_F(KeyValueStoreTest, RecoverNoFreeSectors) {
1546 if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 3) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001547 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001548 return;
1549 }
1550 StackHeavyRecoverNoFreeSectors();
1551}
1552
1553void __attribute__((noinline)) StackHeavyCleanOneSector() {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001554#if 0 // TODO: no FlashSubPartition
1555 ASSERT_GE(test_partition.sector_count(), 2);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001556 FlashSubPartition test_partition_sector1(&test_partition, 0, 1);
1557 FlashSubPartition test_partition_sector2(&test_partition, 1, 1);
1558
1559 KeyValueStore kvs1(&test_partition_sector1);
1560
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001561 test_partition.Erase(0, test_partition.sector_count());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001562
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001563 ASSERT_EQ(Status::OK, kvs1.Enable());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001564
1565 int values[3] = {100, 101, 102};
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001566 ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
1567 ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values[1]));
1568 ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001569
1570 kvs1.Disable();
Wyatt Hepler2e568872020-02-03 18:00:00 -08001571 kvs_.Disable();
Wyatt Heplerb7609542020-01-24 10:29:54 -08001572
1573 uint64_t mark_clean_count = 1;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001574 ASSERT_EQ(Status::OK,
1575 PaddedWrite(&test_partition_sector1,
Wyatt Heplerb7609542020-01-24 10:29:54 -08001576 RoundUpForAlignment(KeyValueStore::kHeaderSize),
1577 reinterpret_cast<uint8_t*>(&mark_clean_count),
1578 sizeof(uint64_t)));
1579
1580 // Reset KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -08001581 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001582
Wyatt Hepler2e568872020-02-03 18:00:00 -08001583 EXPECT_EQ(kvs_.PendingCleanCount(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001584
1585 bool all_sectors_have_been_cleaned = false;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001586 ASSERT_EQ(Status::OK, kvs_.CleanOneSector(&all_sectors_have_been_cleaned));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001587 EXPECT_EQ(all_sectors_have_been_cleaned, true);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001588 EXPECT_EQ(kvs_.PendingCleanCount(), 0u);
1589 ASSERT_EQ(Status::OK, kvs_.CleanOneSector(&all_sectors_have_been_cleaned));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001590 EXPECT_EQ(all_sectors_have_been_cleaned, true);
1591 int value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001592 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001593 ASSERT_EQ(values[0], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001594 ASSERT_EQ(Status::OK, kvs_.Get(keys[1], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001595 ASSERT_EQ(values[1], value);
Wyatt Hepler2e568872020-02-03 18:00:00 -08001596 ASSERT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001597 ASSERT_EQ(values[2], value);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001598#endif
Wyatt Heplerb7609542020-01-24 10:29:54 -08001599}
1600
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001601TEST_F(KeyValueStoreTest, DISABLED_CleanOneSector) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001602 if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001603 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001604 return;
1605 }
1606 StackHeavyCleanOneSector();
1607}
1608
1609#if USE_MEMORY_BUFFER
1610
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001611TEST_F(KeyValueStoreTest, DISABLED_LargePartition) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001612 if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001613 PW_LOG_ERROR("Not enough stack for test, skipping");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001614 return;
1615 }
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001616 KeyValueStore large_kvs(&large_test_partition, format);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001617
1618 const uint8_t kValue1 = 0xDA;
1619 const uint8_t kValue2 = 0x12;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001620 uint8_t value;
1621 ASSERT_EQ(Status::OK, large_kvs.Put(keys[0], kValue1));
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001622 EXPECT_EQ(large_kvs.size(), 1u);
1623 ASSERT_EQ(Status::OK, large_kvs.Delete(keys[0]));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001624 EXPECT_EQ(large_kvs.Get(keys[0], &value), Status::NOT_FOUND);
1625 ASSERT_EQ(Status::OK, large_kvs.Put(keys[1], kValue1));
1626 ASSERT_EQ(Status::OK, large_kvs.Put(keys[2], kValue2));
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001627 ASSERT_EQ(Status::OK, large_kvs.Delete(keys[1]));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001628 EXPECT_EQ(Status::OK, large_kvs.Get(keys[2], &value));
1629 EXPECT_EQ(kValue2, value);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001630 ASSERT_EQ(large_kvs.Get(keys[1], &value), Status::NOT_FOUND);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001631 EXPECT_EQ(large_kvs.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001632}
1633#endif // USE_MEMORY_BUFFER
1634
Keir Mierle8c352dc2020-02-02 13:58:19 -08001635TEST(KeyValueStoreEntryHeader, KeyValueSizes) {
1636 EntryHeader header;
1637
1638 header.set_key_length(9u);
1639 EXPECT_EQ(header.key_length(), 9u);
1640
1641 header.set_value_length(11u);
1642 EXPECT_EQ(header.value_length(), 11u);
1643
1644 header.set_key_length(6u);
1645 header.set_value_length(100u);
1646 EXPECT_EQ(header.key_length(), 6u);
1647 EXPECT_EQ(header.value_length(), 100u);
1648
1649 header.set_value_length(10u);
1650 EXPECT_EQ(header.key_length(), 6u);
1651 EXPECT_EQ(header.value_length(), 10u);
1652
1653 header.set_key_length(3u);
1654 header.set_value_length(4000u);
1655 EXPECT_EQ(header.key_length(), 3u);
1656 EXPECT_EQ(header.value_length(), 4000u);
1657}
1658
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001659} // namespace pw::kvs