blob: 947a3faedc2e607a6e145efa4e40ad0a9a889b73 [file] [log] [blame]
Wyatt Hepler495b6ee2020-02-12 18:58:01 -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 Hepler0af6ad92020-02-13 15:54:46 -080015#include <cstdlib>
Wyatt Hepler023f35b2020-07-01 09:40:50 -070016#include <random>
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080017#include <set>
Wyatt Hepler6d1a6c62020-06-22 15:40:45 -070018#include <span>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080019#include <string>
20#include <string_view>
21#include <unordered_map>
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080022#include <unordered_set>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080023
24#define DUMP_KVS_CONTENTS 0
25
26#if DUMP_KVS_CONTENTS
27#include <iostream>
28#endif // DUMP_KVS_CONTENTS
29
30#include "gtest/gtest.h"
31#include "pw_kvs/crc16_checksum.h"
David Rogersd64cc012020-05-26 12:37:37 -070032#include "pw_kvs/fake_flash_memory.h"
David Rogers5cc5ce82020-03-13 19:19:03 -070033#include "pw_kvs/flash_partition_with_stats.h"
Wyatt Heplerbdd8e5a2020-02-20 19:27:26 -080034#include "pw_kvs/internal/entry.h"
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080035#include "pw_kvs/key_value_store.h"
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080036#include "pw_log/log.h"
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080037
38namespace pw::kvs {
39namespace {
40
41using std::byte;
42
Wyatt Hepler38ce30f2020-02-19 11:48:31 -080043constexpr size_t kMaxEntries = 256;
44constexpr size_t kMaxUsableSectors = 256;
45
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080046constexpr std::string_view kChars =
47 "abcdefghijklmnopqrstuvwxyz"
48 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
49 "0123456789";
50
51struct TestParameters {
52 size_t sector_size;
53 size_t sector_count;
54 size_t sector_alignment;
David Rogersf3884eb2020-03-08 19:21:40 -070055 size_t redundancy;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080056 size_t partition_start_sector;
57 size_t partition_sector_count;
58 size_t partition_alignment;
59};
60
David Rogersc8fe1f52020-02-27 14:04:08 -080061enum Options {
62 kNone,
63 kReinit,
64 kReinitWithFullGC,
65 kReinitWithPartialGC,
66};
67
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080068template <typename T>
69std::set<T> difference(const std::set<T> lhs, const std::set<T> rhs) {
70 std::set<T> diff;
71 std::set_difference(lhs.begin(),
72 lhs.end(),
73 rhs.begin(),
74 rhs.end(),
75 std::inserter(diff, diff.begin()));
76
77 return diff;
78}
79
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080080template <const TestParameters& kParams>
81class KvsTester {
82 public:
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080083 KvsTester()
84 : partition_(&flash_,
85 kParams.partition_start_sector,
86 kParams.partition_sector_count,
87 kParams.partition_alignment),
David Rogers436b3aa2020-08-03 08:44:10 -070088 // For KVS magic value always use a random 32 bit integer rather than a
89 // human readable 4 bytes. See pw_kvs/format.h for more information.
90 kvs_(&partition_, {.magic = 0xc857e51d, .checksum = nullptr}) {
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080091 EXPECT_EQ(OkStatus(), partition_.Erase());
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080092 Status result = kvs_.Init();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080093 EXPECT_EQ(OkStatus(), result);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080094
95 if (!result.ok()) {
96 std::abort();
97 }
98 }
99
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800100 ~KvsTester() { CompareContents(); }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800101
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800102 void Test_RandomValidInputs(int iterations,
103 uint_fast32_t seed,
David Rogersc8fe1f52020-02-27 14:04:08 -0800104 Options options) {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800105 std::mt19937 random(seed);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800106 std::uniform_int_distribution<unsigned> distro;
107 auto random_int = [&] { return distro(random); };
108
109 auto random_string = [&](size_t length) {
110 std::string value;
111 for (size_t i = 0; i < length; ++i) {
112 value.push_back(kChars[random_int() % kChars.size()]);
113 }
114 return value;
115 };
116
David Rogers5cc5ce82020-03-13 19:19:03 -0700117 partition_.ResetCounters();
118
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800119 for (int i = 0; i < iterations; ++i) {
David Rogersc8fe1f52020-02-27 14:04:08 -0800120 if (options != kNone && random_int() % 10 == 0) {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800121 Init();
122 }
123
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800124 // One out of 4 times, delete a key.
125 if (random_int() % 4 == 0) {
126 // Either delete a non-existent key or delete an existing one.
127 if (empty() || random_int() % 8 == 0) {
128 Delete("not_a_key" + std::to_string(random_int()));
129 } else {
Wyatt Heplere541e072020-02-14 09:10:53 -0800130 Delete(RandomPresentKey());
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800131 }
132 } else {
133 std::string key;
134
135 // Either add a new key or replace an existing one.
David Rogersf3884eb2020-03-08 19:21:40 -0700136 // TODO: Using %2 (or any less than 16) fails with redundancy due to KVS
137 // filling up and not being able to write the second redundant entry,
138 // returning error. After re-init() the new key is picked up, resulting
139 // in a mis-match between KVS and the test map.
140 if (empty() || random_int() % 16 == 0) {
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800141 key = random_string(random_int() %
142 (internal::Entry::kMaxKeyLength + 1));
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800143 } else {
Wyatt Heplere541e072020-02-14 09:10:53 -0800144 key = RandomPresentKey();
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800145 }
146
147 Put(key, random_string(random_int() % kMaxValueLength));
148 }
David Rogerscd87c322020-02-27 14:04:08 -0800149
David Rogersc8fe1f52020-02-27 14:04:08 -0800150 if (options == kReinitWithFullGC && random_int() % 250 == 0) {
David Rogerscd87c322020-02-27 14:04:08 -0800151 GCFull();
David Rogersc8fe1f52020-02-27 14:04:08 -0800152 } else if (options == kReinitWithPartialGC && random_int() % 40 == 0) {
David Rogerscd87c322020-02-27 14:04:08 -0800153 GCPartial();
154 }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800155 }
David Rogers5cc5ce82020-03-13 19:19:03 -0700156
157 // Only save for tests that have enough data to be interesting.
158 if (partition_.sector_count() > 2 && partition_.total_erase_count() > 20) {
159 pw::StringBuffer<64> label;
160 label << "Random";
161 label << partition_.sector_count();
162 label << "Sector";
163 label << iterations;
164 label << ((options != kNone) ? "Reinit" : "");
165 label << ((options == kReinitWithFullGC) ? "FullGC" : "");
166 label << ((options == kReinitWithPartialGC) ? "PartialGC" : "");
167 label << ((kvs_.redundancy() > 1) ? "Redundant" : "");
168
169 partition_.SaveStorageStats(kvs_, label.data());
170 }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800171 }
172
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800173 void Test_Put() {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800174 Put("base_key", "base_value");
175 for (int i = 0; i < 100; ++i) {
176 Put("other_key", std::to_string(i));
177 }
178 for (int i = 0; i < 100; ++i) {
179 Put("key_" + std::to_string(i), std::to_string(i));
180 }
181 }
182
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800183 void Test_PutAndDelete_RelocateDeletedEntriesShouldStayDeleted() {
184 for (int i = 0; i < 100; ++i) {
185 std::string str = "key_" + std::to_string(i);
186 Put(str, std::string(kMaxValueLength, '?'));
187 Delete(str);
188 }
189 }
190
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800191 private:
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800192 void CompareContents() {
193#if DUMP_KVS_CONTENTS
194 std::set<std::string> map_keys, kvs_keys;
195
196 std::cout << "/==============================================\\\n";
197 std::cout << "KVS EXPECTED CONTENTS\n";
198 std::cout << "------------------------------------------------\n";
199 std::cout << "Entries: " << map_.size() << '\n';
200 std::cout << "------------------------------------------------\n";
201 for (const auto& [key, value] : map_) {
David Rogersc0104462020-05-08 15:50:23 -0700202 std::cout << key << " = [" << value << "]\n";
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800203 map_keys.insert(key);
204 }
205 std::cout << "\\===============================================/\n";
206
207 std::cout << "/==============================================\\\n";
208 std::cout << "KVS ACTUAL CONTENTS\n";
209 std::cout << "------------------------------------------------\n";
210 std::cout << "Entries: " << kvs_.size() << '\n';
211 std::cout << "------------------------------------------------\n";
212 for (const auto& item : kvs_) {
213 std::cout << item.key() << " = " << item.ValueSize().size() << " B\n";
214 kvs_keys.insert(std::string(item.key()));
215 }
216 std::cout << "\\===============================================/\n";
217
218 auto missing_from_kvs = difference(map_keys, kvs_keys);
219
220 if (!missing_from_kvs.empty()) {
221 std::cout << "MISSING FROM KVS: " << missing_from_kvs.size() << '\n';
222 for (auto& key : missing_from_kvs) {
223 std::cout << key << '\n';
224 }
225 }
226
227 auto missing_from_map = difference(kvs_keys, map_keys);
228 if (!missing_from_map.empty()) {
229 std::cout << "MISSING FROM MAP: " << missing_from_map.size() << '\n';
230 for (auto& key : missing_from_map) {
231 std::cout << key << '\n';
232 }
233 }
234#endif // DUMP_KVS_CONTENTS
235
236 EXPECT_EQ(map_.size(), kvs_.size());
237
238 size_t count = 0;
239
240 for (auto& item : kvs_) {
241 count += 1;
242
243 auto map_entry = map_.find(std::string(item.key()));
244 if (map_entry == map_.end()) {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700245 PW_LOG_CRITICAL(
246 "Entry %s missing from map%s",
247 item.key(),
248 deleted_.count(item.key()) > 0u ? " [was deleted previously]" : "");
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800249 } else if (map_entry != map_.end()) {
250 EXPECT_EQ(map_entry->first, item.key());
251
252 char value[kMaxValueLength + 1] = {};
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800253 EXPECT_EQ(OkStatus(),
Wyatt Hepler6d1a6c62020-06-22 15:40:45 -0700254 item.Get(std::as_writable_bytes(std::span(value))).status());
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800255 EXPECT_EQ(map_entry->second, std::string(value));
256 }
257 }
258
259 EXPECT_EQ(count, map_.size());
260 }
261
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800262 // Adds a key to the KVS, if there is room for it.
263 void Put(const std::string& key, const std::string& value) {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800264 StartOperation("Put", key);
265 EXPECT_LE(value.size(), kMaxValueLength);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800266
Wyatt Hepler6d1a6c62020-06-22 15:40:45 -0700267 Status result = kvs_.Put(key, std::as_bytes(std::span(value)));
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800268
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800269 if (key.empty() || key.size() > internal::Entry::kMaxKeyLength) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700270 EXPECT_EQ(Status::InvalidArgument(), result);
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800271 } else if (map_.size() == kvs_.max_size()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700272 EXPECT_EQ(Status::ResourceExhausted(), result);
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800273 } else if (result.IsResourceExhausted()) {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800274 EXPECT_FALSE(map_.empty());
275 } else if (result.ok()) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800276 map_[key] = value;
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800277 deleted_.erase(key);
278 } else {
279 PW_LOG_CRITICAL("Put: unhandled result %s", result.str());
280 std::abort();
281 }
282
283 FinishOperation("Put", result, key);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800284 }
285
286 // Deletes a key from the KVS if it is present.
287 void Delete(const std::string& key) {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800288 StartOperation("Delete", key);
289
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800290 Status result = kvs_.Delete(key);
291
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800292 if (key.empty() || key.size() > internal::Entry::kMaxKeyLength) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700293 EXPECT_EQ(Status::InvalidArgument(), result);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800294 } else if (map_.count(key) == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700295 EXPECT_EQ(Status::NotFound(), result);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800296 } else if (result.ok()) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800297 map_.erase(key);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800298
299 if (deleted_.count(key) > 0u) {
300 PW_LOG_CRITICAL("Deleted key that was already deleted %s", key.c_str());
301 std::abort();
302 }
303
304 deleted_.insert(key);
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800305 } else if (result.IsResourceExhausted()) {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800306 PW_LOG_WARN("Delete: RESOURCE_EXHAUSTED could not delete key %s",
307 key.c_str());
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800308 } else {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800309 PW_LOG_CRITICAL("Delete: unhandled result \"%s\"", result.str());
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800310 std::abort();
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800311 }
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800312 FinishOperation("Delete", result, key);
313 }
314
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800315 void Init() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700316 StartOperation("Init");
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800317 Status status = kvs_.Init();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800318 EXPECT_EQ(OkStatus(), status);
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700319 FinishOperation("Init", status);
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800320 }
321
David Rogerscd87c322020-02-27 14:04:08 -0800322 void GCFull() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700323 StartOperation("GCFull");
David Rogers9abe3c72020-03-24 19:03:13 -0700324 Status status = kvs_.FullMaintenance();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800325 EXPECT_EQ(OkStatus(), status);
David Rogers35c3f842020-04-22 15:34:05 -0700326
David Rogerscd87c322020-02-27 14:04:08 -0800327 KeyValueStore::StorageStats post_stats = kvs_.GetStorageStats();
David Rogers35c3f842020-04-22 15:34:05 -0700328 if (post_stats.in_use_bytes > ((partition_.size_bytes() * 70) / 100)) {
329 EXPECT_EQ(post_stats.reclaimable_bytes, 0U);
330 }
331
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700332 FinishOperation("GCFull", status);
David Rogerscd87c322020-02-27 14:04:08 -0800333 }
334
335 void GCPartial() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700336 StartOperation("GCPartial");
David Rogerscd87c322020-02-27 14:04:08 -0800337 KeyValueStore::StorageStats pre_stats = kvs_.GetStorageStats();
David Rogers9abe3c72020-03-24 19:03:13 -0700338 Status status = kvs_.PartialMaintenance();
David Rogerscd87c322020-02-27 14:04:08 -0800339 KeyValueStore::StorageStats post_stats = kvs_.GetStorageStats();
340 if (pre_stats.reclaimable_bytes != 0) {
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800341 EXPECT_EQ(OkStatus(), status);
David Rogerscd87c322020-02-27 14:04:08 -0800342 EXPECT_LT(post_stats.reclaimable_bytes, pre_stats.reclaimable_bytes);
343 } else {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700344 EXPECT_EQ(Status::NotFound(), status);
David Rogerscd87c322020-02-27 14:04:08 -0800345 EXPECT_EQ(post_stats.reclaimable_bytes, 0U);
346 }
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700347 FinishOperation("GCPartial", status);
David Rogerscd87c322020-02-27 14:04:08 -0800348 }
349
Wyatt Hepler486ac572020-03-12 15:15:22 -0700350 // Logs that an operation started and checks that the KVS matches the map. If
351 // a key is provided, that is included in the logs.
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700352 void StartOperation(const std::string& operation,
353 const std::string& key = "") {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800354 count_ += 1;
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700355 if (key.empty()) {
356 PW_LOG_DEBUG("[%3u] START %s", count_, operation.c_str());
357 } else {
358 PW_LOG_DEBUG(
359 "[%3u] START %s for '%s'", count_, operation.c_str(), key.c_str());
360 }
361 AbortIfMismatched("Pre-" + operation);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800362 }
363
Wyatt Hepler486ac572020-03-12 15:15:22 -0700364 // Logs that an operation finished and checks that the KVS matches the map.
365 // If a key is provided, that is included in the logs.
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800366 void FinishOperation(const std::string& operation,
367 Status result,
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700368 const std::string& key = "") {
369 if (key.empty()) {
370 PW_LOG_DEBUG(
371 "[%3u] FINISH %s <%s>", count_, operation.c_str(), result.str());
372 } else {
373 PW_LOG_DEBUG("[%3u] FINISH %s <%s> for '%s'",
374 count_,
375 operation.c_str(),
376 result.str(),
377 key.c_str());
378 }
379 AbortIfMismatched(operation);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800380 }
381
382 bool empty() const { return map_.empty(); }
383
Wyatt Heplere541e072020-02-14 09:10:53 -0800384 std::string RandomPresentKey() const {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800385 return map_.empty() ? "" : map_.begin()->second;
386 }
387
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700388 void AbortIfMismatched(const std::string& stage) {
389 if (kvs_.size() != map_.size()) {
390 PW_LOG_CRITICAL("%s: size mismatch", stage.c_str());
391 CompareContents();
392 std::abort();
393 }
394 }
395
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800396 static constexpr size_t kMaxValueLength = 64;
397
David Rogersd64cc012020-05-26 12:37:37 -0700398 static FakeFlashMemoryBuffer<kParams.sector_size,
399 (kParams.sector_count * kParams.redundancy)>
David Rogersf3884eb2020-03-08 19:21:40 -0700400 flash_;
David Rogers5cc5ce82020-03-13 19:19:03 -0700401
402 FlashPartitionWithStatsBuffer<kMaxEntries> partition_;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800403
David Rogersf3884eb2020-03-08 19:21:40 -0700404 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors, kParams.redundancy> kvs_;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800405 std::unordered_map<std::string, std::string> map_;
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800406 std::unordered_set<std::string> deleted_;
407 unsigned count_ = 0;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800408};
409
410template <const TestParameters& kParams>
David Rogersd64cc012020-05-26 12:37:37 -0700411FakeFlashMemoryBuffer<kParams.sector_size,
412 (kParams.sector_count * kParams.redundancy)>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800413 KvsTester<kParams>::flash_ =
David Rogersd64cc012020-05-26 12:37:37 -0700414 FakeFlashMemoryBuffer<kParams.sector_size,
415 (kParams.sector_count * kParams.redundancy)>(
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800416 kParams.sector_alignment);
417
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800418#define _TEST(fixture, test, ...) \
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800419 _TEST_VARIANT(fixture, test, test, __VA_ARGS__)
420
421#define _TEST_VARIANT(fixture, test, variant, ...) \
422 TEST_F(fixture, test##variant) { tester_.Test_##test(__VA_ARGS__); }
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800423
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800424// Defines a test fixture that runs all tests against a flash with the specified
425// parameters.
David Rogersf3884eb2020-03-08 19:21:40 -0700426#define RUN_TESTS_WITH_PARAMETERS(name, ...) \
427 class name : public ::testing::Test { \
428 protected: \
429 static constexpr TestParameters kParams = {__VA_ARGS__}; \
430 \
431 KvsTester<kParams> tester_; \
432 }; \
433 /* Run each test defined in the KvsTester class with these parameters. */ \
434 _TEST(name, Put); \
435 _TEST(name, PutAndDelete_RelocateDeletedEntriesShouldStayDeleted); \
436 _TEST_VARIANT(name, RandomValidInputs, 1, 1000, 6006411, kNone); \
437 _TEST_VARIANT(name, RandomValidInputs, 1WithReinit, 500, 6006411, kReinit); \
438 _TEST_VARIANT(name, RandomValidInputs, 2, 100, 123, kNone); \
439 _TEST_VARIANT(name, RandomValidInputs, 2WithReinit, 100, 123, kReinit); \
440 _TEST_VARIANT(name, \
441 RandomValidInputs, \
442 1ReinitFullGC, \
443 300, \
444 6006411, \
445 kReinitWithFullGC); \
446 _TEST_VARIANT( \
447 name, RandomValidInputs, 2ReinitFullGC, 300, 123, kReinitWithFullGC); \
448 _TEST_VARIANT(name, \
449 RandomValidInputs, \
450 1ReinitPartialGC, \
451 100, \
452 6006411, \
453 kReinitWithPartialGC); \
454 _TEST_VARIANT(name, \
455 RandomValidInputs, \
456 2ReinitPartialGC, \
457 200, \
458 123, \
459 kReinitWithPartialGC); \
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800460 static_assert(true, "Don't forget a semicolon!")
461
462RUN_TESTS_WITH_PARAMETERS(Basic,
463 .sector_size = 4 * 1024,
464 .sector_count = 4,
465 .sector_alignment = 16,
David Rogersf3884eb2020-03-08 19:21:40 -0700466 .redundancy = 1,
467 .partition_start_sector = 0,
468 .partition_sector_count = 4,
469 .partition_alignment = 16);
470
471RUN_TESTS_WITH_PARAMETERS(BasicRedundant,
472 .sector_size = 4 * 1024,
473 .sector_count = 4,
474 .sector_alignment = 16,
475 .redundancy = 2,
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800476 .partition_start_sector = 0,
477 .partition_sector_count = 4,
478 .partition_alignment = 16);
479
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800480RUN_TESTS_WITH_PARAMETERS(LotsOfSmallSectors,
481 .sector_size = 160,
482 .sector_count = 100,
483 .sector_alignment = 32,
David Rogersf3884eb2020-03-08 19:21:40 -0700484 .redundancy = 1,
485 .partition_start_sector = 5,
486 .partition_sector_count = 95,
487 .partition_alignment = 32);
488
489RUN_TESTS_WITH_PARAMETERS(LotsOfSmallSectorsRedundant,
490 .sector_size = 160,
491 .sector_count = 100,
492 .sector_alignment = 32,
493 .redundancy = 2,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800494 .partition_start_sector = 5,
495 .partition_sector_count = 95,
496 .partition_alignment = 32);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800497
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800498RUN_TESTS_WITH_PARAMETERS(OnlyTwoSectors,
499 .sector_size = 4 * 1024,
500 .sector_count = 20,
501 .sector_alignment = 16,
David Rogersf3884eb2020-03-08 19:21:40 -0700502 .redundancy = 1,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800503 .partition_start_sector = 18,
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800504 .partition_sector_count = 2,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800505 .partition_alignment = 64);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800506
507} // namespace
508} // namespace pw::kvs