Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1 | // 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 Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 15 | #define DUMP_KVS_STATE_TO_FILE 0 |
| 16 | #define USE_MEMORY_BUFFER 1 |
| 17 | #define PW_LOG_USE_ULTRA_SHORT_NAMES 1 |
| 18 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 19 | #include "pw_kvs/key_value_store.h" |
| 20 | |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 21 | #include <array> |
| 22 | #include <cstdio> |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 23 | #include <cstring> |
Wyatt Hepler | bc6332c | 2020-02-10 16:34:19 -0800 | [diff] [blame] | 24 | |
| 25 | #if DUMP_KVS_STATE_TO_FILE |
Wyatt Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 26 | #include <vector> |
Wyatt Hepler | bc6332c | 2020-02-10 16:34:19 -0800 | [diff] [blame] | 27 | #endif // DUMP_KVS_STATE_TO_FILE |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 28 | |
| 29 | #include "gtest/gtest.h" |
| 30 | #include "pw_checksum/ccitt_crc16.h" |
Wyatt Hepler | ec4b935 | 2020-01-31 15:51:50 -0800 | [diff] [blame] | 31 | #include "pw_kvs/crc16_checksum.h" |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 32 | #include "pw_kvs/flash_memory.h" |
Wyatt Hepler | bdd8e5a | 2020-02-20 19:27:26 -0800 | [diff] [blame] | 33 | #include "pw_kvs/internal/entry.h" |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 34 | #include "pw_kvs_private/byte_utils.h" |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 35 | #include "pw_kvs_private/macros.h" |
| 36 | #include "pw_log/log.h" |
Wyatt Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 37 | #include "pw_span/span.h" |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 38 | #include "pw_status/status.h" |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 39 | #include "pw_string/string_builder.h" |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 40 | |
| 41 | #if USE_MEMORY_BUFFER |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 42 | #include "pw_kvs/in_memory_fake_flash.h" |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 43 | #endif // USE_MEMORY_BUFFER |
| 44 | |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 45 | namespace pw::kvs { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 46 | namespace { |
| 47 | |
Wyatt Hepler | 1fc1104 | 2020-02-19 17:17:51 -0800 | [diff] [blame] | 48 | using internal::EntryHeader; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 49 | using std::byte; |
| 50 | |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 51 | constexpr size_t kMaxEntries = 256; |
| 52 | constexpr size_t kMaxUsableSectors = 256; |
| 53 | |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 54 | // Test the functions in byte_utils.h. Create a byte array with AsBytes and |
| 55 | // ByteStr and check that its contents are correct. |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 56 | constexpr std::array<char, 2> kTestArray = {'a', 'b'}; |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 57 | |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 58 | constexpr auto kAsBytesTest = AsBytes( |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 59 | 'a', uint16_t(1), uint8_t(23), kTestArray, ByteStr("c"), uint64_t(-1)); |
| 60 | |
| 61 | static_assert(kAsBytesTest.size() == 15); |
| 62 | static_assert(kAsBytesTest[0] == std::byte{'a'}); |
| 63 | static_assert(kAsBytesTest[1] == std::byte{1}); |
| 64 | static_assert(kAsBytesTest[2] == std::byte{0}); |
| 65 | static_assert(kAsBytesTest[3] == std::byte{23}); |
| 66 | static_assert(kAsBytesTest[4] == std::byte{'a'}); |
| 67 | static_assert(kAsBytesTest[5] == std::byte{'b'}); |
| 68 | static_assert(kAsBytesTest[6] == std::byte{'c'}); |
| 69 | static_assert(kAsBytesTest[7] == std::byte{0xff}); |
| 70 | static_assert(kAsBytesTest[8] == std::byte{0xff}); |
| 71 | static_assert(kAsBytesTest[9] == std::byte{0xff}); |
| 72 | static_assert(kAsBytesTest[10] == std::byte{0xff}); |
| 73 | static_assert(kAsBytesTest[11] == std::byte{0xff}); |
| 74 | static_assert(kAsBytesTest[12] == std::byte{0xff}); |
| 75 | static_assert(kAsBytesTest[13] == std::byte{0xff}); |
| 76 | static_assert(kAsBytesTest[14] == std::byte{0xff}); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 77 | |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 78 | // Test that the ConvertsToSpan trait correctly idenitifies types that convert |
| 79 | // to span. |
| 80 | static_assert(!ConvertsToSpan<int>()); |
| 81 | static_assert(!ConvertsToSpan<void>()); |
| 82 | static_assert(!ConvertsToSpan<std::byte>()); |
| 83 | static_assert(!ConvertsToSpan<std::byte*>()); |
| 84 | |
| 85 | static_assert(ConvertsToSpan<std::array<int, 5>>()); |
| 86 | static_assert(ConvertsToSpan<decltype("Hello!")>()); |
| 87 | |
| 88 | static_assert(ConvertsToSpan<std::string_view>()); |
| 89 | static_assert(ConvertsToSpan<std::string_view&>()); |
| 90 | static_assert(ConvertsToSpan<std::string_view&&>()); |
| 91 | |
| 92 | static_assert(ConvertsToSpan<const std::string_view>()); |
| 93 | static_assert(ConvertsToSpan<const std::string_view&>()); |
| 94 | static_assert(ConvertsToSpan<const std::string_view&&>()); |
| 95 | |
Wyatt Hepler | fac8113 | 2020-02-27 17:26:33 -0800 | [diff] [blame] | 96 | static_assert(ConvertsToSpan<bool[1]>()); |
| 97 | static_assert(ConvertsToSpan<char[35]>()); |
| 98 | static_assert(ConvertsToSpan<const int[35]>()); |
| 99 | |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 100 | static_assert(ConvertsToSpan<span<int>>()); |
| 101 | static_assert(ConvertsToSpan<span<byte>>()); |
| 102 | static_assert(ConvertsToSpan<span<const int*>>()); |
| 103 | static_assert(ConvertsToSpan<span<bool>&&>()); |
| 104 | static_assert(ConvertsToSpan<const span<bool>&>()); |
| 105 | static_assert(ConvertsToSpan<span<bool>&&>()); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 106 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 107 | // This is a self contained flash unit with both memory and a single partition. |
| 108 | template <uint32_t sector_size_bytes, uint16_t sector_count> |
| 109 | struct 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 Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 115 | FakeFlashBuffer<sector_size_bytes, sector_count> memory; |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 116 | FlashPartition partition; |
| 117 | |
| 118 | public: |
Wyatt Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 119 | #if DUMP_KVS_STATE_TO_FILE |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 120 | 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 Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 150 | Status Dump(const char*) { return Status::OK; } |
| 151 | #endif // DUMP_KVS_STATE_TO_FILE |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 152 | }; |
| 153 | |
| 154 | typedef FlashWithPartitionFake<4 * 128 /*sector size*/, 6 /*sectors*/> Flash; |
| 155 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 156 | #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 Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 159 | FakeFlashBuffer<4 * 1024, 4> test_flash( |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 160 | 16); // 4 x 4k sectors, 16 byte alignment |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 161 | FlashPartition test_partition(&test_flash, 0, test_flash.sector_count()); |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 162 | FakeFlashBuffer<1024, 60> large_test_flash(8); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 163 | FlashPartition large_test_partition(&large_test_flash, |
| 164 | 0, |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 165 | large_test_flash.sector_count()); |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 166 | #else // TODO: Test with real flash |
| 167 | FlashPartition& test_partition = FlashExternalTestPartition(); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 168 | #endif // USE_MEMORY_BUFFER |
| 169 | |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 170 | std::array<byte, 512> buffer; |
| 171 | constexpr std::array<const char*, 3> keys{"TestKey1", "Key2", "TestKey3"}; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 172 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 173 | ChecksumCrc16 checksum; |
Wyatt Hepler | 88adfe8 | 2020-02-20 19:33:27 -0800 | [diff] [blame] | 174 | constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = &checksum}; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 175 | |
| 176 | size_t RoundUpForAlignment(size_t size) { |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 177 | return AlignUp(size, test_partition.alignment_bytes()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | // This class gives attributes of KVS that we are testing against |
| 181 | class KvsAttributes { |
| 182 | public: |
| 183 | KvsAttributes(size_t key_size, size_t data_size) |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 184 | : chunk_header_size_(RoundUpForAlignment(sizeof(EntryHeader))), |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 185 | data_size_(RoundUpForAlignment(data_size)), |
| 186 | key_size_(RoundUpForAlignment(key_size)), |
| 187 | erase_size_(chunk_header_size_ + key_size_), |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 188 | min_put_size_( |
| 189 | RoundUpForAlignment(chunk_header_size_ + key_size_ + data_size_)) {} |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 190 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 191 | 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 Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 198 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 205 | class EmptyInitializedKvs : public ::testing::Test { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 206 | protected: |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 207 | EmptyInitializedKvs() : kvs_(&test_partition, format) { |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 208 | test_partition.Erase(); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 209 | ASSERT_EQ(Status::OK, kvs_.Init()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 210 | } |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 211 | |
| 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 Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 244 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 245 | }; |
| 246 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 247 | } // namespace |
| 248 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 249 | TEST_F(EmptyInitializedKvs, Put_SameKeySameValueRepeatedly_AlignedEntries) { |
Wyatt Hepler | ad0a793 | 2020-02-06 08:20:38 -0800 | [diff] [blame] | 250 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 257 | TEST_F(EmptyInitializedKvs, Put_SameKeySameValueRepeatedly_UnalignedEntries) { |
Wyatt Hepler | ad0a793 | 2020-02-06 08:20:38 -0800 | [diff] [blame] | 258 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 265 | TEST_F(EmptyInitializedKvs, Put_SameKeyDifferentValuesRepeatedly) { |
Wyatt Hepler | 116d116 | 2020-02-06 09:42:59 -0800 | [diff] [blame] | 266 | 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 Hepler | ad0a793 | 2020-02-06 08:20:38 -0800 | [diff] [blame] | 272 | } |
| 273 | } |
| 274 | |
Wyatt Hepler | 5406a67 | 2020-02-18 15:42:38 -0800 | [diff] [blame] | 275 | TEST_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 Hepler | fac8113 | 2020-02-27 17:26:33 -0800 | [diff] [blame] | 291 | TEST_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 | |
| 301 | TEST_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 | |
| 311 | TEST_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 Hepler | 5f6efc0 | 2020-02-18 16:54:31 -0800 | [diff] [blame] | 326 | TEST_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 | |
| 336 | TEST_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 | |
| 346 | TEST_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 | |
| 356 | TEST_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 Hepler | fac8113 | 2020-02-27 17:26:33 -0800 | [diff] [blame] | 366 | TEST_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 | |
| 374 | TEST_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 | |
| 382 | TEST_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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 390 | TEST_F(EmptyInitializedKvs, Delete_GetDeletedKey_ReturnsNotFound) { |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 391 | 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 Hepler | 50f7077 | 2020-02-13 11:25:10 -0800 | [diff] [blame] | 395 | EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("kEy").status()); |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 396 | } |
| 397 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 398 | TEST_F(EmptyInitializedKvs, Delete_AddBackKey_PersistsAfterInitialization) { |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 399 | 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 Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 408 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> new_kvs(&test_partition, |
| 409 | format); |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 410 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 418 | TEST_F(EmptyInitializedKvs, Delete_AllItems_KvsIsEmpty) { |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 419 | 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 Hepler | 2d40169 | 2020-02-13 16:01:23 -0800 | [diff] [blame] | 426 | TEST_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 | |
| 444 | TEST_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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 463 | TEST_F(EmptyInitializedKvs, Iteration_Empty_ByReference) { |
Wyatt Hepler | ce0da52 | 2020-02-04 16:56:44 -0800 | [diff] [blame] | 464 | for (const KeyValueStore::Item& entry : kvs_) { |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 465 | FAIL(); // The KVS is empty; this shouldn't execute. |
| 466 | static_cast<void>(entry); |
| 467 | } |
| 468 | } |
| 469 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 470 | TEST_F(EmptyInitializedKvs, Iteration_Empty_ByValue) { |
Wyatt Hepler | ce0da52 | 2020-02-04 16:56:44 -0800 | [diff] [blame] | 471 | for (KeyValueStore::Item entry : kvs_) { |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 472 | FAIL(); // The KVS is empty; this shouldn't execute. |
| 473 | static_cast<void>(entry); |
| 474 | } |
| 475 | } |
| 476 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 477 | TEST_F(EmptyInitializedKvs, Iteration_OneItem) { |
Wyatt Hepler | 5f6efc0 | 2020-02-18 16:54:31 -0800 | [diff] [blame] | 478 | ASSERT_EQ(Status::OK, kvs_.Put("kEy", as_bytes(span("123")))); |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 479 | |
| 480 | for (KeyValueStore::Item entry : kvs_) { |
Wyatt Hepler | a00d1ef | 2020-02-14 14:31:26 -0800 | [diff] [blame] | 481 | EXPECT_STREQ(entry.key(), "kEy"); // Make sure null-terminated. |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 482 | |
Wyatt Hepler | 5f6efc0 | 2020-02-18 16:54:31 -0800 | [diff] [blame] | 483 | char buffer[sizeof("123")] = {}; |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 484 | EXPECT_EQ(Status::OK, entry.Get(&buffer)); |
Wyatt Hepler | 5f6efc0 | 2020-02-18 16:54:31 -0800 | [diff] [blame] | 485 | EXPECT_STREQ("123", buffer); |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | TEST_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 Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 498 | } |
| 499 | } |
| 500 | |
Wyatt Hepler | fac8113 | 2020-02-27 17:26:33 -0800 | [diff] [blame] | 501 | TEST_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 | |
| 511 | TEST_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 | |
| 521 | TEST_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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 531 | TEST_F(EmptyInitializedKvs, Iteration_EmptyAfterDeletion) { |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 532 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 541 | TEST_F(EmptyInitializedKvs, FuzzTest) { |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 542 | if (test_partition.sector_size_bytes() < 4 * 1024 || |
| 543 | test_partition.sector_count() < 4) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 544 | PW_LOG_INFO("Sectors too small, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 545 | return; // TODO: Test could be generalized |
| 546 | } |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 547 | const char* key1 = "Buf1"; |
| 548 | const char* key2 = "Buf2"; |
| 549 | const size_t kLargestBufSize = 3 * 1024; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 550 | static byte buf1[kLargestBufSize]; |
| 551 | static byte buf2[kLargestBufSize]; |
| 552 | std::memset(buf1, 1, sizeof(buf1)); |
| 553 | std::memset(buf2, 2, sizeof(buf2)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 554 | |
| 555 | // Start with things in KVS |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 556 | ASSERT_EQ(Status::OK, kvs_.Put(key1, buf1)); |
| 557 | ASSERT_EQ(Status::OK, kvs_.Put(key2, buf2)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 558 | for (size_t j = 0; j < keys.size(); j++) { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 559 | ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 560 | } |
| 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 Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 568 | ASSERT_EQ(Status::OK, kvs_.Put("some_data", j)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 569 | } |
| 570 | // Delete and re-add everything |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 571 | 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 Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 575 | for (size_t j = 0; j < keys.size(); j++) { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 576 | ASSERT_EQ(Status::OK, kvs_.Delete(keys[j])); |
| 577 | ASSERT_EQ(Status::OK, kvs_.Put(keys[j], j)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 578 | } |
| 579 | |
| 580 | // Re-enable and verify |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 581 | ASSERT_EQ(Status::OK, kvs_.Init()); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 582 | static byte buf[4 * 1024]; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 583 | ASSERT_EQ(Status::OK, kvs_.Get(key1, span(buf, size1)).status()); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 584 | ASSERT_EQ(std::memcmp(buf, buf1, size1), 0); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 585 | ASSERT_EQ(Status::OK, kvs_.Get(key2, span(buf, size2)).status()); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 586 | ASSERT_EQ(std::memcmp(buf2, buf2, size2), 0); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 587 | for (size_t j = 0; j < keys.size(); j++) { |
| 588 | size_t ret = 1000; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 589 | ASSERT_EQ(Status::OK, kvs_.Get(keys[j], &ret)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 590 | ASSERT_EQ(ret, j); |
| 591 | } |
| 592 | } |
| 593 | } |
| 594 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 595 | TEST_F(EmptyInitializedKvs, Basic) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 596 | // Add some data |
| 597 | uint8_t value1 = 0xDA; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 598 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 599 | kvs_.Put(keys[0], as_bytes(span(&value1, sizeof(value1))))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 600 | |
| 601 | uint32_t value2 = 0xBAD0301f; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 602 | ASSERT_EQ(Status::OK, kvs_.Put(keys[1], value2)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 603 | |
| 604 | // Verify data |
| 605 | uint32_t test2; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 606 | EXPECT_EQ(Status::OK, kvs_.Get(keys[1], &test2)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 607 | uint8_t test1; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 608 | ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &test1)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 609 | |
| 610 | EXPECT_EQ(test1, value1); |
| 611 | EXPECT_EQ(test2, value2); |
| 612 | |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 613 | // Delete a key |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 614 | EXPECT_EQ(Status::OK, kvs_.Delete(keys[0])); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 615 | |
| 616 | // Verify it was erased |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 617 | EXPECT_EQ(kvs_.Get(keys[0], &test1), Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 618 | test2 = 0; |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 619 | ASSERT_EQ( |
| 620 | Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 621 | kvs_.Get(keys[1], span(reinterpret_cast<byte*>(&test2), sizeof(test2))) |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 622 | .status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 623 | EXPECT_EQ(test2, value2); |
| 624 | |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 625 | // Delete other key |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 626 | kvs_.Delete(keys[1]); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 627 | |
| 628 | // Verify it was erased |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 629 | EXPECT_EQ(kvs_.size(), 0u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 630 | } |
| 631 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 632 | #define ASSERT_OK(expr) ASSERT_EQ(Status::OK, expr) |
| 633 | #define EXPECT_OK(expr) EXPECT_EQ(Status::OK, expr) |
| 634 | |
Wyatt Hepler | 595cf01 | 2020-02-05 09:31:02 -0800 | [diff] [blame] | 635 | TEST(InMemoryKvs, WriteOneKeyMultipleTimes) { |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 636 | // 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 Hepler | 88adfe8 | 2020-02-20 19:33:27 -0800 | [diff] [blame] | 649 | constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr}; |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 650 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition, |
| 651 | format); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 652 | ASSERT_OK(kvs.Init()); |
| 653 | |
| 654 | // Write the same entry many times. |
| 655 | const char* key = "abcd"; |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 656 | const size_t num_writes = 99; |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 657 | uint32_t written_value; |
| 658 | EXPECT_EQ(kvs.size(), (reload == 0) ? 0 : 1u); |
| 659 | for (uint32_t i = 0; i < num_writes; ++i) { |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 660 | DBG("PUT #%zu for key %s with value %zu", size_t(i), key, size_t(i)); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 661 | |
| 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 Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 668 | DBG("GET final value for key: %s", key); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 669 | uint32_t actual_value; |
| 670 | EXPECT_OK(kvs.Get(key, &actual_value)); |
| 671 | EXPECT_EQ(actual_value, written_value); |
| 672 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 673 | 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 | |
| 682 | TEST(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 Hepler | 88adfe8 | 2020-02-20 19:33:27 -0800 | [diff] [blame] | 688 | constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr}; |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 689 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition, |
| 690 | format); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 691 | 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 Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 699 | DBG("PUT #%zu for key %s with value %zu", i, key.c_str(), i); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 700 | |
| 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 Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 705 | flash.Dump("WritingMultipleKeysIncreasesSize.bin"); |
| 706 | } |
| 707 | |
| 708 | TEST(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 Hepler | 88adfe8 | 2020-02-20 19:33:27 -0800 | [diff] [blame] | 714 | constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr}; |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 715 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition, |
| 716 | format); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 717 | ASSERT_OK(kvs.Init()); |
| 718 | |
| 719 | // Add two entries with different keys and values. |
| 720 | const char* key = "Key1"; |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 721 | DBG("PUT value for key: %s", key); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 722 | uint8_t written_value = 0xDA; |
| 723 | ASSERT_OK(kvs.Put(key, written_value)); |
| 724 | EXPECT_EQ(kvs.size(), 1u); |
| 725 | |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 726 | DBG("GET value for key: %s", key); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 727 | 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 | |
| 734 | TEST(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 Hepler | 88adfe8 | 2020-02-20 19:33:27 -0800 | [diff] [blame] | 743 | constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr}; |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 744 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&flash.partition, |
| 745 | format); |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 746 | ASSERT_OK(kvs.Init()); |
| 747 | |
| 748 | // Add two entries with different keys and values. |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 749 | uint8_t value1 = 0xDA; |
| 750 | ASSERT_OK(kvs.Put(key1, as_bytes(span(&value1, sizeof(value1))))); |
| 751 | EXPECT_EQ(kvs.size(), 1u); |
| 752 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 753 | uint32_t value2 = 0xBAD0301f; |
| 754 | ASSERT_OK(kvs.Put(key2, value2)); |
| 755 | EXPECT_EQ(kvs.size(), 2u); |
| 756 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 757 | // Verify data |
| 758 | uint32_t test2; |
| 759 | EXPECT_OK(kvs.Get(key2, &test2)); |
| 760 | |
Keir Mierle | 8c352dc | 2020-02-02 13:58:19 -0800 | [diff] [blame] | 761 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 770 | TEST_F(EmptyInitializedKvs, MaxKeyLength) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 771 | // Add some data |
| 772 | char key[16] = "123456789abcdef"; // key length 15 (without \0) |
| 773 | int value = 1; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 774 | ASSERT_EQ(Status::OK, kvs_.Put(key, value)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 775 | |
| 776 | // Verify data |
| 777 | int test = 0; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 778 | ASSERT_EQ(Status::OK, kvs_.Get(key, &test)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 779 | EXPECT_EQ(test, value); |
| 780 | |
Wyatt Hepler | 6c24c06 | 2020-02-05 15:30:49 -0800 | [diff] [blame] | 781 | // Delete a key |
Wyatt Hepler | 50f7077 | 2020-02-13 11:25:10 -0800 | [diff] [blame] | 782 | EXPECT_EQ(Status::OK, kvs_.Delete(key)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 783 | |
| 784 | // Verify it was erased |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 785 | EXPECT_EQ(kvs_.Get(key, &test), Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 786 | } |
| 787 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 788 | TEST_F(EmptyInitializedKvs, LargeBuffers) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 789 | // 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 797 | const size_t kMinSize = kvs_attr.MinPutSize() * keys.size(); |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 798 | const size_t kAvailSectorSpace = |
| 799 | test_partition.sector_size_bytes() * (test_partition.sector_count() - 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 800 | if (kAvailSectorSpace < kMinSize) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 801 | PW_LOG_INFO("KVS too small, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 802 | return; |
| 803 | } |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 804 | |
| 805 | // Add and verify |
| 806 | for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 807 | std::memset(buffer.data(), add_idx, buffer.size()); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 808 | ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer)); |
| 809 | EXPECT_EQ(kvs_.size(), add_idx + 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 810 | for (unsigned verify_idx = 0; verify_idx <= add_idx; verify_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 811 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 812 | ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 813 | for (unsigned i = 0; i < buffer.size(); i++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 814 | EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 815 | } |
| 816 | } |
| 817 | } |
| 818 | |
| 819 | // Erase and verify |
| 820 | for (unsigned erase_idx = 0; erase_idx < keys.size(); erase_idx++) { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 821 | ASSERT_EQ(Status::OK, kvs_.Delete(keys[erase_idx])); |
| 822 | EXPECT_EQ(kvs_.size(), keys.size() - erase_idx - 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 823 | for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 824 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 825 | if (verify_idx <= erase_idx) { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 826 | ASSERT_EQ(kvs_.Get(keys[verify_idx], buffer).status(), |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 827 | Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 828 | } else { |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 829 | ASSERT_EQ(Status::OK, kvs_.Get(keys[verify_idx], buffer).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 830 | for (uint32_t i = 0; i < buffer.size(); i++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 831 | EXPECT_EQ(buffer[i], static_cast<byte>(verify_idx)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 832 | } |
| 833 | } |
| 834 | } |
| 835 | } |
| 836 | } |
| 837 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 838 | TEST_F(EmptyInitializedKvs, Enable) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 839 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 844 | const size_t kMinSize = kvs_attr.MinPutSize() * keys.size(); |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 845 | const size_t kAvailSectorSpace = |
| 846 | test_partition.sector_size_bytes() * (test_partition.sector_count() - 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 847 | if (kAvailSectorSpace < kMinSize) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 848 | PW_LOG_INFO("KVS too small, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 849 | return; |
| 850 | } |
| 851 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 852 | // Add some items |
| 853 | for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 854 | std::memset(buffer.data(), add_idx, buffer.size()); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 855 | ASSERT_EQ(Status::OK, kvs_.Put(keys[add_idx], buffer)); |
| 856 | EXPECT_EQ(kvs_.size(), add_idx + 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 857 | } |
| 858 | |
| 859 | // Enable different KVS which should be able to properly setup the same map |
| 860 | // from what is stored in flash. |
Wyatt Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 861 | static KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_local( |
| 862 | &test_partition, format); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 863 | ASSERT_EQ(Status::OK, kvs_local.Init()); |
| 864 | EXPECT_EQ(kvs_local.size(), keys.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 865 | |
| 866 | // Ensure adding to new KVS works |
| 867 | uint8_t value = 0xDA; |
| 868 | const char* key = "new_key"; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 869 | ASSERT_EQ(Status::OK, kvs_local.Put(key, value)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 870 | uint8_t test; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 871 | ASSERT_EQ(Status::OK, kvs_local.Get(key, &test)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 872 | EXPECT_EQ(value, test); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 873 | EXPECT_EQ(kvs_local.size(), keys.size() + 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 874 | |
| 875 | // Verify previous data |
| 876 | for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 877 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 878 | ASSERT_EQ(Status::OK, kvs_local.Get(keys[verify_idx], buffer).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 879 | for (uint32_t i = 0; i < buffer.size(); i++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 880 | EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 881 | } |
| 882 | } |
| 883 | } |
| 884 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 885 | TEST_F(EmptyInitializedKvs, MultiSector) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 886 | // Calculate number of elements to ensure multiple sectors are required. |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 887 | uint16_t add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 888 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 889 | if (kvs_.max_size() < add_count) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 890 | PW_LOG_INFO("Sector size too large, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 891 | return; // this chip has very large sectors, test won't work |
| 892 | } |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 893 | if (test_partition.sector_count() < 3) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 894 | PW_LOG_INFO("Not enough sectors, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 895 | 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 Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 900 | std::memset(buffer.data(), add_idx, buffer.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 901 | snprintf(key, sizeof(key), "key_%u", add_idx); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 902 | ASSERT_EQ(Status::OK, kvs_.Put(key, buffer)); |
| 903 | EXPECT_EQ(kvs_.size(), add_idx + 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 904 | } |
| 905 | |
| 906 | for (unsigned verify_idx = 0; verify_idx < add_count; verify_idx++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 907 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 908 | snprintf(key, sizeof(key), "key_%u", verify_idx); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 909 | ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 910 | for (uint32_t i = 0; i < buffer.size(); i++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 911 | EXPECT_EQ(static_cast<unsigned>(buffer[i]), verify_idx); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 912 | } |
| 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 Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 918 | ASSERT_EQ(Status::OK, kvs_.Delete(key)); |
| 919 | EXPECT_EQ(kvs_.size(), add_count - erase_idx - 1); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 920 | } |
| 921 | } |
| 922 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 923 | TEST_F(EmptyInitializedKvs, RewriteValue) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 924 | // Write first value |
| 925 | const uint8_t kValue1 = 0xDA; |
| 926 | const uint8_t kValue2 = 0x12; |
| 927 | const char* key = "the_key"; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 928 | ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue1, 1)))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 929 | |
| 930 | // Verify |
| 931 | uint8_t value; |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 932 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 933 | kvs_.Get(key, as_writable_bytes(span(&value, 1))).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 934 | EXPECT_EQ(kValue1, value); |
| 935 | |
| 936 | // Write new value for key |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 937 | ASSERT_EQ(Status::OK, kvs_.Put(key, as_bytes(span(&kValue2, 1)))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 938 | |
| 939 | // Verify |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 940 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 941 | kvs_.Get(key, as_writable_bytes(span(&value, 1))).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 942 | EXPECT_EQ(kValue2, value); |
| 943 | |
| 944 | // Verify only 1 element exists |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 945 | EXPECT_EQ(kvs_.size(), 1u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 946 | } |
| 947 | |
David Rogers | cf680ab | 2020-02-12 23:28:32 -0800 | [diff] [blame] | 948 | TEST_F(EmptyInitializedKvs, RepeatingValueWithOtherData) { |
David Rogers | be744c1 | 2020-02-12 19:19:40 -0800 | [diff] [blame] | 949 | 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 Rogers | cf680ab | 2020-02-12 23:28:32 -0800 | [diff] [blame] | 962 | // TOD0: Add KVS erase |
David Rogers | be744c1 | 2020-02-12 19:19:40 -0800 | [diff] [blame] | 963 | // 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 Hepler | 5f6efc0 | 2020-02-18 16:54:31 -0800 | [diff] [blame] | 972 | ASSERT_EQ(Status::OK, result.status()); |
David Rogers | be744c1 | 2020-02-12 19:19:40 -0800 | [diff] [blame] | 973 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1007 | TEST_F(EmptyInitializedKvs, OffsetRead) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1008 | const char* key = "the_key"; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1009 | constexpr size_t kReadSize = 16; // needs to be a multiple of alignment |
| 1010 | constexpr size_t kTestBufferSize = kReadSize * 10; |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1011 | ASSERT_GT(buffer.size(), kTestBufferSize); |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 1012 | ASSERT_LE(kTestBufferSize, 0xFFu); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1013 | |
| 1014 | // Write the entire buffer |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1015 | for (size_t i = 0; i < kTestBufferSize; i++) { |
| 1016 | buffer[i] = byte(i); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1017 | } |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1018 | ASSERT_EQ(Status::OK, kvs_.Put(key, span(buffer.data(), kTestBufferSize))); |
| 1019 | EXPECT_EQ(kvs_.size(), 1u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1020 | |
| 1021 | // Read in small chunks and verify |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1022 | for (unsigned i = 0; i < kTestBufferSize / kReadSize; i++) { |
| 1023 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 1024 | 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 Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1036 | for (unsigned j = 0; j < kReadSize; j++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1037 | ASSERT_EQ(static_cast<unsigned>(buffer[j]), j + i * kReadSize); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1038 | } |
| 1039 | } |
| 1040 | } |
| 1041 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1042 | TEST_F(EmptyInitializedKvs, MultipleRewrite) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1043 | // Calculate number of elements to ensure multiple sectors are required. |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1044 | unsigned add_count = (test_partition.sector_size_bytes() / buffer.size()) + 1; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1045 | |
| 1046 | const char* key = "the_key"; |
| 1047 | constexpr uint8_t kGoodVal = 0x60; |
| 1048 | constexpr uint8_t kBadVal = 0xBA; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1049 | std::memset(buffer.data(), kBadVal, buffer.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1050 | for (unsigned add_idx = 0; add_idx < add_count; add_idx++) { |
| 1051 | if (add_idx == add_count - 1) { // last value |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1052 | std::memset(buffer.data(), kGoodVal, buffer.size()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1053 | } |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1054 | ASSERT_EQ(Status::OK, kvs_.Put(key, buffer)); |
| 1055 | EXPECT_EQ(kvs_.size(), 1u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1056 | } |
| 1057 | |
| 1058 | // Verify |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1059 | std::memset(buffer.data(), 0, buffer.size()); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1060 | ASSERT_EQ(Status::OK, kvs_.Get(key, buffer).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1061 | for (uint32_t i = 0; i < buffer.size(); i++) { |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1062 | ASSERT_EQ(buffer[i], static_cast<byte>(kGoodVal)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1063 | } |
| 1064 | } |
| 1065 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1066 | TEST_F(EmptyInitializedKvs, FillSector) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1067 | 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1071 | int bytes_remaining = test_partition.sector_size_bytes(); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1072 | constexpr byte kKey0Pattern = byte{0xBA}; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1073 | |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1074 | std::memset( |
| 1075 | buffer.data(), static_cast<int>(kKey0Pattern), kvs_attr.DataSize()); |
| 1076 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1077 | kvs_.Put(keys[0], span(buffer.data(), kvs_attr.DataSize()))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1078 | bytes_remaining -= kvs_attr.MinPutSize(); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1079 | std::memset(buffer.data(), 1, kvs_attr.DataSize()); |
| 1080 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1081 | kvs_.Put(keys[2], span(buffer.data(), kvs_attr.DataSize()))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1082 | bytes_remaining -= kvs_attr.MinPutSize(); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1083 | EXPECT_EQ(kvs_.size(), 2u); |
| 1084 | ASSERT_EQ(Status::OK, kvs_.Delete(keys[2])); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1085 | bytes_remaining -= kvs_attr.EraseSize(); |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1086 | EXPECT_EQ(kvs_.size(), 1u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1087 | |
| 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 Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1093 | std::memset(buffer.data(), 0, kvs_attr.DataSize()); |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1094 | ASSERT_EQ( |
| 1095 | Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1096 | kvs_.Get(keys[0], span(buffer.data(), kvs_attr.DataSize())).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1097 | for (uint32_t i = 0; i < kvs_attr.DataSize(); i++) { |
| 1098 | EXPECT_EQ(buffer[i], kKey0Pattern); |
| 1099 | } |
| 1100 | } |
| 1101 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1102 | TEST_F(EmptyInitializedKvs, Interleaved) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1103 | const uint8_t kValue1 = 0xDA; |
| 1104 | const uint8_t kValue2 = 0x12; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1105 | uint8_t value; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1106 | 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 Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1114 | EXPECT_EQ(kValue2, value); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1115 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1116 | EXPECT_EQ(kvs_.size(), 1u); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1117 | } |
| 1118 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1119 | TEST_F(EmptyInitializedKvs, DeleteAndReinitialize) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1120 | // Write value |
| 1121 | const uint8_t kValue = 0xDA; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1122 | ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1123 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1124 | ASSERT_EQ(Status::OK, kvs_.Delete(keys[0])); |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1125 | uint8_t value; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1126 | ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1127 | |
| 1128 | // Reset KVS, ensure captured at enable |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1129 | ASSERT_EQ(Status::OK, kvs_.Init()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1130 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1131 | ASSERT_EQ(kvs_.Get(keys[0], &value), Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1132 | } |
| 1133 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1134 | TEST_F(EmptyInitializedKvs, TemplatedPutAndGet) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1135 | // Store a value with the convenience method. |
| 1136 | const uint32_t kValue = 0x12345678; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1137 | ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1138 | |
| 1139 | // Read it back with the other convenience method. |
| 1140 | uint32_t value; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1141 | ASSERT_EQ(Status::OK, kvs_.Get(keys[0], &value)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1142 | 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 Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1147 | ASSERT_EQ(kvs_.Get(keys[0], &small_value), Status::INVALID_ARGUMENT); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1148 | ASSERT_EQ(small_value, kSmallValue); |
| 1149 | } |
| 1150 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1151 | // 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 Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1154 | TEST_F(EmptyInitializedKvs, FillSector2) { |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1155 | if (test_partition.sector_count() < 3) { |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 1156 | PW_LOG_INFO("Not enough sectors, skipping test."); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1157 | return; // need at least 3 sectors |
| 1158 | } |
| 1159 | |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1160 | // Start of by filling flash sector to near full |
| 1161 | constexpr int kHalfBufferSize = buffer.size() / 2; |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1162 | const int kSizeToFill = test_partition.sector_size_bytes() - kHalfBufferSize; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1163 | 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 Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1171 | size_t alignment = test_partition.alignment_bytes(); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1172 | // Starts on second sector since it will try to keep first sector free |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 1173 | FlashPartition::Address read_address = |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1174 | 2 * test_partition.sector_size_bytes() - alignment; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1175 | for (; read_address > 0; read_address -= alignment) { |
| 1176 | bool is_erased = false; |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 1177 | ASSERT_EQ( |
| 1178 | Status::OK, |
Wyatt Hepler | 4da1fcb | 2020-01-30 17:32:18 -0800 | [diff] [blame] | 1179 | test_partition.IsRegionErased(read_address, alignment, &is_erased)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1180 | if (is_erased) { |
| 1181 | new_keyvalue_size += alignment; |
| 1182 | } else { |
| 1183 | break; |
| 1184 | } |
| 1185 | } |
| 1186 | |
Wyatt Hepler | 16b0452 | 2020-02-07 16:00:14 -0800 | [diff] [blame] | 1187 | size_t expected_remaining = test_partition.sector_size_bytes() - kSizeToFill; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1188 | ASSERT_EQ(new_keyvalue_size, expected_remaining); |
| 1189 | |
| 1190 | const char* kNewKey = "NewKey"; |
| 1191 | constexpr size_t kValueLessThanChunkHeaderSize = 2; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1192 | constexpr auto kTestPattern = byte{0xBA}; |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1193 | new_keyvalue_size -= kValueLessThanChunkHeaderSize; |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1194 | std::memset(buffer.data(), static_cast<int>(kTestPattern), new_keyvalue_size); |
| 1195 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1196 | kvs_.Put(kNewKey, span(buffer.data(), new_keyvalue_size))); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1197 | |
| 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 Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1200 | ASSERT_EQ(Status::OK, kvs_.Init()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1201 | |
| 1202 | // Might as well check that new key-value is what we expect it to be |
Wyatt Hepler | acaacf9 | 2020-01-24 10:58:30 -0800 | [diff] [blame] | 1203 | ASSERT_EQ(Status::OK, |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1204 | kvs_.Get(kNewKey, span(buffer.data(), new_keyvalue_size)).status()); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1205 | for (size_t i = 0; i < new_keyvalue_size; i++) { |
| 1206 | EXPECT_EQ(buffer[i], kTestPattern); |
| 1207 | } |
| 1208 | } |
| 1209 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1210 | TEST_F(EmptyInitializedKvs, ValueSize_Positive) { |
Wyatt Hepler | cdd6dfc | 2020-02-18 12:04:04 -0800 | [diff] [blame] | 1211 | constexpr auto kData = AsBytes('h', 'i', '!'); |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1212 | ASSERT_EQ(Status::OK, kvs_.Put("TheKey", kData)); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1213 | |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1214 | auto result = kvs_.ValueSize("TheKey"); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1215 | |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1216 | EXPECT_EQ(Status::OK, result.status()); |
| 1217 | EXPECT_EQ(kData.size(), result.size()); |
| 1218 | } |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1219 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1220 | TEST_F(EmptyInitializedKvs, ValueSize_Zero) { |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1221 | ASSERT_EQ(Status::OK, kvs_.Put("TheKey", as_bytes(span("123", 3)))); |
| 1222 | auto result = kvs_.ValueSize("TheKey"); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1223 | |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1224 | EXPECT_EQ(Status::OK, result.status()); |
| 1225 | EXPECT_EQ(3u, result.size()); |
| 1226 | } |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1227 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1228 | TEST_F(EmptyInitializedKvs, ValueSize_InvalidKey) { |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1229 | EXPECT_EQ(Status::INVALID_ARGUMENT, kvs_.ValueSize("").status()); |
| 1230 | } |
| 1231 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1232 | TEST_F(EmptyInitializedKvs, ValueSize_MissingKey) { |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1233 | EXPECT_EQ(Status::NOT_FOUND, kvs_.ValueSize("Not in there").status()); |
| 1234 | } |
| 1235 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1236 | TEST_F(EmptyInitializedKvs, ValueSize_DeletedKey) { |
Wyatt Hepler | ed163b0 | 2020-02-03 17:49:32 -0800 | [diff] [blame] | 1237 | 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 Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1241 | } |
| 1242 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1243 | #if USE_MEMORY_BUFFER |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1244 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1245 | class 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 Hepler | 38ce30f | 2020-02-19 11:48:31 -0800 | [diff] [blame] | 1254 | KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs_; |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1255 | }; |
| 1256 | |
| 1257 | TEST_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 Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1272 | } |
| 1273 | |
Wyatt Hepler | 0bde10a | 2020-02-07 13:35:51 -0800 | [diff] [blame] | 1274 | #endif // USE_MEMORY_BUFFER |
| 1275 | |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 1276 | TEST_F(EmptyInitializedKvs, CallingEraseTwice_NothingWrittenToFlash) { |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1277 | const uint8_t kValue = 0xDA; |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1278 | ASSERT_EQ(Status::OK, kvs_.Put(keys[0], kValue)); |
| 1279 | ASSERT_EQ(Status::OK, kvs_.Delete(keys[0])); |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 1280 | |
| 1281 | // Compare before / after checksums to verify that nothing was written. |
| 1282 | const uint16_t crc = checksum::CcittCrc16(test_flash.buffer()); |
| 1283 | |
Wyatt Hepler | 2e56887 | 2020-02-03 18:00:00 -0800 | [diff] [blame] | 1284 | EXPECT_EQ(kvs_.Delete(keys[0]), Status::NOT_FOUND); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1285 | |
Wyatt Hepler | e3288e1 | 2020-02-26 13:05:07 -0800 | [diff] [blame] | 1286 | EXPECT_EQ(crc, checksum::CcittCrc16(test_flash.buffer())); |
Wyatt Hepler | b760954 | 2020-01-24 10:29:54 -0800 | [diff] [blame] | 1287 | } |
| 1288 | |
Wyatt Hepler | 2ad6067 | 2020-01-21 08:00:16 -0800 | [diff] [blame] | 1289 | } // namespace pw::kvs |