blob: e2d8f6868f833e47f44a6e03bdb49f808599c63c [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 Hepler495b6ee2020-02-12 18:58:01 -080016#include <random>
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080017#include <set>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080018#include <string>
19#include <string_view>
20#include <unordered_map>
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080021#include <unordered_set>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080022
23#define DUMP_KVS_CONTENTS 0
24
25#if DUMP_KVS_CONTENTS
26#include <iostream>
27#endif // DUMP_KVS_CONTENTS
28
29#include "gtest/gtest.h"
30#include "pw_kvs/crc16_checksum.h"
David Rogers5cc5ce82020-03-13 19:19:03 -070031#include "pw_kvs/flash_partition_with_stats.h"
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080032#include "pw_kvs/in_memory_fake_flash.h"
Wyatt Heplerbdd8e5a2020-02-20 19:27:26 -080033#include "pw_kvs/internal/entry.h"
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080034#include "pw_kvs/key_value_store.h"
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080035#include "pw_log/log.h"
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080036#include "pw_span/span.h"
37
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),
Wyatt Hepler22d0d9f2020-03-05 14:57:11 -080088 kvs_(&partition_, {.magic = 0xBAD'C0D3, .checksum = nullptr}) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080089 EXPECT_EQ(Status::OK, partition_.Erase());
90 Status result = kvs_.Init();
91 EXPECT_EQ(Status::OK, result);
92
93 if (!result.ok()) {
94 std::abort();
95 }
96 }
97
Wyatt Hepler0af6ad92020-02-13 15:54:46 -080098 ~KvsTester() { CompareContents(); }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -080099
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800100 void Test_RandomValidInputs(int iterations,
101 uint_fast32_t seed,
David Rogersc8fe1f52020-02-27 14:04:08 -0800102 Options options) {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800103 std::mt19937 random(seed);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800104 std::uniform_int_distribution<unsigned> distro;
105 auto random_int = [&] { return distro(random); };
106
107 auto random_string = [&](size_t length) {
108 std::string value;
109 for (size_t i = 0; i < length; ++i) {
110 value.push_back(kChars[random_int() % kChars.size()]);
111 }
112 return value;
113 };
114
David Rogers5cc5ce82020-03-13 19:19:03 -0700115 partition_.ResetCounters();
116
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800117 for (int i = 0; i < iterations; ++i) {
David Rogersc8fe1f52020-02-27 14:04:08 -0800118 if (options != kNone && random_int() % 10 == 0) {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800119 Init();
120 }
121
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800122 // One out of 4 times, delete a key.
123 if (random_int() % 4 == 0) {
124 // Either delete a non-existent key or delete an existing one.
125 if (empty() || random_int() % 8 == 0) {
126 Delete("not_a_key" + std::to_string(random_int()));
127 } else {
Wyatt Heplere541e072020-02-14 09:10:53 -0800128 Delete(RandomPresentKey());
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800129 }
130 } else {
131 std::string key;
132
133 // Either add a new key or replace an existing one.
David Rogersf3884eb2020-03-08 19:21:40 -0700134 // TODO: Using %2 (or any less than 16) fails with redundancy due to KVS
135 // filling up and not being able to write the second redundant entry,
136 // returning error. After re-init() the new key is picked up, resulting
137 // in a mis-match between KVS and the test map.
138 if (empty() || random_int() % 16 == 0) {
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800139 key = random_string(random_int() %
140 (internal::Entry::kMaxKeyLength + 1));
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800141 } else {
Wyatt Heplere541e072020-02-14 09:10:53 -0800142 key = RandomPresentKey();
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800143 }
144
145 Put(key, random_string(random_int() % kMaxValueLength));
146 }
David Rogerscd87c322020-02-27 14:04:08 -0800147
David Rogersc8fe1f52020-02-27 14:04:08 -0800148 if (options == kReinitWithFullGC && random_int() % 250 == 0) {
David Rogerscd87c322020-02-27 14:04:08 -0800149 GCFull();
David Rogersc8fe1f52020-02-27 14:04:08 -0800150 } else if (options == kReinitWithPartialGC && random_int() % 40 == 0) {
David Rogerscd87c322020-02-27 14:04:08 -0800151 GCPartial();
152 }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800153 }
David Rogers5cc5ce82020-03-13 19:19:03 -0700154
155 // Only save for tests that have enough data to be interesting.
156 if (partition_.sector_count() > 2 && partition_.total_erase_count() > 20) {
157 pw::StringBuffer<64> label;
158 label << "Random";
159 label << partition_.sector_count();
160 label << "Sector";
161 label << iterations;
162 label << ((options != kNone) ? "Reinit" : "");
163 label << ((options == kReinitWithFullGC) ? "FullGC" : "");
164 label << ((options == kReinitWithPartialGC) ? "PartialGC" : "");
165 label << ((kvs_.redundancy() > 1) ? "Redundant" : "");
166
167 partition_.SaveStorageStats(kvs_, label.data());
168 }
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800169 }
170
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800171 void Test_Put() {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800172 Put("base_key", "base_value");
173 for (int i = 0; i < 100; ++i) {
174 Put("other_key", std::to_string(i));
175 }
176 for (int i = 0; i < 100; ++i) {
177 Put("key_" + std::to_string(i), std::to_string(i));
178 }
179 }
180
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800181 void Test_PutAndDelete_RelocateDeletedEntriesShouldStayDeleted() {
182 for (int i = 0; i < 100; ++i) {
183 std::string str = "key_" + std::to_string(i);
184 Put(str, std::string(kMaxValueLength, '?'));
185 Delete(str);
186 }
187 }
188
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800189 private:
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800190 void CompareContents() {
191#if DUMP_KVS_CONTENTS
192 std::set<std::string> map_keys, kvs_keys;
193
194 std::cout << "/==============================================\\\n";
195 std::cout << "KVS EXPECTED CONTENTS\n";
196 std::cout << "------------------------------------------------\n";
197 std::cout << "Entries: " << map_.size() << '\n';
198 std::cout << "------------------------------------------------\n";
199 for (const auto& [key, value] : map_) {
200 std::cout << key << " = " << value << '\n';
201 map_keys.insert(key);
202 }
203 std::cout << "\\===============================================/\n";
204
205 std::cout << "/==============================================\\\n";
206 std::cout << "KVS ACTUAL CONTENTS\n";
207 std::cout << "------------------------------------------------\n";
208 std::cout << "Entries: " << kvs_.size() << '\n';
209 std::cout << "------------------------------------------------\n";
210 for (const auto& item : kvs_) {
211 std::cout << item.key() << " = " << item.ValueSize().size() << " B\n";
212 kvs_keys.insert(std::string(item.key()));
213 }
214 std::cout << "\\===============================================/\n";
215
216 auto missing_from_kvs = difference(map_keys, kvs_keys);
217
218 if (!missing_from_kvs.empty()) {
219 std::cout << "MISSING FROM KVS: " << missing_from_kvs.size() << '\n';
220 for (auto& key : missing_from_kvs) {
221 std::cout << key << '\n';
222 }
223 }
224
225 auto missing_from_map = difference(kvs_keys, map_keys);
226 if (!missing_from_map.empty()) {
227 std::cout << "MISSING FROM MAP: " << missing_from_map.size() << '\n';
228 for (auto& key : missing_from_map) {
229 std::cout << key << '\n';
230 }
231 }
232#endif // DUMP_KVS_CONTENTS
233
234 EXPECT_EQ(map_.size(), kvs_.size());
235
236 size_t count = 0;
237
238 for (auto& item : kvs_) {
239 count += 1;
240
241 auto map_entry = map_.find(std::string(item.key()));
242 if (map_entry == map_.end()) {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700243 PW_LOG_CRITICAL(
244 "Entry %s missing from map%s",
245 item.key(),
246 deleted_.count(item.key()) > 0u ? " [was deleted previously]" : "");
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800247 } else if (map_entry != map_.end()) {
248 EXPECT_EQ(map_entry->first, item.key());
249
250 char value[kMaxValueLength + 1] = {};
251 EXPECT_EQ(Status::OK,
252 item.Get(as_writable_bytes(span(value))).status());
253 EXPECT_EQ(map_entry->second, std::string(value));
254 }
255 }
256
257 EXPECT_EQ(count, map_.size());
258 }
259
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800260 // Adds a key to the KVS, if there is room for it.
261 void Put(const std::string& key, const std::string& value) {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800262 StartOperation("Put", key);
263 EXPECT_LE(value.size(), kMaxValueLength);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800264
265 Status result = kvs_.Put(key, as_bytes(span(value)));
266
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800267 if (key.empty() || key.size() > internal::Entry::kMaxKeyLength) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800268 EXPECT_EQ(Status::INVALID_ARGUMENT, result);
Wyatt Hepler38ce30f2020-02-19 11:48:31 -0800269 } else if (map_.size() == kvs_.max_size()) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800270 EXPECT_EQ(Status::RESOURCE_EXHAUSTED, result);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800271 } else if (result == Status::RESOURCE_EXHAUSTED) {
272 EXPECT_FALSE(map_.empty());
273 } else if (result.ok()) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800274 map_[key] = value;
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800275 deleted_.erase(key);
276 } else {
277 PW_LOG_CRITICAL("Put: unhandled result %s", result.str());
278 std::abort();
279 }
280
281 FinishOperation("Put", result, key);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800282 }
283
284 // Deletes a key from the KVS if it is present.
285 void Delete(const std::string& key) {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800286 StartOperation("Delete", key);
287
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800288 Status result = kvs_.Delete(key);
289
Wyatt Hepler1fc11042020-02-19 17:17:51 -0800290 if (key.empty() || key.size() > internal::Entry::kMaxKeyLength) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800291 EXPECT_EQ(Status::INVALID_ARGUMENT, result);
292 } else if (map_.count(key) == 0) {
293 EXPECT_EQ(Status::NOT_FOUND, result);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800294 } else if (result.ok()) {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800295 map_.erase(key);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800296
297 if (deleted_.count(key) > 0u) {
298 PW_LOG_CRITICAL("Deleted key that was already deleted %s", key.c_str());
299 std::abort();
300 }
301
302 deleted_.insert(key);
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800303 } else if (result == Status::RESOURCE_EXHAUSTED) {
304 PW_LOG_WARN("Delete: RESOURCE_EXHAUSTED could not delete key %s",
305 key.c_str());
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800306 } else {
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800307 PW_LOG_CRITICAL("Delete: unhandled result \"%s\"", result.str());
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800308 std::abort();
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800309 }
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800310 FinishOperation("Delete", result, key);
311 }
312
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800313 void Init() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700314 StartOperation("Init");
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800315 Status status = kvs_.Init();
316 EXPECT_EQ(Status::OK, status);
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700317 FinishOperation("Init", status);
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800318 }
319
David Rogerscd87c322020-02-27 14:04:08 -0800320 void GCFull() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700321 StartOperation("GCFull");
David Rogers9abe3c72020-03-24 19:03:13 -0700322 Status status = kvs_.FullMaintenance();
David Rogerscd87c322020-02-27 14:04:08 -0800323 EXPECT_EQ(Status::OK, status);
324 KeyValueStore::StorageStats post_stats = kvs_.GetStorageStats();
325 EXPECT_EQ(post_stats.reclaimable_bytes, 0U);
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700326 FinishOperation("GCFull", status);
David Rogerscd87c322020-02-27 14:04:08 -0800327 }
328
329 void GCPartial() {
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700330 StartOperation("GCPartial");
David Rogerscd87c322020-02-27 14:04:08 -0800331 KeyValueStore::StorageStats pre_stats = kvs_.GetStorageStats();
David Rogers9abe3c72020-03-24 19:03:13 -0700332 Status status = kvs_.PartialMaintenance();
David Rogerscd87c322020-02-27 14:04:08 -0800333 KeyValueStore::StorageStats post_stats = kvs_.GetStorageStats();
334 if (pre_stats.reclaimable_bytes != 0) {
David Rogersa2562b52020-03-05 15:30:05 -0800335 EXPECT_EQ(Status::OK, status);
David Rogerscd87c322020-02-27 14:04:08 -0800336 EXPECT_LT(post_stats.reclaimable_bytes, pre_stats.reclaimable_bytes);
337 } else {
David Rogersa2562b52020-03-05 15:30:05 -0800338 EXPECT_EQ(Status::NOT_FOUND, status);
David Rogerscd87c322020-02-27 14:04:08 -0800339 EXPECT_EQ(post_stats.reclaimable_bytes, 0U);
340 }
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700341 FinishOperation("GCPartial", status);
David Rogerscd87c322020-02-27 14:04:08 -0800342 }
343
Wyatt Hepler486ac572020-03-12 15:15:22 -0700344 // Logs that an operation started and checks that the KVS matches the map. If
345 // a key is provided, that is included in the logs.
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700346 void StartOperation(const std::string& operation,
347 const std::string& key = "") {
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800348 count_ += 1;
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700349 if (key.empty()) {
350 PW_LOG_DEBUG("[%3u] START %s", count_, operation.c_str());
351 } else {
352 PW_LOG_DEBUG(
353 "[%3u] START %s for '%s'", count_, operation.c_str(), key.c_str());
354 }
355 AbortIfMismatched("Pre-" + operation);
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800356 }
357
Wyatt Hepler486ac572020-03-12 15:15:22 -0700358 // Logs that an operation finished and checks that the KVS matches the map.
359 // If a key is provided, that is included in the logs.
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800360 void FinishOperation(const std::string& operation,
361 Status result,
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700362 const std::string& key = "") {
363 if (key.empty()) {
364 PW_LOG_DEBUG(
365 "[%3u] FINISH %s <%s>", count_, operation.c_str(), result.str());
366 } else {
367 PW_LOG_DEBUG("[%3u] FINISH %s <%s> for '%s'",
368 count_,
369 operation.c_str(),
370 result.str(),
371 key.c_str());
372 }
373 AbortIfMismatched(operation);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800374 }
375
376 bool empty() const { return map_.empty(); }
377
Wyatt Heplere541e072020-02-14 09:10:53 -0800378 std::string RandomPresentKey() const {
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800379 return map_.empty() ? "" : map_.begin()->second;
380 }
381
Wyatt Hepler7bc766e2020-03-10 10:06:20 -0700382 void AbortIfMismatched(const std::string& stage) {
383 if (kvs_.size() != map_.size()) {
384 PW_LOG_CRITICAL("%s: size mismatch", stage.c_str());
385 CompareContents();
386 std::abort();
387 }
388 }
389
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800390 static constexpr size_t kMaxValueLength = 64;
391
David Rogersf3884eb2020-03-08 19:21:40 -0700392 static FakeFlashBuffer<kParams.sector_size,
393 (kParams.sector_count * kParams.redundancy)>
394 flash_;
David Rogers5cc5ce82020-03-13 19:19:03 -0700395
396 FlashPartitionWithStatsBuffer<kMaxEntries> partition_;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800397
David Rogersf3884eb2020-03-08 19:21:40 -0700398 KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors, kParams.redundancy> kvs_;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800399 std::unordered_map<std::string, std::string> map_;
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800400 std::unordered_set<std::string> deleted_;
401 unsigned count_ = 0;
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800402};
403
404template <const TestParameters& kParams>
David Rogersf3884eb2020-03-08 19:21:40 -0700405FakeFlashBuffer<kParams.sector_size,
406 (kParams.sector_count * kParams.redundancy)>
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800407 KvsTester<kParams>::flash_ =
David Rogersf3884eb2020-03-08 19:21:40 -0700408 FakeFlashBuffer<kParams.sector_size,
409 (kParams.sector_count * kParams.redundancy)>(
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800410 kParams.sector_alignment);
411
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800412#define _TEST(fixture, test, ...) \
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800413 _TEST_VARIANT(fixture, test, test, __VA_ARGS__)
414
415#define _TEST_VARIANT(fixture, test, variant, ...) \
416 TEST_F(fixture, test##variant) { tester_.Test_##test(__VA_ARGS__); }
Wyatt Hepler0af6ad92020-02-13 15:54:46 -0800417
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800418// Defines a test fixture that runs all tests against a flash with the specified
419// parameters.
David Rogersf3884eb2020-03-08 19:21:40 -0700420#define RUN_TESTS_WITH_PARAMETERS(name, ...) \
421 class name : public ::testing::Test { \
422 protected: \
423 static constexpr TestParameters kParams = {__VA_ARGS__}; \
424 \
425 KvsTester<kParams> tester_; \
426 }; \
427 /* Run each test defined in the KvsTester class with these parameters. */ \
428 _TEST(name, Put); \
429 _TEST(name, PutAndDelete_RelocateDeletedEntriesShouldStayDeleted); \
430 _TEST_VARIANT(name, RandomValidInputs, 1, 1000, 6006411, kNone); \
431 _TEST_VARIANT(name, RandomValidInputs, 1WithReinit, 500, 6006411, kReinit); \
432 _TEST_VARIANT(name, RandomValidInputs, 2, 100, 123, kNone); \
433 _TEST_VARIANT(name, RandomValidInputs, 2WithReinit, 100, 123, kReinit); \
434 _TEST_VARIANT(name, \
435 RandomValidInputs, \
436 1ReinitFullGC, \
437 300, \
438 6006411, \
439 kReinitWithFullGC); \
440 _TEST_VARIANT( \
441 name, RandomValidInputs, 2ReinitFullGC, 300, 123, kReinitWithFullGC); \
442 _TEST_VARIANT(name, \
443 RandomValidInputs, \
444 1ReinitPartialGC, \
445 100, \
446 6006411, \
447 kReinitWithPartialGC); \
448 _TEST_VARIANT(name, \
449 RandomValidInputs, \
450 2ReinitPartialGC, \
451 200, \
452 123, \
453 kReinitWithPartialGC); \
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800454 static_assert(true, "Don't forget a semicolon!")
455
456RUN_TESTS_WITH_PARAMETERS(Basic,
457 .sector_size = 4 * 1024,
458 .sector_count = 4,
459 .sector_alignment = 16,
David Rogersf3884eb2020-03-08 19:21:40 -0700460 .redundancy = 1,
461 .partition_start_sector = 0,
462 .partition_sector_count = 4,
463 .partition_alignment = 16);
464
465RUN_TESTS_WITH_PARAMETERS(BasicRedundant,
466 .sector_size = 4 * 1024,
467 .sector_count = 4,
468 .sector_alignment = 16,
469 .redundancy = 2,
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800470 .partition_start_sector = 0,
471 .partition_sector_count = 4,
472 .partition_alignment = 16);
473
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800474RUN_TESTS_WITH_PARAMETERS(LotsOfSmallSectors,
475 .sector_size = 160,
476 .sector_count = 100,
477 .sector_alignment = 32,
David Rogersf3884eb2020-03-08 19:21:40 -0700478 .redundancy = 1,
479 .partition_start_sector = 5,
480 .partition_sector_count = 95,
481 .partition_alignment = 32);
482
483RUN_TESTS_WITH_PARAMETERS(LotsOfSmallSectorsRedundant,
484 .sector_size = 160,
485 .sector_count = 100,
486 .sector_alignment = 32,
487 .redundancy = 2,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800488 .partition_start_sector = 5,
489 .partition_sector_count = 95,
490 .partition_alignment = 32);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800491
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800492RUN_TESTS_WITH_PARAMETERS(OnlyTwoSectors,
493 .sector_size = 4 * 1024,
494 .sector_count = 20,
495 .sector_alignment = 16,
David Rogersf3884eb2020-03-08 19:21:40 -0700496 .redundancy = 1,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800497 .partition_start_sector = 18,
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800498 .partition_sector_count = 2,
Wyatt Heplere2a36a22020-02-20 17:01:38 -0800499 .partition_alignment = 64);
Wyatt Hepler495b6ee2020-02-12 18:58:01 -0800500
501} // namespace
502} // namespace pw::kvs