1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/internal/entry_cache.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/fake_flash_memory.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/flash_memory.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/internal/hash.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/internal/key_descriptor.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker namespace pw::kvs::internal {
25*61c4878aSAndroid Build Coastguard Worker namespace {
26*61c4878aSAndroid Build Coastguard Worker
27*61c4878aSAndroid Build Coastguard Worker using std::byte;
28*61c4878aSAndroid Build Coastguard Worker
29*61c4878aSAndroid Build Coastguard Worker class EmptyEntryCache : public ::testing::Test {
30*61c4878aSAndroid Build Coastguard Worker protected:
31*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kMaxEntries = 32;
32*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kRedundancy = 3;
33*61c4878aSAndroid Build Coastguard Worker
EmptyEntryCache()34*61c4878aSAndroid Build Coastguard Worker EmptyEntryCache() : entries_(descriptors_, addresses_, kRedundancy) {}
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker Vector<KeyDescriptor, kMaxEntries> descriptors_;
37*61c4878aSAndroid Build Coastguard Worker EntryCache::AddressList<kMaxEntries, kRedundancy> addresses_;
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Worker EntryCache entries_;
40*61c4878aSAndroid Build Coastguard Worker };
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker constexpr char kTheKey[] = "The Key";
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker constexpr KeyDescriptor kDescriptor = {.key_hash = Hash(kTheKey),
45*61c4878aSAndroid Build Coastguard Worker .transaction_id = 123,
46*61c4878aSAndroid Build Coastguard Worker .state = EntryState::kValid};
47*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNew)48*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNew) {
49*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata = entries_.AddNew(kDescriptor, 5);
50*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.key_hash, metadata.hash());
51*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.transaction_id, metadata.transaction_id());
52*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.state, metadata.state());
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(5u, metadata.first_address());
55*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, metadata.addresses().size());
56*61c4878aSAndroid Build Coastguard Worker }
57*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,EntryMetadata_AddNewAddress)58*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, EntryMetadata_AddNewAddress) {
59*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata = entries_.AddNew(kDescriptor, 100);
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker metadata.AddNewAddress(999);
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(2u, metadata.addresses().size());
64*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(100u, metadata.first_address());
65*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(100u, metadata.addresses()[0]);
66*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(999u, metadata.addresses()[1]);
67*61c4878aSAndroid Build Coastguard Worker }
68*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,EntryMetadata_Reset)69*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, EntryMetadata_Reset) {
70*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata = entries_.AddNew(kDescriptor, 100);
71*61c4878aSAndroid Build Coastguard Worker metadata.AddNewAddress(999);
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker metadata.Reset(
74*61c4878aSAndroid Build Coastguard Worker {.key_hash = 987, .transaction_id = 5, .state = EntryState::kDeleted},
75*61c4878aSAndroid Build Coastguard Worker 8888);
76*61c4878aSAndroid Build Coastguard Worker
77*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(987u, metadata.hash());
78*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(5u, metadata.transaction_id());
79*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(EntryState::kDeleted, metadata.state());
80*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, metadata.addresses().size());
81*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(8888u, metadata.first_address());
82*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(8888u, metadata.addresses()[0]);
83*61c4878aSAndroid Build Coastguard Worker }
84*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNewOrUpdateExisting_NewEntry)85*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNewOrUpdateExisting_NewEntry) {
86*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
87*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 1000, 2000));
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entries_.present_entries());
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker for (const EntryMetadata& entry : entries_) {
92*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1000u, entry.first_address());
93*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.key_hash, entry.hash());
94*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.transaction_id, entry.transaction_id());
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker }
97*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNewOrUpdateExisting_NewEntry_Full)98*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNewOrUpdateExisting_NewEntry_Full) {
99*61c4878aSAndroid Build Coastguard Worker for (uint32_t i = 0; i < kMaxEntries; ++i) {
100*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ( // Fill up the cache
101*61c4878aSAndroid Build Coastguard Worker OkStatus(),
102*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting({i, i, EntryState::kValid}, i, 1));
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(kMaxEntries, entries_.total_entries());
105*61c4878aSAndroid Build Coastguard Worker ASSERT_TRUE(entries_.full());
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Status::ResourceExhausted(),
108*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 1000, 1));
109*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kMaxEntries, entries_.total_entries());
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNewOrUpdateExisting_UpdatedEntry)112*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNewOrUpdateExisting_UpdatedEntry) {
113*61c4878aSAndroid Build Coastguard Worker KeyDescriptor kd = kDescriptor;
114*61c4878aSAndroid Build Coastguard Worker kd.transaction_id += 3;
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), entries_.AddNewOrUpdateExisting(kd, 3210, 2000));
117*61c4878aSAndroid Build Coastguard Worker
118*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entries_.present_entries());
119*61c4878aSAndroid Build Coastguard Worker
120*61c4878aSAndroid Build Coastguard Worker for (const EntryMetadata& entry : entries_) {
121*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(3210u, entry.first_address());
122*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.key_hash, entry.hash());
123*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.transaction_id + 3, entry.transaction_id());
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker }
126*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNewOrUpdateExisting_AddDuplicateEntry)127*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNewOrUpdateExisting_AddDuplicateEntry) {
128*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
129*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 1000, 2000));
130*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
131*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 3000, 2000));
132*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
133*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 7000, 2000));
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker // Duplicates beyond the redundancy are ignored.
136*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
137*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 9000, 2000));
138*61c4878aSAndroid Build Coastguard Worker
139*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entries_.present_entries());
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker for (const EntryMetadata& entry : entries_) {
142*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(3u, entry.addresses().size());
143*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1000u, entry.addresses()[0]);
144*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(3000u, entry.addresses()[1]);
145*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(7000u, entry.addresses()[2]);
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.key_hash, entry.hash());
148*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.transaction_id, entry.transaction_id());
149*61c4878aSAndroid Build Coastguard Worker }
150*61c4878aSAndroid Build Coastguard Worker }
151*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,AddNewOrUpdateExisting_AddDuplicateEntryInSameSector)152*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, AddNewOrUpdateExisting_AddDuplicateEntryInSameSector) {
153*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
154*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 1000, 1000));
155*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Status::DataLoss(),
156*61c4878aSAndroid Build Coastguard Worker entries_.AddNewOrUpdateExisting(kDescriptor, 1950, 1000));
157*61c4878aSAndroid Build Coastguard Worker
158*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entries_.present_entries());
159*61c4878aSAndroid Build Coastguard Worker
160*61c4878aSAndroid Build Coastguard Worker for (const EntryMetadata& entry : entries_) {
161*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entry.addresses().size());
162*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1000u, entry.addresses()[0]);
163*61c4878aSAndroid Build Coastguard Worker
164*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.key_hash, entry.hash());
165*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kDescriptor.transaction_id, entry.transaction_id());
166*61c4878aSAndroid Build Coastguard Worker }
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,Iterator_MutableFromConst_CanModify)169*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, Iterator_MutableFromConst_CanModify) {
170*61c4878aSAndroid Build Coastguard Worker entries_.AddNew(kDescriptor, 1);
171*61c4878aSAndroid Build Coastguard Worker EntryCache::iterator it = static_cast<const EntryCache&>(entries_).begin();
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker static_assert(kRedundancy > 1);
174*61c4878aSAndroid Build Coastguard Worker it->AddNewAddress(1234);
175*61c4878aSAndroid Build Coastguard Worker
176*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, it->first_address());
177*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, (*it).addresses()[0]);
178*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1234u, it->addresses()[1]);
179*61c4878aSAndroid Build Coastguard Worker }
180*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,Iterator_Const)181*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, Iterator_Const) {
182*61c4878aSAndroid Build Coastguard Worker entries_.AddNew(kDescriptor, 99);
183*61c4878aSAndroid Build Coastguard Worker EntryCache::const_iterator it = entries_.cbegin();
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(99u, (*it).first_address());
186*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(99u, it->first_address());
187*61c4878aSAndroid Build Coastguard Worker }
188*61c4878aSAndroid Build Coastguard Worker
TEST_F(EmptyEntryCache,Iterator_Const_CanBeAssignedFromMutable)189*61c4878aSAndroid Build Coastguard Worker TEST_F(EmptyEntryCache, Iterator_Const_CanBeAssignedFromMutable) {
190*61c4878aSAndroid Build Coastguard Worker entries_.AddNew(kDescriptor, 99);
191*61c4878aSAndroid Build Coastguard Worker EntryCache::const_iterator it = entries_.begin();
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(99u, (*it).first_address());
194*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(99u, it->first_address());
195*61c4878aSAndroid Build Coastguard Worker }
196*61c4878aSAndroid Build Coastguard Worker
197*61c4878aSAndroid Build Coastguard Worker constexpr size_t kSectorSize = 64;
198*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kMagic = 0xa14ae726;
199*61c4878aSAndroid Build Coastguard Worker // For KVS entry magic value always use a random 32 bit integer rather than a
200*61c4878aSAndroid Build Coastguard Worker // human readable 4 bytes. See pw_kvs/format.h for more information.
201*61c4878aSAndroid Build Coastguard Worker constexpr auto kTheEntry =
202*61c4878aSAndroid Build Coastguard Worker bytes::Concat(uint32_t(kMagic), // magic
203*61c4878aSAndroid Build Coastguard Worker uint32_t(0), // checksum
204*61c4878aSAndroid Build Coastguard Worker uint8_t(0), // alignment (16 B)
205*61c4878aSAndroid Build Coastguard Worker uint8_t(sizeof(kTheKey) - 1), // key length
206*61c4878aSAndroid Build Coastguard Worker uint16_t(0), // value size
207*61c4878aSAndroid Build Coastguard Worker uint32_t(123), // transaction ID
208*61c4878aSAndroid Build Coastguard Worker bytes::String(kTheKey));
209*61c4878aSAndroid Build Coastguard Worker constexpr std::array<byte, kSectorSize - kTheEntry.size() % kSectorSize>
210*61c4878aSAndroid Build Coastguard Worker kPadding1{};
211*61c4878aSAndroid Build Coastguard Worker constexpr size_t kSize1 = kTheEntry.size() + kPadding1.size();
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard Worker constexpr char kCollision1[] = "9FDC";
214*61c4878aSAndroid Build Coastguard Worker constexpr char kCollision2[] = "axzzK";
215*61c4878aSAndroid Build Coastguard Worker
216*61c4878aSAndroid Build Coastguard Worker // For KVS entry magic value always use a random 32 bit integer rather than a
217*61c4878aSAndroid Build Coastguard Worker // human readable 4 bytes. See pw_kvs/format.h for more information.
218*61c4878aSAndroid Build Coastguard Worker constexpr auto kCollisionEntry =
219*61c4878aSAndroid Build Coastguard Worker bytes::Concat(uint32_t(kMagic), // magic
220*61c4878aSAndroid Build Coastguard Worker uint32_t(0), // checksum
221*61c4878aSAndroid Build Coastguard Worker uint8_t(0), // alignment (16 B)
222*61c4878aSAndroid Build Coastguard Worker uint8_t(sizeof(kCollision1) - 1), // key length
223*61c4878aSAndroid Build Coastguard Worker uint16_t(0), // value size
224*61c4878aSAndroid Build Coastguard Worker uint32_t(123), // transaction ID
225*61c4878aSAndroid Build Coastguard Worker bytes::String(kCollision1));
226*61c4878aSAndroid Build Coastguard Worker constexpr std::array<byte, kSectorSize - kCollisionEntry.size() % kSectorSize>
227*61c4878aSAndroid Build Coastguard Worker kPadding2{};
228*61c4878aSAndroid Build Coastguard Worker constexpr size_t kSize2 = kCollisionEntry.size() + kPadding2.size();
229*61c4878aSAndroid Build Coastguard Worker
230*61c4878aSAndroid Build Coastguard Worker // For KVS entry magic value always use a random 32 bit integer rather than a
231*61c4878aSAndroid Build Coastguard Worker // human readable 4 bytes. See pw_kvs/format.h for more information.
232*61c4878aSAndroid Build Coastguard Worker constexpr auto kDeletedEntry =
233*61c4878aSAndroid Build Coastguard Worker bytes::Concat(uint32_t(kMagic), // magic
234*61c4878aSAndroid Build Coastguard Worker uint32_t(0), // checksum
235*61c4878aSAndroid Build Coastguard Worker uint8_t(0), // alignment (16 B)
236*61c4878aSAndroid Build Coastguard Worker uint8_t(sizeof("delorted") - 1), // key length
237*61c4878aSAndroid Build Coastguard Worker uint16_t(0xffff), // value size (deleted)
238*61c4878aSAndroid Build Coastguard Worker uint32_t(123), // transaction ID
239*61c4878aSAndroid Build Coastguard Worker bytes::String("delorted"));
240*61c4878aSAndroid Build Coastguard Worker constexpr std::array<byte, kSectorSize - kDeletedEntry.size() % kSectorSize>
241*61c4878aSAndroid Build Coastguard Worker kPadding3{};
242*61c4878aSAndroid Build Coastguard Worker
243*61c4878aSAndroid Build Coastguard Worker // For KVS entry magic value always use a random 32 bit integer rather than a
244*61c4878aSAndroid Build Coastguard Worker // human readable 4 bytes. See pw_kvs/format.h for more information.
245*61c4878aSAndroid Build Coastguard Worker constexpr EntryFormat kFormat{.magic = uint32_t(kMagic), .checksum = nullptr};
246*61c4878aSAndroid Build Coastguard Worker
247*61c4878aSAndroid Build Coastguard Worker class InitializedEntryCache : public EmptyEntryCache {
248*61c4878aSAndroid Build Coastguard Worker protected:
249*61c4878aSAndroid Build Coastguard Worker static_assert(Hash(kCollision1) == Hash(kCollision2));
250*61c4878aSAndroid Build Coastguard Worker
InitializedEntryCache()251*61c4878aSAndroid Build Coastguard Worker InitializedEntryCache()
252*61c4878aSAndroid Build Coastguard Worker : flash_(bytes::Concat(kTheEntry,
253*61c4878aSAndroid Build Coastguard Worker kPadding1,
254*61c4878aSAndroid Build Coastguard Worker kTheEntry,
255*61c4878aSAndroid Build Coastguard Worker kPadding1,
256*61c4878aSAndroid Build Coastguard Worker kCollisionEntry,
257*61c4878aSAndroid Build Coastguard Worker kPadding2,
258*61c4878aSAndroid Build Coastguard Worker kDeletedEntry,
259*61c4878aSAndroid Build Coastguard Worker kPadding3)),
260*61c4878aSAndroid Build Coastguard Worker partition_(&flash_),
261*61c4878aSAndroid Build Coastguard Worker sectors_(sector_descriptors_, partition_, nullptr),
262*61c4878aSAndroid Build Coastguard Worker format_(kFormat) {
263*61c4878aSAndroid Build Coastguard Worker sectors_.Reset();
264*61c4878aSAndroid Build Coastguard Worker size_t address = 0;
265*61c4878aSAndroid Build Coastguard Worker auto entry = entries_.AddNew(kDescriptor, address);
266*61c4878aSAndroid Build Coastguard Worker
267*61c4878aSAndroid Build Coastguard Worker address += kSize1;
268*61c4878aSAndroid Build Coastguard Worker entry.AddNewAddress(kSize1);
269*61c4878aSAndroid Build Coastguard Worker
270*61c4878aSAndroid Build Coastguard Worker address += kSize1;
271*61c4878aSAndroid Build Coastguard Worker entries_.AddNew({.key_hash = Hash(kCollision1),
272*61c4878aSAndroid Build Coastguard Worker .transaction_id = 125,
273*61c4878aSAndroid Build Coastguard Worker .state = EntryState::kDeleted},
274*61c4878aSAndroid Build Coastguard Worker address);
275*61c4878aSAndroid Build Coastguard Worker
276*61c4878aSAndroid Build Coastguard Worker address += kSize2;
277*61c4878aSAndroid Build Coastguard Worker entries_.AddNew({.key_hash = Hash("delorted"),
278*61c4878aSAndroid Build Coastguard Worker .transaction_id = 256,
279*61c4878aSAndroid Build Coastguard Worker .state = EntryState::kDeleted},
280*61c4878aSAndroid Build Coastguard Worker address);
281*61c4878aSAndroid Build Coastguard Worker }
282*61c4878aSAndroid Build Coastguard Worker
CheckForCorruptSectors(SectorDescriptor * sector1=nullptr,SectorDescriptor * sector2=nullptr)283*61c4878aSAndroid Build Coastguard Worker void CheckForCorruptSectors(SectorDescriptor* sector1 = nullptr,
284*61c4878aSAndroid Build Coastguard Worker SectorDescriptor* sector2 = nullptr) {
285*61c4878aSAndroid Build Coastguard Worker for (const auto& sector : sectors_) {
286*61c4878aSAndroid Build Coastguard Worker bool expect_corrupt =
287*61c4878aSAndroid Build Coastguard Worker ((sector1 && §or == sector1) || (sector2 && §or == sector2));
288*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(expect_corrupt, sector.corrupt());
289*61c4878aSAndroid Build Coastguard Worker }
290*61c4878aSAndroid Build Coastguard Worker }
291*61c4878aSAndroid Build Coastguard Worker
292*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kTotalSectors = 128;
293*61c4878aSAndroid Build Coastguard Worker FakeFlashMemoryBuffer<kSectorSize, kTotalSectors> flash_;
294*61c4878aSAndroid Build Coastguard Worker FlashPartition partition_;
295*61c4878aSAndroid Build Coastguard Worker
296*61c4878aSAndroid Build Coastguard Worker Vector<SectorDescriptor, kTotalSectors> sector_descriptors_;
297*61c4878aSAndroid Build Coastguard Worker Sectors sectors_;
298*61c4878aSAndroid Build Coastguard Worker
299*61c4878aSAndroid Build Coastguard Worker EntryFormats format_;
300*61c4878aSAndroid Build Coastguard Worker };
301*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,EntryCounts)302*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, EntryCounts) {
303*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(3u, entries_.total_entries());
304*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, entries_.present_entries());
305*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kMaxEntries, entries_.max_entries());
306*61c4878aSAndroid Build Coastguard Worker }
307*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Reset_ClearsEntryCounts)308*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Reset_ClearsEntryCounts) {
309*61c4878aSAndroid Build Coastguard Worker entries_.Reset();
310*61c4878aSAndroid Build Coastguard Worker
311*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, entries_.total_entries());
312*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, entries_.present_entries());
313*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kMaxEntries, entries_.max_entries());
314*61c4878aSAndroid Build Coastguard Worker }
315*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_PresentEntry)316*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_PresentEntry) {
317*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
318*61c4878aSAndroid Build Coastguard Worker
319*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
320*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, kTheKey, &metadata);
321*61c4878aSAndroid Build Coastguard Worker
322*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), result.status());
323*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, result.size());
324*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Hash(kTheKey), metadata.hash());
325*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(EntryState::kValid, metadata.state());
326*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors();
327*61c4878aSAndroid Build Coastguard Worker }
328*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_PresentEntryWithSingleReadError)329*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_PresentEntryWithSingleReadError) {
330*61c4878aSAndroid Build Coastguard Worker // Inject 2 read errors so that the initial key read and the follow-up full
331*61c4878aSAndroid Build Coastguard Worker // read of the first entry fail.
332*61c4878aSAndroid Build Coastguard Worker flash_.InjectReadError(FlashError::Unconditional(Status::Internal(), 2));
333*61c4878aSAndroid Build Coastguard Worker
334*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
335*61c4878aSAndroid Build Coastguard Worker
336*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
337*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, kTheKey, &metadata);
338*61c4878aSAndroid Build Coastguard Worker
339*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), result.status());
340*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, result.size());
341*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Hash(kTheKey), metadata.hash());
342*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(EntryState::kValid, metadata.state());
343*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors(§ors_.FromAddress(0));
344*61c4878aSAndroid Build Coastguard Worker }
345*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_PresentEntryWithMultiReadError)346*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_PresentEntryWithMultiReadError) {
347*61c4878aSAndroid Build Coastguard Worker flash_.InjectReadError(FlashError::Unconditional(Status::Internal(), 4));
348*61c4878aSAndroid Build Coastguard Worker
349*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
350*61c4878aSAndroid Build Coastguard Worker
351*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
352*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, kTheKey, &metadata);
353*61c4878aSAndroid Build Coastguard Worker
354*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(Status::DataLoss(), result.status());
355*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(1u, result.size());
356*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors(§ors_.FromAddress(0),
357*61c4878aSAndroid Build Coastguard Worker §ors_.FromAddress(kSize1));
358*61c4878aSAndroid Build Coastguard Worker }
359*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_DeletedEntry)360*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_DeletedEntry) {
361*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
362*61c4878aSAndroid Build Coastguard Worker
363*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
364*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, "delorted", &metadata);
365*61c4878aSAndroid Build Coastguard Worker
366*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), result.status());
367*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, result.size());
368*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Hash("delorted"), metadata.hash());
369*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(EntryState::kDeleted, metadata.state());
370*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors();
371*61c4878aSAndroid Build Coastguard Worker }
372*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_MissingEntry)373*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_MissingEntry) {
374*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
375*61c4878aSAndroid Build Coastguard Worker
376*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
377*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, "3.141", &metadata);
378*61c4878aSAndroid Build Coastguard Worker
379*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(Status::NotFound(), result.status());
380*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, result.size());
381*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors();
382*61c4878aSAndroid Build Coastguard Worker }
383*61c4878aSAndroid Build Coastguard Worker
TEST_F(InitializedEntryCache,Find_Collision)384*61c4878aSAndroid Build Coastguard Worker TEST_F(InitializedEntryCache, Find_Collision) {
385*61c4878aSAndroid Build Coastguard Worker EntryMetadata metadata;
386*61c4878aSAndroid Build Coastguard Worker
387*61c4878aSAndroid Build Coastguard Worker StatusWithSize result =
388*61c4878aSAndroid Build Coastguard Worker entries_.Find(partition_, sectors_, format_, kCollision2, &metadata);
389*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Status::AlreadyExists(), result.status());
390*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, result.size());
391*61c4878aSAndroid Build Coastguard Worker CheckForCorruptSectors();
392*61c4878aSAndroid Build Coastguard Worker }
393*61c4878aSAndroid Build Coastguard Worker
394*61c4878aSAndroid Build Coastguard Worker } // namespace
395*61c4878aSAndroid Build Coastguard Worker } // namespace pw::kvs::internal
396