xref: /aosp_15_r20/external/pigweed/pw_kvs/entry_cache_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 && &sector == sector1) || (sector2 && &sector == 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(&sectors_.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(&sectors_.FromAddress(0),
357*61c4878aSAndroid Build Coastguard Worker                          &sectors_.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