blob: 9d0e3d486c31cba7ec50acd389cf8fb6152e4e09 [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
17#define PW_LOG_USE_ULTRA_SHORT_NAMES 1
18
Wyatt Heplerb7609542020-01-24 10:29:54 -080019#include "pw_kvs/key_value_store.h"
20
Wyatt Hepleracaacf92020-01-24 10:58:30 -080021#include <array>
22#include <cstdio>
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080023#include <cstring>
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"
30#include "pw_checksum/ccitt_crc16.h"
Wyatt Heplerec4b9352020-01-31 15:51:50 -080031#include "pw_kvs/crc16_checksum.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080032#include "pw_kvs/flash_memory.h"
Wyatt Heplerbdd8e5a2020-02-20 19:27:26 -080033#include "pw_kvs/internal/entry.h"
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080034#include "pw_kvs_private/byte_utils.h"
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080035#include "pw_kvs_private/macros.h"
36#include "pw_log/log.h"
Wyatt Hepler16b04522020-02-07 16:00:14 -080037#include "pw_span/span.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
41#if USE_MEMORY_BUFFER
Wyatt Hepler2ad60672020-01-21 08:00:16 -080042#include "pw_kvs/in_memory_fake_flash.h"
Wyatt Heplerb7609542020-01-24 10:29:54 -080043#endif // USE_MEMORY_BUFFER
44
Wyatt Hepler2ad60672020-01-21 08:00:16 -080045namespace pw::kvs {
Wyatt Heplerb7609542020-01-24 10:29:54 -080046namespace {
47
Wyatt Hepler1fc11042020-02-19 17:17:51 -080048using internal::EntryHeader;
Wyatt Hepleracaacf92020-01-24 10:58:30 -080049using std::byte;
50
Wyatt Hepler38ce30f2020-02-19 11:48:31 -080051constexpr size_t kMaxEntries = 256;
52constexpr size_t kMaxUsableSectors = 256;
53
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080054// Test the functions in byte_utils.h. Create a byte array with AsBytes and
55// ByteStr and check that its contents are correct.
Wyatt Hepler38ce30f2020-02-19 11:48:31 -080056constexpr std::array<char, 2> kTestArray = {'a', 'b'};
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080057
Wyatt Hepler38ce30f2020-02-19 11:48:31 -080058constexpr auto kAsBytesTest = AsBytes(
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080059 'a', uint16_t(1), uint8_t(23), kTestArray, ByteStr("c"), uint64_t(-1));
60
61static_assert(kAsBytesTest.size() == 15);
62static_assert(kAsBytesTest[0] == std::byte{'a'});
63static_assert(kAsBytesTest[1] == std::byte{1});
64static_assert(kAsBytesTest[2] == std::byte{0});
65static_assert(kAsBytesTest[3] == std::byte{23});
66static_assert(kAsBytesTest[4] == std::byte{'a'});
67static_assert(kAsBytesTest[5] == std::byte{'b'});
68static_assert(kAsBytesTest[6] == std::byte{'c'});
69static_assert(kAsBytesTest[7] == std::byte{0xff});
70static_assert(kAsBytesTest[8] == std::byte{0xff});
71static_assert(kAsBytesTest[9] == std::byte{0xff});
72static_assert(kAsBytesTest[10] == std::byte{0xff});
73static_assert(kAsBytesTest[11] == std::byte{0xff});
74static_assert(kAsBytesTest[12] == std::byte{0xff});
75static_assert(kAsBytesTest[13] == std::byte{0xff});
76static_assert(kAsBytesTest[14] == std::byte{0xff});
Wyatt Hepleracaacf92020-01-24 10:58:30 -080077
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080078// Test that the ConvertsToSpan trait correctly idenitifies types that convert
79// to span.
80static_assert(!ConvertsToSpan<int>());
81static_assert(!ConvertsToSpan<void>());
82static_assert(!ConvertsToSpan<std::byte>());
83static_assert(!ConvertsToSpan<std::byte*>());
84
85static_assert(ConvertsToSpan<std::array<int, 5>>());
86static_assert(ConvertsToSpan<decltype("Hello!")>());
87
88static_assert(ConvertsToSpan<std::string_view>());
89static_assert(ConvertsToSpan<std::string_view&>());
90static_assert(ConvertsToSpan<std::string_view&&>());
91
92static_assert(ConvertsToSpan<const std::string_view>());
93static_assert(ConvertsToSpan<const std::string_view&>());
94static_assert(ConvertsToSpan<const std::string_view&&>());
95
Wyatt Heplerfac81132020-02-27 17:26:33 -080096static_assert(ConvertsToSpan<bool[1]>());
97static_assert(ConvertsToSpan<char[35]>());
98static_assert(ConvertsToSpan<const int[35]>());
99
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800100static_assert(ConvertsToSpan<span<int>>());
101static_assert(ConvertsToSpan<span<byte>>());
102static_assert(ConvertsToSpan<span<const int*>>());
103static_assert(ConvertsToSpan<span<bool>&&>());
104static_assert(ConvertsToSpan<const span<bool>&>());
105static_assert(ConvertsToSpan<span<bool>&&>());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800106
Keir Mierle8c352dc2020-02-02 13:58:19 -0800107// This is a self contained flash unit with both memory and a single partition.
108template <uint32_t sector_size_bytes, uint16_t sector_count>
109struct FlashWithPartitionFake {
110 // Default to 16 byte alignment, which is common in practice.
111 FlashWithPartitionFake() : FlashWithPartitionFake(16) {}
112 FlashWithPartitionFake(size_t alignment_bytes)
113 : memory(alignment_bytes), partition(&memory, 0, memory.sector_count()) {}
114
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800115 FakeFlashBuffer<sector_size_bytes, sector_count> memory;
Keir Mierle8c352dc2020-02-02 13:58:19 -0800116 FlashPartition partition;
117
118 public:
Wyatt Hepler16b04522020-02-07 16:00:14 -0800119#if DUMP_KVS_STATE_TO_FILE
Keir Mierle8c352dc2020-02-02 13:58:19 -0800120 Status Dump(const char* filename) {
121 std::FILE* out_file = std::fopen(filename, "w+");
122 if (out_file == nullptr) {
123 PW_LOG_ERROR("Failed to dump to %s", filename);
124 return Status::DATA_LOSS;
125 }
126 std::vector<std::byte> out_vec(memory.size_bytes());
127 Status status =
128 memory.Read(0, pw::span<std::byte>(out_vec.data(), out_vec.size()));
129 if (status != Status::OK) {
130 fclose(out_file);
131 return status;
132 }
133
134 size_t written =
135 std::fwrite(out_vec.data(), 1, memory.size_bytes(), out_file);
136 if (written != memory.size_bytes()) {
137 PW_LOG_ERROR("Failed to dump to %s, written=%u",
138 filename,
139 static_cast<unsigned>(written));
140 status = Status::DATA_LOSS;
141 } else {
142 PW_LOG_INFO("Dumped to %s", filename);
143 status = Status::OK;
144 }
145
146 fclose(out_file);
147 return status;
148 }
149#else
Wyatt Hepler16b04522020-02-07 16:00:14 -0800150 Status Dump(const char*) { return Status::OK; }
151#endif // DUMP_KVS_STATE_TO_FILE
Keir Mierle8c352dc2020-02-02 13:58:19 -0800152};
153
154typedef FlashWithPartitionFake<4 * 128 /*sector size*/, 6 /*sectors*/> Flash;
155
Wyatt Heplerb7609542020-01-24 10:29:54 -0800156#if USE_MEMORY_BUFFER
157// Although it might be useful to test other configurations, some tests require
158// at least 3 sectors; therfore it should have this when checked in.
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800159FakeFlashBuffer<4 * 1024, 4> test_flash(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800160 16); // 4 x 4k sectors, 16 byte alignment
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800161FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800162FakeFlashBuffer<1024, 60> large_test_flash(8);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800163FlashPartition large_test_partition(&large_test_flash,
164 0,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800165 large_test_flash.sector_count());
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800166#else // TODO: Test with real flash
167FlashPartition& test_partition = FlashExternalTestPartition();
Wyatt Heplerb7609542020-01-24 10:29:54 -0800168#endif // USE_MEMORY_BUFFER
169
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800170std::array<byte, 512> buffer;
171constexpr std::array<const char*, 3> keys{"TestKey1", "Key2", "TestKey3"};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800172
Wyatt Hepler2e568872020-02-03 18:00:00 -0800173ChecksumCrc16 checksum;
Wyatt Hepler88adfe82020-02-20 19:33:27 -0800174constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = &checksum};
Wyatt Heplerb7609542020-01-24 10:29:54 -0800175
176size_t RoundUpForAlignment(size_t size) {
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800177 return AlignUp(size, test_partition.alignment_bytes());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800178}
179
180// This class gives attributes of KVS that we are testing against
181class KvsAttributes {
182 public:
183 KvsAttributes(size_t key_size, size_t data_size)
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800184 : chunk_header_size_(RoundUpForAlignment(sizeof(EntryHeader))),
Wyatt Heplerb7609542020-01-24 10:29:54 -0800185 data_size_(RoundUpForAlignment(data_size)),
186 key_size_(RoundUpForAlignment(key_size)),
187 erase_size_(chunk_header_size_ + key_size_),
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800188 min_put_size_(
189 RoundUpForAlignment(chunk_header_size_ + key_size_ + data_size_)) {}
Wyatt Heplerb7609542020-01-24 10:29:54 -0800190
Wyatt Heplerb7609542020-01-24 10:29:54 -0800191 size_t ChunkHeaderSize() { return chunk_header_size_; }
192 size_t DataSize() { return data_size_; }
193 size_t KeySize() { return key_size_; }
194 size_t EraseSize() { return erase_size_; }
195 size_t MinPutSize() { return min_put_size_; }
196
197 private:
Wyatt Heplerb7609542020-01-24 10:29:54 -0800198 const size_t chunk_header_size_;
199 const size_t data_size_;
200 const size_t key_size_;
201 const size_t erase_size_;
202 const size_t min_put_size_;
203};
204
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800205class EmptyInitializedKvs : public ::testing::Test {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800206 protected:
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800207 EmptyInitializedKvs() : kvs_(&test_partition, format) {
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800208 test_partition.Erase();
Wyatt Hepler2e568872020-02-03 18:00:00 -0800209 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800210 }
Wyatt Hepler2e568872020-02-03 18:00:00 -0800211
212 // Intention of this is to put and erase key-val to fill up sectors. It's a
213 // helper function in testing how KVS handles cases where flash sector is full
214 // or near full.
215 void FillKvs(const char* key, size_t size_to_fill) {
216 constexpr size_t kTestDataSize = 8;
217 KvsAttributes kvs_attr(std::strlen(key), kTestDataSize);
218 const size_t kMaxPutSize =
219 buffer.size() + kvs_attr.ChunkHeaderSize() + kvs_attr.KeySize();
220
221 ASSERT_GE(size_to_fill, kvs_attr.MinPutSize() + kvs_attr.EraseSize());
222
223 // Saving enough space to perform erase after loop
224 size_to_fill -= kvs_attr.EraseSize();
225 // We start with possible small chunk to prevent too small of a Kvs.Put() at
226 // the end.
227 size_t chunk_len =
228 std::max(kvs_attr.MinPutSize(), size_to_fill % buffer.size());
229 std::memset(buffer.data(), 0, buffer.size());
230 while (size_to_fill > 0) {
231 // Changing buffer value so put actually does something
232 buffer[0] = static_cast<byte>(static_cast<uint8_t>(buffer[0]) + 1);
233 ASSERT_EQ(Status::OK,
234 kvs_.Put(key,
235 span(buffer.data(),
236 chunk_len - kvs_attr.ChunkHeaderSize() -
237 kvs_attr.KeySize())));
238 size_to_fill -= chunk_len;
239 chunk_len = std::min(size_to_fill, kMaxPutSize);
240 }
241 ASSERT_EQ(Status::OK, kvs_.Delete(key));
242 }
243
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800244 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800245};
246
Wyatt Heplerb7609542020-01-24 10:29:54 -0800247} // namespace
248
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800249TEST_F(EmptyInitializedKvs, Put_SameKeySameValueRepeatedly_AlignedEntries) {
Wyatt Heplerad0a7932020-02-06 08:20:38 -0800250 std::array<char, 8> value{'v', 'a', 'l', 'u', 'e', '6', '7', '\0'};
251
252 for (int i = 0; i < 1000; ++i) {
253 ASSERT_EQ(Status::OK, kvs_.Put("The Key!", as_bytes(span(value))));
254 }
255}
256
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800257TEST_F(EmptyInitializedKvs, Put_SameKeySameValueRepeatedly_UnalignedEntries) {
Wyatt Heplerad0a7932020-02-06 08:20:38 -0800258 std::array<char, 7> value{'v', 'a', 'l', 'u', 'e', '6', '\0'};
259
260 for (int i = 0; i < 1000; ++i) {
261 ASSERT_EQ(Status::OK, kvs_.Put("The Key!", as_bytes(span(value))));
262 }
263}
264
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800265TEST_F(EmptyInitializedKvs, Put_SameKeyDifferentValuesRepeatedly) {
Wyatt Hepler116d1162020-02-06 09:42:59 -0800266 std::array<char, 10> value{'v', 'a', 'l', 'u', 'e', '6', '7', '8', '9', '\0'};
267
268 for (int i = 0; i < 100; ++i) {
269 for (unsigned size = 0; size < value.size(); ++size) {
270 ASSERT_EQ(Status::OK, kvs_.Put("The Key!", i));
271 }
Wyatt Heplerad0a7932020-02-06 08:20:38 -0800272 }
273}
274
Wyatt Hepler5406a672020-02-18 15:42:38 -0800275TEST_F(EmptyInitializedKvs, Put_MaxValueSize) {
276 size_t max_value_size =
277 test_partition.sector_size_bytes() - sizeof(EntryHeader) - 1;
278
279 // Use the large_test_flash as a big chunk of data for the Put statement.
280 ASSERT_GT(sizeof(large_test_flash), max_value_size + 2 * sizeof(EntryHeader));
281 auto big_data = as_bytes(span(&large_test_flash, 1));
282
283 EXPECT_EQ(Status::OK, kvs_.Put("K", big_data.subspan(0, max_value_size)));
284
285 // Larger than maximum is rejected.
286 EXPECT_EQ(Status::INVALID_ARGUMENT,
287 kvs_.Put("K", big_data.subspan(0, max_value_size + 1)));
288 EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.Put("K", big_data));
289}
290
Wyatt Heplerfac81132020-02-27 17:26:33 -0800291TEST_F(EmptyInitializedKvs, PutAndGetByValue_ConvertibleToSpan) {
292 constexpr float input[] = {1.0, -3.5};
293 ASSERT_EQ(Status::OK, kvs_.Put("key", input));
294
295 float output[2] = {};
296 ASSERT_EQ(Status::OK, kvs_.Get("key", &output));
297 EXPECT_EQ(input[0], output[0]);
298 EXPECT_EQ(input[1], output[1]);
299}
300
301TEST_F(EmptyInitializedKvs, PutAndGetByValue_Span) {
302 float input[] = {1.0, -3.5};
303 ASSERT_EQ(Status::OK, kvs_.Put("key", span(input)));
304
305 float output[2] = {};
306 ASSERT_EQ(Status::OK, kvs_.Get("key", &output));
307 EXPECT_EQ(input[0], output[0]);
308 EXPECT_EQ(input[1], output[1]);
309}
310
311TEST_F(EmptyInitializedKvs, PutAndGetByValue_NotConvertibleToSpan) {
312 struct TestStruct {
313 double a;
314 bool b;
315 };
316 const TestStruct input{-1234.5, true};
317
318 ASSERT_EQ(Status::OK, kvs_.Put("key", input));
319
320 TestStruct output;
321 ASSERT_EQ(Status::OK, kvs_.Get("key", &output));
322 EXPECT_EQ(input.a, output.a);
323 EXPECT_EQ(input.b, output.b);
324}
325
Wyatt Hepler5f6efc02020-02-18 16:54:31 -0800326TEST_F(EmptyInitializedKvs, Get_Simple) {
327 ASSERT_EQ(Status::OK, kvs_.Put("Charles", as_bytes(span("Mingus"))));
328
329 char value[16];
330 auto result = kvs_.Get("Charles", as_writable_bytes(span(value)));
331 EXPECT_EQ(Status::OK, result.status());
332 EXPECT_EQ(sizeof("Mingus"), result.size());
333 EXPECT_STREQ("Mingus", value);
334}
335
336TEST_F(EmptyInitializedKvs, Get_WithOffset) {
337 ASSERT_EQ(Status::OK, kvs_.Put("Charles", as_bytes(span("Mingus"))));
338
339 char value[16];
340 auto result = kvs_.Get("Charles", as_writable_bytes(span(value)), 4);
341 EXPECT_EQ(Status::OK, result.status());
342 EXPECT_EQ(sizeof("Mingus") - 4, result.size());
343 EXPECT_STREQ("us", value);
344}
345
346TEST_F(EmptyInitializedKvs, Get_WithOffset_FillBuffer) {
347 ASSERT_EQ(Status::OK, kvs_.Put("Charles", as_bytes(span("Mingus"))));
348
349 char value[4] = {};
350 auto result = kvs_.Get("Charles", as_writable_bytes(span(value, 3)), 1);
351 EXPECT_EQ(Status::RESOURCE_EXHAUSTED, result.status());
352 EXPECT_EQ(3u, result.size());
353 EXPECT_STREQ("ing", value);
354}
355
356TEST_F(EmptyInitializedKvs, Get_WithOffset_PastEnd) {
357 ASSERT_EQ(Status::OK, kvs_.Put("Charles", as_bytes(span("Mingus"))));
358
359 char value[16];
360 auto result =
361 kvs_.Get("Charles", as_writable_bytes(span(value)), sizeof("Mingus") + 1);
362 EXPECT_EQ(Status::OUT_OF_RANGE, result.status());
363 EXPECT_EQ(0u, result.size());
364}
365
Wyatt Heplerfac81132020-02-27 17:26:33 -0800366TEST_F(EmptyInitializedKvs, GetValue) {
367 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
368
369 uint32_t value = 0;
370 EXPECT_EQ(Status::OK, kvs_.Get("key", &value));
371 EXPECT_EQ(uint32_t(0xfeedbeef), value);
372}
373
374TEST_F(EmptyInitializedKvs, GetValue_TooSmall) {
375 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
376
377 uint8_t value = 0;
378 EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.Get("key", &value));
379 EXPECT_EQ(0u, value);
380}
381
382TEST_F(EmptyInitializedKvs, GetValue_TooLarge) {
383 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
384
385 uint64_t value = 0;
386 EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.Get("key", &value));
387 EXPECT_EQ(0u, value);
388}
389
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800390TEST_F(EmptyInitializedKvs, Delete_GetDeletedKey_ReturnsNotFound) {
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800391 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
392 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
393
394 EXPECT_EQ(Status::NOT_FOUND, kvs_.Get("kEy", {}).status());
Wyatt Hepler50f70772020-02-13 11:25:10 -0800395 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("kEy").status());
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800396}
397
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800398TEST_F(EmptyInitializedKvs, Delete_AddBackKey_PersistsAfterInitialization) {
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800399 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
400 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
401
402 EXPECT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("45678"))));
403 char data[6] = {};
404 ASSERT_EQ(Status::OK, kvs_.Get("kEy", &data));
405 EXPECT_STREQ(data, "45678");
406
407 // Ensure that the re-added key is still present after reinitialization.
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800408 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> new_kvs(&test_partition,
409 format);
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800410 ASSERT_EQ(Status::OK, new_kvs.Init());
411
412 EXPECT_EQ(Status::OK, new_kvs.Put("kEy", as_bytes(span("45678"))));
413 char new_data[6] = {};
414 EXPECT_EQ(Status::OK, new_kvs.Get("kEy", &new_data));
415 EXPECT_STREQ(data, "45678");
416}
417
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800418TEST_F(EmptyInitializedKvs, Delete_AllItems_KvsIsEmpty) {
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800419 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
420 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
421
422 EXPECT_EQ(0u, kvs_.size());
423 EXPECT_TRUE(kvs_.empty());
424}
425
Wyatt Hepler2d401692020-02-13 16:01:23 -0800426TEST_F(EmptyInitializedKvs, Collision_WithPresentKey) {
427 // Both hash to 0x19df36f0.
428 constexpr std::string_view key1 = "D4";
429 constexpr std::string_view key2 = "dFU6S";
430
431 ASSERT_EQ(Status::OK, kvs_.Put(key1, 1000));
432
433 EXPECT_EQ(Status::ALREADY_EXISTS, kvs_.Put(key2, 999));
434
435 int value = 0;
436 EXPECT_EQ(Status::OK, kvs_.Get(key1, &value));
437 EXPECT_EQ(1000, value);
438
439 EXPECT_EQ(Status::NOT_FOUND, kvs_.Get(key2, &value));
440 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize(key2).status());
441 EXPECT_EQ(Status::NOT_FOUND, kvs_.Delete(key2));
442}
443
444TEST_F(EmptyInitializedKvs, Collision_WithDeletedKey) {
445 // Both hash to 0x4060f732.
446 constexpr std::string_view key1 = "1U2";
447 constexpr std::string_view key2 = "ahj9d";
448
449 ASSERT_EQ(Status::OK, kvs_.Put(key1, 1000));
450 ASSERT_EQ(Status::OK, kvs_.Delete(key1));
451
452 // key2 collides with key1's tombstone.
453 EXPECT_EQ(Status::ALREADY_EXISTS, kvs_.Put(key2, 999));
454
455 int value = 0;
456 EXPECT_EQ(Status::NOT_FOUND, kvs_.Get(key1, &value));
457
458 EXPECT_EQ(Status::NOT_FOUND, kvs_.Get(key2, &value));
459 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize(key2).status());
460 EXPECT_EQ(Status::NOT_FOUND, kvs_.Delete(key2));
461}
462
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800463TEST_F(EmptyInitializedKvs, Iteration_Empty_ByReference) {
Wyatt Heplerce0da522020-02-04 16:56:44 -0800464 for (const KeyValueStore::Item& entry : kvs_) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800465 FAIL(); // The KVS is empty; this shouldn't execute.
466 static_cast<void>(entry);
467 }
468}
469
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800470TEST_F(EmptyInitializedKvs, Iteration_Empty_ByValue) {
Wyatt Heplerce0da522020-02-04 16:56:44 -0800471 for (KeyValueStore::Item entry : kvs_) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800472 FAIL(); // The KVS is empty; this shouldn't execute.
473 static_cast<void>(entry);
474 }
475}
476
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800477TEST_F(EmptyInitializedKvs, Iteration_OneItem) {
Wyatt Hepler5f6efc02020-02-18 16:54:31 -0800478 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800479
480 for (KeyValueStore::Item entry : kvs_) {
Wyatt Heplera00d1ef2020-02-14 14:31:26 -0800481 EXPECT_STREQ(entry.key(), "kEy"); // Make sure null-terminated.
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800482
Wyatt Hepler5f6efc02020-02-18 16:54:31 -0800483 char buffer[sizeof("123")] = {};
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800484 EXPECT_EQ(Status::OK, entry.Get(&buffer));
Wyatt Hepler5f6efc02020-02-18 16:54:31 -0800485 EXPECT_STREQ("123", buffer);
486 }
487}
488
489TEST_F(EmptyInitializedKvs, Iteration_GetWithOffset) {
490 ASSERT_EQ(Status::OK, kvs_.Put("key", as_bytes(span("not bad!"))));
491
492 for (KeyValueStore::Item entry : kvs_) {
493 char buffer[5];
494 auto result = entry.Get(as_writable_bytes(span(buffer)), 4);
495 EXPECT_EQ(Status::OK, result.status());
496 EXPECT_EQ(5u, result.size());
497 EXPECT_STREQ("bad!", buffer);
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800498 }
499}
500
Wyatt Heplerfac81132020-02-27 17:26:33 -0800501TEST_F(EmptyInitializedKvs, Iteration_GetValue) {
502 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
503
504 for (KeyValueStore::Item entry : kvs_) {
505 uint32_t value = 0;
506 EXPECT_EQ(Status::OK, entry.Get(&value));
507 EXPECT_EQ(uint32_t(0xfeedbeef), value);
508 }
509}
510
511TEST_F(EmptyInitializedKvs, Iteration_GetValue_TooSmall) {
512 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
513
514 for (KeyValueStore::Item entry : kvs_) {
515 uint8_t value = 0;
516 EXPECT_EQ(Status::INVALID_ARGUMENT, entry.Get(&value));
517 EXPECT_EQ(0u, value);
518 }
519}
520
521TEST_F(EmptyInitializedKvs, Iteration_GetValue_TooLarge) {
522 ASSERT_EQ(Status::OK, kvs_.Put("key", uint32_t(0xfeedbeef)));
523
524 for (KeyValueStore::Item entry : kvs_) {
525 uint64_t value = 0;
526 EXPECT_EQ(Status::INVALID_ARGUMENT, entry.Get(&value));
527 EXPECT_EQ(0u, value);
528 }
529}
530
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800531TEST_F(EmptyInitializedKvs, Iteration_EmptyAfterDeletion) {
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800532 ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123"))));
533 ASSERT_EQ(Status::OK, kvs_.Delete("kEy"));
534
535 for (KeyValueStore::Item entry : kvs_) {
536 static_cast<void>(entry);
537 FAIL();
538 }
539}
540
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800541TEST_F(EmptyInitializedKvs, FuzzTest) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800542 if (test_partition.sector_size_bytes() < 4 * 1024 ||
543 test_partition.sector_count() < 4) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800544 PW_LOG_INFO("Sectors too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800545 return; // TODO: Test could be generalized
546 }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800547 const char* key1 = "Buf1";
548 const char* key2 = "Buf2";
549 const size_t kLargestBufSize = 3 * 1024;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800550 static byte buf1[kLargestBufSize];
551 static byte buf2[kLargestBufSize];
552 std::memset(buf1, 1, sizeof(buf1));
553 std::memset(buf2, 2, sizeof(buf2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800554
555 // Start with things in KVS
Wyatt Hepler2e568872020-02-03 18:00:00 -0800556 ASSERT_EQ(Status::OK, kvs_.Put(key1, buf1));
557 ASSERT_EQ(Status::OK, kvs_.Put(key2, buf2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800558 for (size_t j = 0; j < keys.size(); j++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800559 ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800560 }
561
562 for (size_t i = 0; i < 100; i++) {
563 // Vary two sizes
564 size_t size1 = (kLargestBufSize) / (i + 1);
565 size_t size2 = (kLargestBufSize) / (100 - i);
566 for (size_t j = 0; j < 50; j++) {
567 // Rewrite a single key many times, can fill up a sector
Wyatt Hepler2e568872020-02-03 18:00:00 -0800568 ASSERT_EQ(Status::OK, kvs_.Put("some_data", j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800569 }
570 // Delete and re-add everything
Wyatt Hepler2e568872020-02-03 18:00:00 -0800571 ASSERT_EQ(Status::OK, kvs_.Delete(key1));
572 ASSERT_EQ(Status::OK, kvs_.Put(key1, span(buf1, size1)));
573 ASSERT_EQ(Status::OK, kvs_.Delete(key2));
574 ASSERT_EQ(Status::OK, kvs_.Put(key2, span(buf2, size2)));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800575 for (size_t j = 0; j < keys.size(); j++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800576 ASSERT_EQ(Status::OK, kvs_.Delete(keys[j]));
577 ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800578 }
579
580 // Re-enable and verify
Wyatt Hepler2e568872020-02-03 18:00:00 -0800581 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800582 static byte buf[4 * 1024];
Wyatt Hepler2e568872020-02-03 18:00:00 -0800583 ASSERT_EQ(Status::OK, kvs_.Get(key1, span(buf, size1)).status());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800584 ASSERT_EQ(std::memcmp(buf, buf1, size1), 0);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800585 ASSERT_EQ(Status::OK, kvs_.Get(key2, span(buf, size2)).status());
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800586 ASSERT_EQ(std::memcmp(buf2, buf2, size2), 0);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800587 for (size_t j = 0; j < keys.size(); j++) {
588 size_t ret = 1000;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800589 ASSERT_EQ(Status::OK, kvs_.Get(keys[j], &ret));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800590 ASSERT_EQ(ret, j);
591 }
592 }
593}
594
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800595TEST_F(EmptyInitializedKvs, Basic) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800596 // Add some data
597 uint8_t value1 = 0xDA;
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800598 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800599 kvs_.Put(keys[0], as_bytes(span(&value1, sizeof(value1)))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800600
601 uint32_t value2 = 0xBAD0301f;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800602 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], value2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800603
604 // Verify data
605 uint32_t test2;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800606 EXPECT_EQ(Status::OK, kvs_.Get(keys[1], &test2));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800607 uint8_t test1;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800608 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &test1));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800609
610 EXPECT_EQ(test1, value1);
611 EXPECT_EQ(test2, value2);
612
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800613 // Delete a key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800614 EXPECT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800615
616 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800617 EXPECT_EQ(kvs_.Get(keys[0], &test1), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800618 test2 = 0;
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800619 ASSERT_EQ(
620 Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800621 kvs_.Get(keys[1], span(reinterpret_cast<byte*>(&test2), sizeof(test2)))
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800622 .status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800623 EXPECT_EQ(test2, value2);
624
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800625 // Delete other key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800626 kvs_.Delete(keys[1]);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800627
628 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800629 EXPECT_EQ(kvs_.size(), 0u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800630}
631
Keir Mierle8c352dc2020-02-02 13:58:19 -0800632#define ASSERT_OK(expr) ASSERT_EQ(Status::OK, expr)
633#define EXPECT_OK(expr) EXPECT_EQ(Status::OK, expr)
634
Wyatt Hepler595cf012020-02-05 09:31:02 -0800635TEST(InMemoryKvs, WriteOneKeyMultipleTimes) {
Keir Mierle8c352dc2020-02-02 13:58:19 -0800636 // Create and erase the fake flash. It will persist across reloads.
637 Flash flash;
638 ASSERT_OK(flash.partition.Erase());
639
640 int num_reloads = 2;
641 for (int reload = 0; reload < num_reloads; ++reload) {
642 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
643 DBG("xxx xxxx");
644 DBG("xxx Reload %2d xxxx", reload);
645 DBG("xxx xxxx");
646 DBG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
647
648 // Create and initialize the KVS.
Wyatt Hepler88adfe82020-02-20 19:33:27 -0800649 constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800650 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
651 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800652 ASSERT_OK(kvs.Init());
653
654 // Write the same entry many times.
655 const char* key = "abcd";
Wyatt Heplere3288e12020-02-26 13:05:07 -0800656 const size_t num_writes = 99;
Keir Mierle8c352dc2020-02-02 13:58:19 -0800657 uint32_t written_value;
658 EXPECT_EQ(kvs.size(), (reload == 0) ? 0 : 1u);
659 for (uint32_t i = 0; i < num_writes; ++i) {
Wyatt Heplere3288e12020-02-26 13:05:07 -0800660 DBG("PUT #%zu for key %s with value %zu", size_t(i), key, size_t(i));
Keir Mierle8c352dc2020-02-02 13:58:19 -0800661
662 written_value = i + 0xfc; // Prevent accidental pass with zero.
663 EXPECT_OK(kvs.Put(key, written_value));
664 EXPECT_EQ(kvs.size(), 1u);
665 }
666
667 // Verify that we can read the value back.
Wyatt Heplere3288e12020-02-26 13:05:07 -0800668 DBG("GET final value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800669 uint32_t actual_value;
670 EXPECT_OK(kvs.Get(key, &actual_value));
671 EXPECT_EQ(actual_value, written_value);
672
Keir Mierle8c352dc2020-02-02 13:58:19 -0800673 char fname_buf[64] = {'\0'};
674 snprintf(&fname_buf[0],
675 sizeof(fname_buf),
676 "WriteOneKeyMultipleTimes_%d.bin",
677 reload);
678 flash.Dump(fname_buf);
679 }
680}
681
682TEST(InMemoryKvs, WritingMultipleKeysIncreasesSize) {
683 // Create and erase the fake flash.
684 Flash flash;
685 ASSERT_OK(flash.partition.Erase());
686
687 // Create and initialize the KVS.
Wyatt Hepler88adfe82020-02-20 19:33:27 -0800688 constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800689 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
690 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800691 ASSERT_OK(kvs.Init());
692
693 // Write the same entry many times.
694 const size_t num_writes = 10;
695 EXPECT_EQ(kvs.size(), 0u);
696 for (size_t i = 0; i < num_writes; ++i) {
697 StringBuffer<150> key;
698 key << "key_" << i;
Wyatt Heplere3288e12020-02-26 13:05:07 -0800699 DBG("PUT #%zu for key %s with value %zu", i, key.c_str(), i);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800700
701 size_t value = i + 77; // Prevent accidental pass with zero.
702 EXPECT_OK(kvs.Put(key.view(), value));
703 EXPECT_EQ(kvs.size(), i + 1);
704 }
Keir Mierle8c352dc2020-02-02 13:58:19 -0800705 flash.Dump("WritingMultipleKeysIncreasesSize.bin");
706}
707
708TEST(InMemoryKvs, WriteAndReadOneKey) {
709 // Create and erase the fake flash.
710 Flash flash;
711 ASSERT_OK(flash.partition.Erase());
712
713 // Create and initialize the KVS.
Wyatt Hepler88adfe82020-02-20 19:33:27 -0800714 constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800715 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
716 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800717 ASSERT_OK(kvs.Init());
718
719 // Add two entries with different keys and values.
720 const char* key = "Key1";
Wyatt Heplere3288e12020-02-26 13:05:07 -0800721 DBG("PUT value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800722 uint8_t written_value = 0xDA;
723 ASSERT_OK(kvs.Put(key, written_value));
724 EXPECT_EQ(kvs.size(), 1u);
725
Wyatt Heplere3288e12020-02-26 13:05:07 -0800726 DBG("GET value for key: %s", key);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800727 uint8_t actual_value;
728 ASSERT_OK(kvs.Get(key, &actual_value));
729 EXPECT_EQ(actual_value, written_value);
730
731 EXPECT_EQ(kvs.size(), 1u);
732}
733
734TEST(InMemoryKvs, Basic) {
735 const char* key1 = "Key1";
736 const char* key2 = "Key2";
737
738 // Create and erase the fake flash.
739 Flash flash;
740 ASSERT_EQ(Status::OK, flash.partition.Erase());
741
742 // Create and initialize the KVS.
Wyatt Hepler88adfe82020-02-20 19:33:27 -0800743 constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800744 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition,
745 format);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800746 ASSERT_OK(kvs.Init());
747
748 // Add two entries with different keys and values.
Keir Mierle8c352dc2020-02-02 13:58:19 -0800749 uint8_t value1 = 0xDA;
750 ASSERT_OK(kvs.Put(key1, as_bytes(span(&value1, sizeof(value1)))));
751 EXPECT_EQ(kvs.size(), 1u);
752
Keir Mierle8c352dc2020-02-02 13:58:19 -0800753 uint32_t value2 = 0xBAD0301f;
754 ASSERT_OK(kvs.Put(key2, value2));
755 EXPECT_EQ(kvs.size(), 2u);
756
Keir Mierle8c352dc2020-02-02 13:58:19 -0800757 // Verify data
758 uint32_t test2;
759 EXPECT_OK(kvs.Get(key2, &test2));
760
Keir Mierle8c352dc2020-02-02 13:58:19 -0800761 uint8_t test1;
762 ASSERT_OK(kvs.Get(key1, &test1));
763
764 EXPECT_EQ(test1, value1);
765 EXPECT_EQ(test2, value2);
766
767 EXPECT_EQ(kvs.size(), 2u);
768}
769
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800770TEST_F(EmptyInitializedKvs, MaxKeyLength) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800771 // Add some data
772 char key[16] = "123456789abcdef"; // key length 15 (without \0)
773 int value = 1;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800774 ASSERT_EQ(Status::OK, kvs_.Put(key, value));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800775
776 // Verify data
777 int test = 0;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800778 ASSERT_EQ(Status::OK, kvs_.Get(key, &test));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800779 EXPECT_EQ(test, value);
780
Wyatt Hepler6c24c062020-02-05 15:30:49 -0800781 // Delete a key
Wyatt Hepler50f70772020-02-13 11:25:10 -0800782 EXPECT_EQ(Status::OK, kvs_.Delete(key));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800783
784 // Verify it was erased
Wyatt Hepler2e568872020-02-03 18:00:00 -0800785 EXPECT_EQ(kvs_.Get(key, &test), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800786}
787
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800788TEST_F(EmptyInitializedKvs, LargeBuffers) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800789 // Note this assumes that no other keys larger then key0
790 static_assert(sizeof(keys[0]) >= sizeof(keys[1]) &&
791 sizeof(keys[0]) >= sizeof(keys[2]));
792 KvsAttributes kvs_attr(std::strlen(keys[0]), buffer.size());
793
794 // Verify the data will fit in this test partition. This checks that all the
795 // keys chunks will fit and a header for each sector will fit. It requires 1
796 // empty sector also.
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800797 const size_t kMinSize = kvs_attr.MinPutSize() * keys.size();
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800798 const size_t kAvailSectorSpace =
799 test_partition.sector_size_bytes() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800800 if (kAvailSectorSpace < kMinSize) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800801 PW_LOG_INFO("KVS too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800802 return;
803 }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800804
805 // Add and verify
806 for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800807 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800808 ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer));
809 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800810 for (unsigned verify_idx = 0; verify_idx <= add_idx; verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800811 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800812 ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800813 for (unsigned i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800814 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800815 }
816 }
817 }
818
819 // Erase and verify
820 for (unsigned erase_idx = 0; erase_idx < keys.size(); erase_idx++) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800821 ASSERT_EQ(Status::OK, kvs_.Delete(keys[erase_idx]));
822 EXPECT_EQ(kvs_.size(), keys.size() - erase_idx - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800823 for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800824 std::memset(buffer.data(), 0, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800825 if (verify_idx <= erase_idx) {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800826 ASSERT_EQ(kvs_.Get(keys[verify_idx], buffer).status(),
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800827 Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800828 } else {
Wyatt Hepler2e568872020-02-03 18:00:00 -0800829 ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800830 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800831 EXPECT_EQ(buffer[i], static_cast<byte>(verify_idx));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800832 }
833 }
834 }
835 }
836}
837
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800838TEST_F(EmptyInitializedKvs, Enable) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800839 KvsAttributes kvs_attr(std::strlen(keys[0]), buffer.size());
840
841 // Verify the data will fit in this test partition. This checks that all the
842 // keys chunks will fit and a header for each sector will fit. It requires 1
843 // empty sector also.
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800844 const size_t kMinSize = kvs_attr.MinPutSize() * keys.size();
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800845 const size_t kAvailSectorSpace =
846 test_partition.sector_size_bytes() * (test_partition.sector_count() - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800847 if (kAvailSectorSpace < kMinSize) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800848 PW_LOG_INFO("KVS too small, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800849 return;
850 }
851
Wyatt Heplerb7609542020-01-24 10:29:54 -0800852 // Add some items
853 for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800854 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800855 ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer));
856 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800857 }
858
859 // Enable different KVS which should be able to properly setup the same map
860 // from what is stored in flash.
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800861 static KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_local(
862 &test_partition, format);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800863 ASSERT_EQ(Status::OK, kvs_local.Init());
864 EXPECT_EQ(kvs_local.size(), keys.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800865
866 // Ensure adding to new KVS works
867 uint8_t value = 0xDA;
868 const char* key = "new_key";
Wyatt Hepler2e568872020-02-03 18:00:00 -0800869 ASSERT_EQ(Status::OK, kvs_local.Put(key, value));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800870 uint8_t test;
Wyatt Hepler2e568872020-02-03 18:00:00 -0800871 ASSERT_EQ(Status::OK, kvs_local.Get(key, &test));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800872 EXPECT_EQ(value, test);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800873 EXPECT_EQ(kvs_local.size(), keys.size() + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800874
875 // Verify previous data
876 for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800877 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -0800878 ASSERT_EQ(Status::OK, kvs_local.Get(keys[verify_idx], buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800879 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800880 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800881 }
882 }
883}
884
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800885TEST_F(EmptyInitializedKvs, MultiSector) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800886 // Calculate number of elements to ensure multiple sectors are required.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800887 uint16_t add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800888
Wyatt Hepler2e568872020-02-03 18:00:00 -0800889 if (kvs_.max_size() < add_count) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800890 PW_LOG_INFO("Sector size too large, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800891 return; // this chip has very large sectors, test won't work
892 }
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800893 if (test_partition.sector_count() < 3) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800894 PW_LOG_INFO("Not enough sectors, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -0800895 return; // need at least 3 sectors for multi-sector test
896 }
897
898 char key[20];
899 for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800900 std::memset(buffer.data(), add_idx, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800901 snprintf(key, sizeof(key), "key_%u", add_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800902 ASSERT_EQ(Status::OK, kvs_.Put(key, buffer));
903 EXPECT_EQ(kvs_.size(), add_idx + 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800904 }
905
906 for (unsigned verify_idx = 0; verify_idx < add_count; verify_idx++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800907 std::memset(buffer.data(), 0, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800908 snprintf(key, sizeof(key), "key_%u", verify_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800909 ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800910 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -0800911 EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800912 }
913 }
914
915 // Check erase
916 for (unsigned erase_idx = 0; erase_idx < add_count; erase_idx++) {
917 snprintf(key, sizeof(key), "key_%u", erase_idx);
Wyatt Hepler2e568872020-02-03 18:00:00 -0800918 ASSERT_EQ(Status::OK, kvs_.Delete(key));
919 EXPECT_EQ(kvs_.size(), add_count - erase_idx - 1);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800920 }
921}
922
Wyatt Hepler0bde10a2020-02-07 13:35:51 -0800923TEST_F(EmptyInitializedKvs, RewriteValue) {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800924 // Write first value
925 const uint8_t kValue1 = 0xDA;
926 const uint8_t kValue2 = 0x12;
927 const char* key = "the_key";
Wyatt Hepler2e568872020-02-03 18:00:00 -0800928 ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue1, 1))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800929
930 // Verify
931 uint8_t value;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800932 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800933 kvs_.Get(key, as_writable_bytes(span(&value, 1))).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800934 EXPECT_EQ(kValue1, value);
935
936 // Write new value for key
Wyatt Hepler2e568872020-02-03 18:00:00 -0800937 ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue2, 1))));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800938
939 // Verify
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800940 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -0800941 kvs_.Get(key, as_writable_bytes(span(&value, 1))).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -0800942 EXPECT_EQ(kValue2, value);
943
944 // Verify only 1 element exists
Wyatt Hepler2e568872020-02-03 18:00:00 -0800945 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800946}
947
David Rogerscf680ab2020-02-12 23:28:32 -0800948TEST_F(EmptyInitializedKvs, RepeatingValueWithOtherData) {
David Rogersbe744c12020-02-12 19:19:40 -0800949 std::byte set_buf[150];
950 std::byte get_buf[sizeof(set_buf)];
951
952 for (size_t set_index = 0; set_index < sizeof(set_buf); set_index++) {
953 set_buf[set_index] = static_cast<std::byte>(set_index);
954 }
955
956 StatusWithSize result;
957
958 // Test setting the same entry 10 times but varying the amount of data
959 // that is already in env before each test
960 for (size_t test_iteration = 0; test_iteration < sizeof(set_buf);
961 test_iteration++) {
David Rogerscf680ab2020-02-12 23:28:32 -0800962 // TOD0: Add KVS erase
David Rogersbe744c12020-02-12 19:19:40 -0800963 // Add a constant unchanging entry so that the updates are not
964 // the only entries in the env. The size of this initial entry
965 // we vary between no bytes to sizeof(set_buf).
966 ASSERT_EQ(Status::OK,
967 kvs_.Put("const_entry", span(set_buf, test_iteration)));
968
969 // The value we read back should be the last value we set
970 std::memset(get_buf, 0, sizeof(get_buf));
971 result = kvs_.Get("const_entry", span(get_buf));
Wyatt Hepler5f6efc02020-02-18 16:54:31 -0800972 ASSERT_EQ(Status::OK, result.status());
David Rogersbe744c12020-02-12 19:19:40 -0800973 ASSERT_EQ(result.size(), test_iteration);
974 for (size_t j = 0; j < test_iteration; j++) {
975 EXPECT_EQ(set_buf[j], get_buf[j]);
976 }
977
978 // Update the test entry 5 times
979 static_assert(sizeof(std::byte) == sizeof(uint8_t));
980 uint8_t set_entry_buf[]{1, 2, 3, 4, 5, 6, 7, 8};
981 std::byte* set_entry = reinterpret_cast<std::byte*>(set_entry_buf);
982 std::byte get_entry_buf[sizeof(set_entry_buf)];
983 for (size_t i = 0; i < 5; i++) {
984 set_entry[0] = static_cast<std::byte>(i);
985 ASSERT_EQ(Status::OK,
986 kvs_.Put("test_entry", span(set_entry, sizeof(set_entry_buf))));
987 std::memset(get_entry_buf, 0, sizeof(get_entry_buf));
988 result = kvs_.Get("test_entry", span(get_entry_buf));
989 ASSERT_TRUE(result.ok());
990 ASSERT_EQ(result.size(), sizeof(get_entry_buf));
991 for (uint32_t j = 0; j < sizeof(set_entry_buf); j++) {
992 EXPECT_EQ(set_entry[j], get_entry_buf[j]);
993 }
994 }
995
996 // Check that the const entry is still present and has the right value
997 std::memset(get_buf, 0, sizeof(get_buf));
998 result = kvs_.Get("const_entry", span(get_buf));
999 ASSERT_TRUE(result.ok());
1000 ASSERT_EQ(result.size(), test_iteration);
1001 for (size_t j = 0; j < test_iteration; j++) {
1002 EXPECT_EQ(set_buf[j], get_buf[j]);
1003 }
1004 }
1005}
1006
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001007TEST_F(EmptyInitializedKvs, OffsetRead) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001008 const char* key = "the_key";
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001009 constexpr size_t kReadSize = 16; // needs to be a multiple of alignment
1010 constexpr size_t kTestBufferSize = kReadSize * 10;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001011 ASSERT_GT(buffer.size(), kTestBufferSize);
Wyatt Heplere3288e12020-02-26 13:05:07 -08001012 ASSERT_LE(kTestBufferSize, 0xFFu);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001013
1014 // Write the entire buffer
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001015 for (size_t i = 0; i < kTestBufferSize; i++) {
1016 buffer[i] = byte(i);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001017 }
Wyatt Hepler2e568872020-02-03 18:00:00 -08001018 ASSERT_EQ(Status::OK, kvs_.Put(key, span(buffer.data(), kTestBufferSize)));
1019 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001020
1021 // Read in small chunks and verify
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001022 for (unsigned i = 0; i < kTestBufferSize / kReadSize; i++) {
1023 std::memset(buffer.data(), 0, buffer.size());
Wyatt Heplere3288e12020-02-26 13:05:07 -08001024 StatusWithSize result =
1025 kvs_.Get(key, span(buffer.data(), kReadSize), i * kReadSize);
1026
1027 ASSERT_EQ(kReadSize, result.size());
1028
1029 // Only last iteration is OK since all remaining data was read.
1030 if (i == kTestBufferSize / kReadSize - 1) {
1031 ASSERT_EQ(Status::OK, result.status());
1032 } else { // RESOURCE_EXHAUSTED, since there is still data to read.
1033 ASSERT_EQ(Status::RESOURCE_EXHAUSTED, result.status());
1034 }
1035
Wyatt Heplerb7609542020-01-24 10:29:54 -08001036 for (unsigned j = 0; j < kReadSize; j++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001037 ASSERT_EQ(static_cast<unsigned>(buffer[j]), j + i * kReadSize);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001038 }
1039 }
1040}
1041
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001042TEST_F(EmptyInitializedKvs, MultipleRewrite) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001043 // Calculate number of elements to ensure multiple sectors are required.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001044 unsigned add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001045
1046 const char* key = "the_key";
1047 constexpr uint8_t kGoodVal = 0x60;
1048 constexpr uint8_t kBadVal = 0xBA;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001049 std::memset(buffer.data(), kBadVal, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001050 for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
1051 if (add_idx == add_count - 1) { // last value
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001052 std::memset(buffer.data(), kGoodVal, buffer.size());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001053 }
Wyatt Hepler2e568872020-02-03 18:00:00 -08001054 ASSERT_EQ(Status::OK, kvs_.Put(key, buffer));
1055 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001056 }
1057
1058 // Verify
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001059 std::memset(buffer.data(), 0, buffer.size());
Wyatt Hepler2e568872020-02-03 18:00:00 -08001060 ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001061 for (uint32_t i = 0; i < buffer.size(); i++) {
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001062 ASSERT_EQ(buffer[i], static_cast<byte>(kGoodVal));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001063 }
1064}
1065
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001066TEST_F(EmptyInitializedKvs, FillSector) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001067 ASSERT_EQ(std::strlen(keys[0]), 8U); // Easier for alignment
1068 ASSERT_EQ(std::strlen(keys[2]), 8U); // Easier for alignment
1069 constexpr size_t kTestDataSize = 8;
1070 KvsAttributes kvs_attr(std::strlen(keys[2]), kTestDataSize);
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001071 int bytes_remaining = test_partition.sector_size_bytes();
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001072 constexpr byte kKey0Pattern = byte{0xBA};
Wyatt Heplerb7609542020-01-24 10:29:54 -08001073
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001074 std::memset(
1075 buffer.data(), static_cast<int>(kKey0Pattern), kvs_attr.DataSize());
1076 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001077 kvs_.Put(keys[0], span(buffer.data(), kvs_attr.DataSize())));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001078 bytes_remaining -= kvs_attr.MinPutSize();
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001079 std::memset(buffer.data(), 1, kvs_attr.DataSize());
1080 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001081 kvs_.Put(keys[2], span(buffer.data(), kvs_attr.DataSize())));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001082 bytes_remaining -= kvs_attr.MinPutSize();
Wyatt Hepler2e568872020-02-03 18:00:00 -08001083 EXPECT_EQ(kvs_.size(), 2u);
1084 ASSERT_EQ(Status::OK, kvs_.Delete(keys[2]));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001085 bytes_remaining -= kvs_attr.EraseSize();
Wyatt Hepler2e568872020-02-03 18:00:00 -08001086 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001087
1088 // Intentionally adding erase size to trigger sector cleanup
1089 bytes_remaining += kvs_attr.EraseSize();
1090 FillKvs(keys[2], bytes_remaining);
1091
1092 // Verify key[0]
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001093 std::memset(buffer.data(), 0, kvs_attr.DataSize());
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001094 ASSERT_EQ(
1095 Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001096 kvs_.Get(keys[0], span(buffer.data(), kvs_attr.DataSize())).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001097 for (uint32_t i = 0; i < kvs_attr.DataSize(); i++) {
1098 EXPECT_EQ(buffer[i], kKey0Pattern);
1099 }
1100}
1101
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001102TEST_F(EmptyInitializedKvs, Interleaved) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001103 const uint8_t kValue1 = 0xDA;
1104 const uint8_t kValue2 = 0x12;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001105 uint8_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001106 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue1));
1107 EXPECT_EQ(kvs_.size(), 1u);
1108 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
1109 EXPECT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
1110 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], as_bytes(span(&kValue1, 1))));
1111 ASSERT_EQ(Status::OK, kvs_.Put(keys[2], kValue2));
1112 ASSERT_EQ(Status::OK, kvs_.Delete(keys[1]));
1113 EXPECT_EQ(Status::OK, kvs_.Get(keys[2], &value));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001114 EXPECT_EQ(kValue2, value);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001115
Wyatt Hepler2e568872020-02-03 18:00:00 -08001116 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001117}
1118
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001119TEST_F(EmptyInitializedKvs, DeleteAndReinitialize) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001120 // Write value
1121 const uint8_t kValue = 0xDA;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001122 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001123
Wyatt Hepler2e568872020-02-03 18:00:00 -08001124 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001125 uint8_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001126 ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001127
1128 // Reset KVS, ensure captured at enable
Wyatt Hepler2e568872020-02-03 18:00:00 -08001129 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001130
Wyatt Hepler2e568872020-02-03 18:00:00 -08001131 ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001132}
1133
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001134TEST_F(EmptyInitializedKvs, TemplatedPutAndGet) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001135 // Store a value with the convenience method.
1136 const uint32_t kValue = 0x12345678;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001137 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001138
1139 // Read it back with the other convenience method.
1140 uint32_t value;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001141 ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001142 ASSERT_EQ(kValue, value);
1143
1144 // Make sure we cannot get something where size isn't what we expect
1145 const uint8_t kSmallValue = 0xBA;
1146 uint8_t small_value = kSmallValue;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001147 ASSERT_EQ(kvs_.Get(keys[0], &small_value), Status::INVALID_ARGUMENT);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001148 ASSERT_EQ(small_value, kSmallValue);
1149}
1150
Wyatt Heplerb7609542020-01-24 10:29:54 -08001151// This test is derived from bug that was discovered. Testing this corner case
1152// relies on creating a new key-value just under the size that is left over in
1153// the sector.
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001154TEST_F(EmptyInitializedKvs, FillSector2) {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001155 if (test_partition.sector_count() < 3) {
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001156 PW_LOG_INFO("Not enough sectors, skipping test.");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001157 return; // need at least 3 sectors
1158 }
1159
Wyatt Heplerb7609542020-01-24 10:29:54 -08001160 // Start of by filling flash sector to near full
1161 constexpr int kHalfBufferSize = buffer.size() / 2;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001162 const int kSizeToFill = test_partition.sector_size_bytes() - kHalfBufferSize;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001163 constexpr size_t kTestDataSize = 8;
1164 KvsAttributes kvs_attr(std::strlen(keys[2]), kTestDataSize);
1165
1166 FillKvs(keys[2], kSizeToFill);
1167
1168 // Find out how much space is remaining for new key-value and confirm it
1169 // makes sense.
1170 size_t new_keyvalue_size = 0;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001171 size_t alignment = test_partition.alignment_bytes();
Wyatt Heplerb7609542020-01-24 10:29:54 -08001172 // Starts on second sector since it will try to keep first sector free
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001173 FlashPartition::Address read_address =
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001174 2 * test_partition.sector_size_bytes() - alignment;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001175 for (; read_address > 0; read_address -= alignment) {
1176 bool is_erased = false;
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001177 ASSERT_EQ(
1178 Status::OK,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -08001179 test_partition.IsRegionErased(read_address, alignment, &is_erased));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001180 if (is_erased) {
1181 new_keyvalue_size += alignment;
1182 } else {
1183 break;
1184 }
1185 }
1186
Wyatt Hepler16b04522020-02-07 16:00:14 -08001187 size_t expected_remaining = test_partition.sector_size_bytes() - kSizeToFill;
Wyatt Heplerb7609542020-01-24 10:29:54 -08001188 ASSERT_EQ(new_keyvalue_size, expected_remaining);
1189
1190 const char* kNewKey = "NewKey";
1191 constexpr size_t kValueLessThanChunkHeaderSize = 2;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001192 constexpr auto kTestPattern = byte{0xBA};
Wyatt Heplerb7609542020-01-24 10:29:54 -08001193 new_keyvalue_size -= kValueLessThanChunkHeaderSize;
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001194 std::memset(buffer.data(), static_cast<int>(kTestPattern), new_keyvalue_size);
1195 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001196 kvs_.Put(kNewKey, span(buffer.data(), new_keyvalue_size)));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001197
1198 // In failed corner case, adding new key is deceptively successful. It isn't
1199 // until KVS is disabled and reenabled that issue can be detected.
Wyatt Hepler2e568872020-02-03 18:00:00 -08001200 ASSERT_EQ(Status::OK, kvs_.Init());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001201
1202 // Might as well check that new key-value is what we expect it to be
Wyatt Hepleracaacf92020-01-24 10:58:30 -08001203 ASSERT_EQ(Status::OK,
Wyatt Hepler2e568872020-02-03 18:00:00 -08001204 kvs_.Get(kNewKey, span(buffer.data(), new_keyvalue_size)).status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001205 for (size_t i = 0; i < new_keyvalue_size; i++) {
1206 EXPECT_EQ(buffer[i], kTestPattern);
1207 }
1208}
1209
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001210TEST_F(EmptyInitializedKvs, ValueSize_Positive) {
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -08001211 constexpr auto kData = AsBytes('h', 'i', '!');
Wyatt Heplered163b02020-02-03 17:49:32 -08001212 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", kData));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001213
Wyatt Heplered163b02020-02-03 17:49:32 -08001214 auto result = kvs_.ValueSize("TheKey");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001215
Wyatt Heplered163b02020-02-03 17:49:32 -08001216 EXPECT_EQ(Status::OK, result.status());
1217 EXPECT_EQ(kData.size(), result.size());
1218}
Wyatt Heplerb7609542020-01-24 10:29:54 -08001219
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001220TEST_F(EmptyInitializedKvs, ValueSize_Zero) {
Wyatt Heplered163b02020-02-03 17:49:32 -08001221 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", as_bytes(span("123", 3))));
1222 auto result = kvs_.ValueSize("TheKey");
Wyatt Heplerb7609542020-01-24 10:29:54 -08001223
Wyatt Heplered163b02020-02-03 17:49:32 -08001224 EXPECT_EQ(Status::OK, result.status());
1225 EXPECT_EQ(3u, result.size());
1226}
Wyatt Heplerb7609542020-01-24 10:29:54 -08001227
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001228TEST_F(EmptyInitializedKvs, ValueSize_InvalidKey) {
Wyatt Heplered163b02020-02-03 17:49:32 -08001229 EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.ValueSize("").status());
1230}
1231
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001232TEST_F(EmptyInitializedKvs, ValueSize_MissingKey) {
Wyatt Heplered163b02020-02-03 17:49:32 -08001233 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("Not in there").status());
1234}
1235
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001236TEST_F(EmptyInitializedKvs, ValueSize_DeletedKey) {
Wyatt Heplered163b02020-02-03 17:49:32 -08001237 ASSERT_EQ(Status::OK, kvs_.Put("TheKey", as_bytes(span("123", 3))));
1238 ASSERT_EQ(Status::OK, kvs_.Delete("TheKey"));
1239
1240 EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("TheKey").status());
Wyatt Heplerb7609542020-01-24 10:29:54 -08001241}
1242
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001243#if USE_MEMORY_BUFFER
Wyatt Heplerb7609542020-01-24 10:29:54 -08001244
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001245class LargeEmptyInitializedKvs : public ::testing::Test {
1246 protected:
1247 LargeEmptyInitializedKvs() : kvs_(&large_test_partition, format) {
1248 ASSERT_EQ(
1249 Status::OK,
1250 large_test_partition.Erase(0, large_test_partition.sector_count()));
1251 ASSERT_EQ(Status::OK, kvs_.Init());
1252 }
1253
Wyatt Hepler38ce30f2020-02-19 11:48:31 -08001254 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_;
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001255};
1256
1257TEST_F(LargeEmptyInitializedKvs, Basic) {
1258 const uint8_t kValue1 = 0xDA;
1259 const uint8_t kValue2 = 0x12;
1260 uint8_t value;
1261 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue1));
1262 EXPECT_EQ(kvs_.size(), 1u);
1263 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
1264 EXPECT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND);
1265 ASSERT_EQ(Status::OK, kvs_.Put(keys[1], kValue1));
1266 ASSERT_EQ(Status::OK, kvs_.Put(keys[2], kValue2));
1267 ASSERT_EQ(Status::OK, kvs_.Delete(keys[1]));
1268 EXPECT_EQ(Status::OK, kvs_.Get(keys[2], &value));
1269 EXPECT_EQ(kValue2, value);
1270 ASSERT_EQ(kvs_.Get(keys[1], &value), Status::NOT_FOUND);
1271 EXPECT_EQ(kvs_.size(), 1u);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001272}
1273
Wyatt Hepler0bde10a2020-02-07 13:35:51 -08001274#endif // USE_MEMORY_BUFFER
1275
Wyatt Heplere3288e12020-02-26 13:05:07 -08001276TEST_F(EmptyInitializedKvs, CallingEraseTwice_NothingWrittenToFlash) {
Wyatt Heplerb7609542020-01-24 10:29:54 -08001277 const uint8_t kValue = 0xDA;
Wyatt Hepler2e568872020-02-03 18:00:00 -08001278 ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue));
1279 ASSERT_EQ(Status::OK, kvs_.Delete(keys[0]));
Wyatt Heplere3288e12020-02-26 13:05:07 -08001280
1281 // Compare before / after checksums to verify that nothing was written.
1282 const uint16_t crc = checksum::CcittCrc16(test_flash.buffer());
1283
Wyatt Hepler2e568872020-02-03 18:00:00 -08001284 EXPECT_EQ(kvs_.Delete(keys[0]), Status::NOT_FOUND);
Wyatt Heplerb7609542020-01-24 10:29:54 -08001285
Wyatt Heplere3288e12020-02-26 13:05:07 -08001286 EXPECT_EQ(crc, checksum::CcittCrc16(test_flash.buffer()));
Wyatt Heplerb7609542020-01-24 10:29:54 -08001287}
1288
Wyatt Hepler2ad60672020-01-21 08:00:16 -08001289} // namespace pw::kvs