xref: /aosp_15_r20/external/pigweed/pw_kvs/entry_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.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <string_view>
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/alignment.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/checksum.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/crc16_checksum.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/fake_flash_memory.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/flash_memory.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_kvs/format.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
28*61c4878aSAndroid Build Coastguard Worker 
29*61c4878aSAndroid Build Coastguard Worker namespace pw::kvs::internal {
30*61c4878aSAndroid Build Coastguard Worker namespace {
31*61c4878aSAndroid Build Coastguard Worker 
32*61c4878aSAndroid Build Coastguard Worker using std::byte;
33*61c4878aSAndroid Build Coastguard Worker using std::string_view;
34*61c4878aSAndroid Build Coastguard Worker 
35*61c4878aSAndroid Build Coastguard Worker // For magic value always use a random 32 bit integer rather than a human
36*61c4878aSAndroid Build Coastguard Worker // readable 4 bytes. See pw_kvs/format.h for more information.
37*61c4878aSAndroid Build Coastguard Worker constexpr EntryFormat kFormat{0x961c2ff9, nullptr};
38*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,Size_RoundsUpToAlignment)39*61c4878aSAndroid Build Coastguard Worker TEST(Entry, Size_RoundsUpToAlignment) {
40*61c4878aSAndroid Build Coastguard Worker   // Use FakeFlashMemory, rather than FakeFlashMemoryBuffer, so the class gets
41*61c4878aSAndroid Build Coastguard Worker   // tested/used directly.
42*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64 * 2> buffer;
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker   // Flash alignment needs to be 1 due to how the partition is used in this
45*61c4878aSAndroid Build Coastguard Worker   // test.
46*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemory flash(buffer, 64, 2, 1);
47*61c4878aSAndroid Build Coastguard Worker 
48*61c4878aSAndroid Build Coastguard Worker   for (size_t alignment_bytes = 1; alignment_bytes <= 4096; ++alignment_bytes) {
49*61c4878aSAndroid Build Coastguard Worker     FlashPartition partition(&flash, 0, flash.sector_count(), alignment_bytes);
50*61c4878aSAndroid Build Coastguard Worker     const size_t align = AlignUp(alignment_bytes, Entry::kMinAlignmentBytes);
51*61c4878aSAndroid Build Coastguard Worker 
52*61c4878aSAndroid Build Coastguard Worker     for (size_t value : {size_t(0), align - 1, align, align + 1, 2 * align}) {
53*61c4878aSAndroid Build Coastguard Worker       Entry entry = Entry::Valid(
54*61c4878aSAndroid Build Coastguard Worker           partition, 0, kFormat, "k", {static_cast<byte*>(nullptr), value}, 0);
55*61c4878aSAndroid Build Coastguard Worker 
56*61c4878aSAndroid Build Coastguard Worker       ASSERT_EQ(AlignUp(sizeof(EntryHeader) + 1 /* key */ + value, align),
57*61c4878aSAndroid Build Coastguard Worker                 entry.size());
58*61c4878aSAndroid Build Coastguard Worker     }
59*61c4878aSAndroid Build Coastguard Worker 
60*61c4878aSAndroid Build Coastguard Worker     Entry entry = Entry::Tombstone(partition, 0, kFormat, "k", 0);
61*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(AlignUp(sizeof(EntryHeader) + 1 /* key */, align), entry.size());
62*61c4878aSAndroid Build Coastguard Worker   }
63*61c4878aSAndroid Build Coastguard Worker }
64*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,Construct_ValidEntry)65*61c4878aSAndroid Build Coastguard Worker TEST(Entry, Construct_ValidEntry) {
66*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<64, 2> flash(16);
67*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash, 0, flash.sector_count());
68*61c4878aSAndroid Build Coastguard Worker 
69*61c4878aSAndroid Build Coastguard Worker   auto entry =
70*61c4878aSAndroid Build Coastguard Worker       Entry::Valid(partition, 1, kFormat, "k", as_bytes(span("123")), 9876);
71*61c4878aSAndroid Build Coastguard Worker 
72*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(entry.deleted());
73*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.magic(), kFormat.magic);
74*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.value_size(), sizeof("123"));
75*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.transaction_id(), 9876u);
76*61c4878aSAndroid Build Coastguard Worker }
77*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,Construct_Tombstone)78*61c4878aSAndroid Build Coastguard Worker TEST(Entry, Construct_Tombstone) {
79*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<64, 2> flash(16);
80*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash, 0, flash.sector_count());
81*61c4878aSAndroid Build Coastguard Worker 
82*61c4878aSAndroid Build Coastguard Worker   auto entry = Entry::Tombstone(partition, 1, kFormat, "key", 123);
83*61c4878aSAndroid Build Coastguard Worker 
84*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(entry.deleted());
85*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.magic(), kFormat.magic);
86*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.value_size(), 0u);
87*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry.transaction_id(), 123u);
88*61c4878aSAndroid Build Coastguard Worker }
89*61c4878aSAndroid Build Coastguard Worker 
90*61c4878aSAndroid Build Coastguard Worker // For magic value always use a unique random 32 bit integer rather than a human
91*61c4878aSAndroid Build Coastguard Worker // readable 4 bytes. See pw_kvs/format.h for more information.
92*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kMagicWithChecksum = 0xad165142;
93*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kTransactionId1 = 0x96979899;
94*61c4878aSAndroid Build Coastguard Worker 
95*61c4878aSAndroid Build Coastguard Worker constexpr auto kKey1 = bytes::String("key45");
96*61c4878aSAndroid Build Coastguard Worker constexpr auto kValue1 = bytes::String("VALUE!");
97*61c4878aSAndroid Build Coastguard Worker constexpr auto kPadding1 = bytes::String("\0\0\0\0\0");
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker constexpr auto kHeader1 = bytes::Concat(kMagicWithChecksum,
100*61c4878aSAndroid Build Coastguard Worker                                         uint32_t(0x23aa),  // checksum (CRC16)
101*61c4878aSAndroid Build Coastguard Worker                                         uint8_t(1),        // alignment (32 B)
102*61c4878aSAndroid Build Coastguard Worker                                         uint8_t(kKey1.size()),     // key length
103*61c4878aSAndroid Build Coastguard Worker                                         uint16_t(kValue1.size()),  // value size
104*61c4878aSAndroid Build Coastguard Worker                                         kTransactionId1  // transaction ID
105*61c4878aSAndroid Build Coastguard Worker );
106*61c4878aSAndroid Build Coastguard Worker 
107*61c4878aSAndroid Build Coastguard Worker constexpr auto kEntryWithoutPadding1 = bytes::Concat(kHeader1, kKey1, kValue1);
108*61c4878aSAndroid Build Coastguard Worker constexpr auto kEntry1 = bytes::Concat(kEntryWithoutPadding1, kPadding1);
109*61c4878aSAndroid Build Coastguard Worker static_assert(kEntry1.size() == 32);
110*61c4878aSAndroid Build Coastguard Worker 
111*61c4878aSAndroid Build Coastguard Worker ChecksumCrc16 default_checksum;
112*61c4878aSAndroid Build Coastguard Worker constexpr EntryFormat kFormatWithChecksum{kMagicWithChecksum,
113*61c4878aSAndroid Build Coastguard Worker                                           &default_checksum};
114*61c4878aSAndroid Build Coastguard Worker constexpr internal::EntryFormats kFormats(kFormatWithChecksum);
115*61c4878aSAndroid Build Coastguard Worker 
116*61c4878aSAndroid Build Coastguard Worker class ValidEntryInFlash : public ::testing::Test {
117*61c4878aSAndroid Build Coastguard Worker  protected:
ValidEntryInFlash()118*61c4878aSAndroid Build Coastguard Worker   ValidEntryInFlash() : flash_(kEntry1), partition_(&flash_) {
119*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(OkStatus(), Entry::Read(partition_, 0, kFormats, &entry_));
120*61c4878aSAndroid Build Coastguard Worker   }
121*61c4878aSAndroid Build Coastguard Worker 
122*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash_;
123*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition_;
124*61c4878aSAndroid Build Coastguard Worker   Entry entry_;
125*61c4878aSAndroid Build Coastguard Worker };
126*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,PassesChecksumVerification)127*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, PassesChecksumVerification) {
128*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry_.VerifyChecksumInFlash());
129*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry_.VerifyChecksum("key45", kValue1));
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,HeaderContents)132*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, HeaderContents) {
133*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.magic(), kMagicWithChecksum);
134*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.key_length(), 5u);
135*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.value_size(), 6u);
136*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.transaction_id(), kTransactionId1);
137*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(entry_.deleted());
138*61c4878aSAndroid Build Coastguard Worker }
139*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadKey)140*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadKey) {
141*61c4878aSAndroid Build Coastguard Worker   Entry::KeyBuffer key = {};
142*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadKey(key);
143*61c4878aSAndroid Build Coastguard Worker 
144*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
145*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), entry_.key_length());
146*61c4878aSAndroid Build Coastguard Worker   EXPECT_STREQ(key.data(), "key45");
147*61c4878aSAndroid Build Coastguard Worker }
148*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue)149*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue) {
150*61c4878aSAndroid Build Coastguard Worker   char value[32] = {};
151*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)));
152*61c4878aSAndroid Build Coastguard Worker 
153*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
154*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), entry_.value_size());
155*61c4878aSAndroid Build Coastguard Worker   EXPECT_STREQ(value, "VALUE!");
156*61c4878aSAndroid Build Coastguard Worker }
157*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue_BufferTooSmall)158*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue_BufferTooSmall) {
159*61c4878aSAndroid Build Coastguard Worker   char value[3] = {};
160*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)));
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(Status::ResourceExhausted(), result.status());
163*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(3u, result.size());
164*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[0], 'V');
165*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[1], 'A');
166*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[2], 'L');
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue_WithOffset)169*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue_WithOffset) {
170*61c4878aSAndroid Build Coastguard Worker   char value[3] = {};
171*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)), 3);
172*61c4878aSAndroid Build Coastguard Worker 
173*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
174*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(3u, result.size());
175*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[0], 'U');
176*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[1], 'E');
177*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[2], '!');
178*61c4878aSAndroid Build Coastguard Worker }
179*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue_WithOffset_BufferTooSmall)180*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue_WithOffset_BufferTooSmall) {
181*61c4878aSAndroid Build Coastguard Worker   char value[1] = {};
182*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)), 4);
183*61c4878aSAndroid Build Coastguard Worker 
184*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(Status::ResourceExhausted(), result.status());
185*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(1u, result.size());
186*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[0], 'E');
187*61c4878aSAndroid Build Coastguard Worker }
188*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue_WithOffset_EmptyRead)189*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue_WithOffset_EmptyRead) {
190*61c4878aSAndroid Build Coastguard Worker   char value[16] = {'?'};
191*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)), 6);
192*61c4878aSAndroid Build Coastguard Worker 
193*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
194*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, result.size());
195*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value[0], '?');
196*61c4878aSAndroid Build Coastguard Worker }
197*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,ReadValue_WithOffset_PastEnd)198*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, ReadValue_WithOffset_PastEnd) {
199*61c4878aSAndroid Build Coastguard Worker   char value[16] = {};
200*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)), 7);
201*61c4878aSAndroid Build Coastguard Worker 
202*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::OutOfRange(), result.status());
203*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, result.size());
204*61c4878aSAndroid Build Coastguard Worker }
205*61c4878aSAndroid Build Coastguard Worker 
TEST(ValidEntry,Write)206*61c4878aSAndroid Build Coastguard Worker TEST(ValidEntry, Write) {
207*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash;
208*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash, 0, flash.sector_count(), 32);
209*61c4878aSAndroid Build Coastguard Worker 
210*61c4878aSAndroid Build Coastguard Worker   Entry entry = Entry::Valid(
211*61c4878aSAndroid Build Coastguard Worker       partition, 64, kFormatWithChecksum, "key45", kValue1, kTransactionId1);
212*61c4878aSAndroid Build Coastguard Worker 
213*61c4878aSAndroid Build Coastguard Worker   auto result = entry.Write("key45", kValue1);
214*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), result.status());
215*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(32u, result.size());
216*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(&flash.buffer()[64], kEntry1.data(), kEntry1.size()),
217*61c4878aSAndroid Build Coastguard Worker             0);
218*61c4878aSAndroid Build Coastguard Worker }
219*61c4878aSAndroid Build Coastguard Worker 
220*61c4878aSAndroid Build Coastguard Worker constexpr auto kHeader2 = bytes::String(
221*61c4878aSAndroid Build Coastguard Worker     "\x42\x51\x16\xad"  // magic
222*61c4878aSAndroid Build Coastguard Worker     "\xba\xb3\x00\x00"  // checksum (CRC16)
223*61c4878aSAndroid Build Coastguard Worker     "\x00"              // alignment
224*61c4878aSAndroid Build Coastguard Worker     "\x01"              // key length
225*61c4878aSAndroid Build Coastguard Worker     "\xff\xff"          // value size
226*61c4878aSAndroid Build Coastguard Worker     "\x00\x01\x02\x03"  // transaction ID
227*61c4878aSAndroid Build Coastguard Worker );
228*61c4878aSAndroid Build Coastguard Worker 
229*61c4878aSAndroid Build Coastguard Worker constexpr auto kKeyAndPadding2 =
230*61c4878aSAndroid Build Coastguard Worker     bytes::String("K\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
231*61c4878aSAndroid Build Coastguard Worker 
232*61c4878aSAndroid Build Coastguard Worker class TombstoneEntryInFlash : public ::testing::Test {
233*61c4878aSAndroid Build Coastguard Worker  protected:
TombstoneEntryInFlash()234*61c4878aSAndroid Build Coastguard Worker   TombstoneEntryInFlash()
235*61c4878aSAndroid Build Coastguard Worker       : flash_(bytes::Concat(kHeader2, kKeyAndPadding2)), partition_(&flash_) {
236*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(OkStatus(), Entry::Read(partition_, 0, kFormats, &entry_));
237*61c4878aSAndroid Build Coastguard Worker   }
238*61c4878aSAndroid Build Coastguard Worker 
239*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash_;
240*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition_;
241*61c4878aSAndroid Build Coastguard Worker   Entry entry_;
242*61c4878aSAndroid Build Coastguard Worker };
243*61c4878aSAndroid Build Coastguard Worker 
TEST_F(TombstoneEntryInFlash,PassesChecksumVerification)244*61c4878aSAndroid Build Coastguard Worker TEST_F(TombstoneEntryInFlash, PassesChecksumVerification) {
245*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry_.VerifyChecksumInFlash());
246*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry_.VerifyChecksum("K", {}));
247*61c4878aSAndroid Build Coastguard Worker }
248*61c4878aSAndroid Build Coastguard Worker 
TEST_F(TombstoneEntryInFlash,HeaderContents)249*61c4878aSAndroid Build Coastguard Worker TEST_F(TombstoneEntryInFlash, HeaderContents) {
250*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.magic(), kMagicWithChecksum);
251*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.key_length(), 1u);
252*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.value_size(), 0u);
253*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.transaction_id(), 0x03020100u);
254*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(entry_.deleted());
255*61c4878aSAndroid Build Coastguard Worker }
256*61c4878aSAndroid Build Coastguard Worker 
TEST_F(TombstoneEntryInFlash,ReadKey)257*61c4878aSAndroid Build Coastguard Worker TEST_F(TombstoneEntryInFlash, ReadKey) {
258*61c4878aSAndroid Build Coastguard Worker   Entry::KeyBuffer key = {};
259*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadKey(key);
260*61c4878aSAndroid Build Coastguard Worker 
261*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
262*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), entry_.key_length());
263*61c4878aSAndroid Build Coastguard Worker   EXPECT_STREQ(key.data(), "K");
264*61c4878aSAndroid Build Coastguard Worker }
265*61c4878aSAndroid Build Coastguard Worker 
TEST_F(TombstoneEntryInFlash,ReadValue)266*61c4878aSAndroid Build Coastguard Worker TEST_F(TombstoneEntryInFlash, ReadValue) {
267*61c4878aSAndroid Build Coastguard Worker   char value[32] = {};
268*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.ReadValue(as_writable_bytes(span(value)));
269*61c4878aSAndroid Build Coastguard Worker 
270*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
271*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, result.size());
272*61c4878aSAndroid Build Coastguard Worker }
273*61c4878aSAndroid Build Coastguard Worker 
TEST(TombstoneEntry,Write)274*61c4878aSAndroid Build Coastguard Worker TEST(TombstoneEntry, Write) {
275*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash;
276*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash);
277*61c4878aSAndroid Build Coastguard Worker   ChecksumCrc16 checksum;
278*61c4878aSAndroid Build Coastguard Worker 
279*61c4878aSAndroid Build Coastguard Worker   Entry entry =
280*61c4878aSAndroid Build Coastguard Worker       Entry::Tombstone(partition, 16, kFormatWithChecksum, "K", 0x03020100);
281*61c4878aSAndroid Build Coastguard Worker 
282*61c4878aSAndroid Build Coastguard Worker   auto result = entry.Write("K", {});
283*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), result.status());
284*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(32u, result.size());
285*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(&flash.buffer()[16],
286*61c4878aSAndroid Build Coastguard Worker                         bytes::Concat(kHeader2, kKeyAndPadding2).data(),
287*61c4878aSAndroid Build Coastguard Worker                         kEntry1.size()),
288*61c4878aSAndroid Build Coastguard Worker             0);
289*61c4878aSAndroid Build Coastguard Worker }
290*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,Checksum_NoChecksumRequiresZero)291*61c4878aSAndroid Build Coastguard Worker TEST(Entry, Checksum_NoChecksumRequiresZero) {
292*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash(kEntry1);
293*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash);
294*61c4878aSAndroid Build Coastguard Worker   Entry entry;
295*61c4878aSAndroid Build Coastguard Worker 
296*61c4878aSAndroid Build Coastguard Worker   const EntryFormat format{kMagicWithChecksum, nullptr};
297*61c4878aSAndroid Build Coastguard Worker   const internal::EntryFormats formats(format);
298*61c4878aSAndroid Build Coastguard Worker 
299*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), Entry::Read(partition, 0, formats, &entry));
300*61c4878aSAndroid Build Coastguard Worker 
301*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::DataLoss(), entry.VerifyChecksumInFlash());
302*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::DataLoss(), entry.VerifyChecksum({}, {}));
303*61c4878aSAndroid Build Coastguard Worker 
304*61c4878aSAndroid Build Coastguard Worker   std::memset(&flash.buffer()[4], 0, 4);  // set the checksum field to 0
305*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), Entry::Read(partition, 0, formats, &entry));
306*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry.VerifyChecksumInFlash());
307*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry.VerifyChecksum({}, {}));
308*61c4878aSAndroid Build Coastguard Worker }
309*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,Checksum_ChecksPadding)310*61c4878aSAndroid Build Coastguard Worker TEST(Entry, Checksum_ChecksPadding) {
311*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash(
312*61c4878aSAndroid Build Coastguard Worker       bytes::Concat(kHeader1, kKey1, kValue1, bytes::String("\0\0\0\0\1")));
313*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash);
314*61c4878aSAndroid Build Coastguard Worker   Entry entry;
315*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), Entry::Read(partition, 0, kFormats, &entry));
316*61c4878aSAndroid Build Coastguard Worker 
317*61c4878aSAndroid Build Coastguard Worker   // Last byte in padding is a 1; should fail.
318*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::DataLoss(), entry.VerifyChecksumInFlash());
319*61c4878aSAndroid Build Coastguard Worker 
320*61c4878aSAndroid Build Coastguard Worker   // The in-memory verification fills in 0s for the padding.
321*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry.VerifyChecksum("key45", kValue1));
322*61c4878aSAndroid Build Coastguard Worker 
323*61c4878aSAndroid Build Coastguard Worker   flash.buffer()[kEntry1.size() - 1] = byte{0};
324*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry.VerifyChecksumInFlash());
325*61c4878aSAndroid Build Coastguard Worker }
326*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Update_SameFormat_TransactionIdIsUpdated)327*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, Update_SameFormat_TransactionIdIsUpdated) {
328*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(),
329*61c4878aSAndroid Build Coastguard Worker             entry_.Update(kFormatWithChecksum, kTransactionId1 + 3));
330*61c4878aSAndroid Build Coastguard Worker 
331*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kFormatWithChecksum.magic, entry_.magic());
332*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, entry_.address());
333*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kTransactionId1 + 3, entry_.transaction_id());
334*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(entry_.deleted());
335*61c4878aSAndroid Build Coastguard Worker }
336*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Update_DifferentFormat_MagicAndTransactionIdAreUpdated)337*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash,
338*61c4878aSAndroid Build Coastguard Worker        Update_DifferentFormat_MagicAndTransactionIdAreUpdated) {
339*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(kFormat, kTransactionId1 + 6));
340*61c4878aSAndroid Build Coastguard Worker 
341*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kFormat.magic, entry_.magic());
342*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, entry_.address());
343*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kTransactionId1 + 6, entry_.transaction_id());
344*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(entry_.deleted());
345*61c4878aSAndroid Build Coastguard Worker }
346*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Update_ReadError_WithChecksumIsError)347*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, Update_ReadError_WithChecksumIsError) {
348*61c4878aSAndroid Build Coastguard Worker   flash_.InjectReadError(FlashError::Unconditional(Status::Aborted()));
349*61c4878aSAndroid Build Coastguard Worker 
350*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::Aborted(),
351*61c4878aSAndroid Build Coastguard Worker             entry_.Update(kFormatWithChecksum, kTransactionId1 + 1));
352*61c4878aSAndroid Build Coastguard Worker }
353*61c4878aSAndroid Build Coastguard Worker 
354*61c4878aSAndroid Build Coastguard Worker // For magic value always use a random 32 bit integer rather than a human
355*61c4878aSAndroid Build Coastguard Worker // readable 4 bytes. See pw_kvs/format.h for more information.
356*61c4878aSAndroid Build Coastguard Worker constexpr EntryFormat kNoChecksumFormat{.magic = 0x721bad24,
357*61c4878aSAndroid Build Coastguard Worker                                         .checksum = nullptr};
358*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Update_ReadError_NoChecksumIsOkay)359*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, Update_ReadError_NoChecksumIsOkay) {
360*61c4878aSAndroid Build Coastguard Worker   flash_.InjectReadError(FlashError::Unconditional(Status::Aborted()));
361*61c4878aSAndroid Build Coastguard Worker 
362*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), entry_.Update(kNoChecksumFormat, kTransactionId1 + 1));
363*61c4878aSAndroid Build Coastguard Worker }
364*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Copy)365*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, Copy) {
366*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.Copy(123);
367*61c4878aSAndroid Build Coastguard Worker 
368*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), result.status());
369*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(entry_.size(), result.size());
370*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0,
371*61c4878aSAndroid Build Coastguard Worker             std::memcmp(
372*61c4878aSAndroid Build Coastguard Worker                 &flash_.buffer().data()[123], kEntry1.data(), kEntry1.size()));
373*61c4878aSAndroid Build Coastguard Worker }
374*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,Copy_ReadError)375*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, Copy_ReadError) {
376*61c4878aSAndroid Build Coastguard Worker   flash_.InjectReadError(FlashError::Unconditional(Status::Unimplemented()));
377*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.Copy(kEntry1.size());
378*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::Unimplemented(), result.status());
379*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, result.size());
380*61c4878aSAndroid Build Coastguard Worker }
381*61c4878aSAndroid Build Coastguard Worker 
ByteSum(span<const byte> bytes,uint32_t value=0)382*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t ByteSum(span<const byte> bytes, uint32_t value = 0) {
383*61c4878aSAndroid Build Coastguard Worker   for (byte b : bytes) {
384*61c4878aSAndroid Build Coastguard Worker     value += unsigned(b);
385*61c4878aSAndroid Build Coastguard Worker   }
386*61c4878aSAndroid Build Coastguard Worker   return value;
387*61c4878aSAndroid Build Coastguard Worker }
388*61c4878aSAndroid Build Coastguard Worker 
389*61c4878aSAndroid Build Coastguard Worker // Sums the bytes, adding one to each byte so that zeroes change the checksum.
390*61c4878aSAndroid Build Coastguard Worker class ChecksumSummation final : public ChecksumAlgorithm {
391*61c4878aSAndroid Build Coastguard Worker  public:
ChecksumSummation()392*61c4878aSAndroid Build Coastguard Worker   ChecksumSummation() : ChecksumAlgorithm(as_bytes(span(&sum_, 1))), sum_(0) {}
393*61c4878aSAndroid Build Coastguard Worker 
Reset()394*61c4878aSAndroid Build Coastguard Worker   void Reset() override { sum_ = 0; }
395*61c4878aSAndroid Build Coastguard Worker 
Update(span<const byte> data)396*61c4878aSAndroid Build Coastguard Worker   void Update(span<const byte> data) override {
397*61c4878aSAndroid Build Coastguard Worker     for (byte b : data) {
398*61c4878aSAndroid Build Coastguard Worker       sum_ += unsigned(b) + 1;  // Add 1 so zero-value bytes affect checksum.
399*61c4878aSAndroid Build Coastguard Worker     }
400*61c4878aSAndroid Build Coastguard Worker   }
401*61c4878aSAndroid Build Coastguard Worker 
402*61c4878aSAndroid Build Coastguard Worker  private:
403*61c4878aSAndroid Build Coastguard Worker   uint32_t sum_;
404*61c4878aSAndroid Build Coastguard Worker } sum_checksum;
405*61c4878aSAndroid Build Coastguard Worker 
406*61c4878aSAndroid Build Coastguard Worker // For magic value always use a random 32 bit integer rather than a human
407*61c4878aSAndroid Build Coastguard Worker // readable 4 bytes. See pw_kvs/format.h for more information.
408*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kMagicWithSum = 0x6093aadb;
409*61c4878aSAndroid Build Coastguard Worker constexpr EntryFormat kFormatWithSum{kMagicWithSum, &sum_checksum};
410*61c4878aSAndroid Build Coastguard Worker constexpr internal::EntryFormats kFormatsWithSum(kFormatWithSum);
411*61c4878aSAndroid Build Coastguard Worker 
412*61c4878aSAndroid Build Coastguard Worker template <size_t kAlignment>
MakeNewFormatWithSumEntry()413*61c4878aSAndroid Build Coastguard Worker constexpr auto MakeNewFormatWithSumEntry() {
414*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t alignment_units = (kAlignment + 15) / 16 - 1;
415*61c4878aSAndroid Build Coastguard Worker   constexpr size_t size = AlignUp(kEntryWithoutPadding1.size(), kAlignment);
416*61c4878aSAndroid Build Coastguard Worker 
417*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t checksum =
418*61c4878aSAndroid Build Coastguard Worker       ByteSum(bytes::Concat(kFormatWithSum.magic)) + 0 /* checksum */ +
419*61c4878aSAndroid Build Coastguard Worker       alignment_units + kKey1.size() + kValue1.size() +
420*61c4878aSAndroid Build Coastguard Worker       ByteSum(bytes::Concat(kTransactionId1 + 1)) + ByteSum(kKey1) +
421*61c4878aSAndroid Build Coastguard Worker       ByteSum(kValue1) + size /* +1 for each byte in the checksum */;
422*61c4878aSAndroid Build Coastguard Worker 
423*61c4878aSAndroid Build Coastguard Worker   constexpr auto kNewHeader1 =
424*61c4878aSAndroid Build Coastguard Worker       bytes::Concat(kFormatWithSum.magic,      // magic
425*61c4878aSAndroid Build Coastguard Worker                     checksum,                  // checksum (byte sum)
426*61c4878aSAndroid Build Coastguard Worker                     alignment_units,           // alignment (in 16 B units)
427*61c4878aSAndroid Build Coastguard Worker                     uint8_t(kKey1.size()),     // key length
428*61c4878aSAndroid Build Coastguard Worker                     uint16_t(kValue1.size()),  // value size
429*61c4878aSAndroid Build Coastguard Worker                     kTransactionId1 + 1);      // transaction ID
430*61c4878aSAndroid Build Coastguard Worker   constexpr size_t padding = Padding(kEntryWithoutPadding1.size(), kAlignment);
431*61c4878aSAndroid Build Coastguard Worker   return bytes::Concat(
432*61c4878aSAndroid Build Coastguard Worker       kNewHeader1, kKey1, kValue1, bytes::Initialized<padding>(0));
433*61c4878aSAndroid Build Coastguard Worker }
434*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,UpdateAndCopy_DifferentFormatSmallerAlignment)435*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, UpdateAndCopy_DifferentFormatSmallerAlignment) {
436*61c4878aSAndroid Build Coastguard Worker   // Uses 16-bit alignment, smaller than the original entry's alignment.
437*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(kFormatWithSum, kTransactionId1 + 1));
438*61c4878aSAndroid Build Coastguard Worker 
439*61c4878aSAndroid Build Coastguard Worker   StatusWithSize result = entry_.Copy(kEntry1.size());
440*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
441*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kEntry1.size(), result.size());
442*61c4878aSAndroid Build Coastguard Worker 
443*61c4878aSAndroid Build Coastguard Worker   constexpr auto new_data = MakeNewFormatWithSumEntry<16>();
444*61c4878aSAndroid Build Coastguard Worker   static_assert(new_data.size() == 32);
445*61c4878aSAndroid Build Coastguard Worker 
446*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
447*61c4878aSAndroid Build Coastguard Worker       0,
448*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
449*61c4878aSAndroid Build Coastguard Worker           &flash_.buffer()[kEntry1.size()], new_data.data(), new_data.size()));
450*61c4878aSAndroid Build Coastguard Worker   Entry new_entry;
451*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(),
452*61c4878aSAndroid Build Coastguard Worker             Entry::Read(partition_, 32, kFormatsWithSum, &new_entry));
453*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), new_entry.VerifyChecksumInFlash());
454*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kFormatWithSum.magic, new_entry.magic());
455*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kTransactionId1 + 1, new_entry.transaction_id());
456*61c4878aSAndroid Build Coastguard Worker }
457*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,UpdateAndCopy_DifferentFormatSameAlignment)458*61c4878aSAndroid Build Coastguard Worker TEST(Entry, UpdateAndCopy_DifferentFormatSameAlignment) {
459*61c4878aSAndroid Build Coastguard Worker   // Use 32-bit alignment, the same as the original entry's alignment.
460*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash(kEntry1);
461*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash, 0, 4, 32);
462*61c4878aSAndroid Build Coastguard Worker   Entry entry;
463*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), Entry::Read(partition, 0, kFormats, &entry));
464*61c4878aSAndroid Build Coastguard Worker 
465*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry.Update(kFormatWithSum, kTransactionId1 + 1));
466*61c4878aSAndroid Build Coastguard Worker 
467*61c4878aSAndroid Build Coastguard Worker   StatusWithSize result = entry.Copy(32);
468*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
469*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(AlignUp(kEntry1.size(), 32), result.size());
470*61c4878aSAndroid Build Coastguard Worker 
471*61c4878aSAndroid Build Coastguard Worker   constexpr auto new_data = MakeNewFormatWithSumEntry<32>();
472*61c4878aSAndroid Build Coastguard Worker   static_assert(new_data.size() == 32);
473*61c4878aSAndroid Build Coastguard Worker 
474*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0,
475*61c4878aSAndroid Build Coastguard Worker             std::memcmp(&flash.buffer()[32], new_data.data(), new_data.size()));
476*61c4878aSAndroid Build Coastguard Worker 
477*61c4878aSAndroid Build Coastguard Worker   Entry new_entry;
478*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(),
479*61c4878aSAndroid Build Coastguard Worker             Entry::Read(partition, 32, kFormatsWithSum, &new_entry));
480*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), new_entry.VerifyChecksumInFlash());
481*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kTransactionId1 + 1, new_entry.transaction_id());
482*61c4878aSAndroid Build Coastguard Worker }
483*61c4878aSAndroid Build Coastguard Worker 
TEST(Entry,UpdateAndCopy_DifferentFormatLargerAlignment)484*61c4878aSAndroid Build Coastguard Worker TEST(Entry, UpdateAndCopy_DifferentFormatLargerAlignment) {
485*61c4878aSAndroid Build Coastguard Worker   // Use 64-bit alignment, larger than the original entry's alignment.
486*61c4878aSAndroid Build Coastguard Worker   FakeFlashMemoryBuffer<1024, 4> flash(kEntry1);
487*61c4878aSAndroid Build Coastguard Worker   FlashPartition partition(&flash, 0, 4, 64);
488*61c4878aSAndroid Build Coastguard Worker   Entry entry;
489*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), Entry::Read(partition, 0, kFormats, &entry));
490*61c4878aSAndroid Build Coastguard Worker 
491*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry.Update(kFormatWithSum, kTransactionId1 + 1));
492*61c4878aSAndroid Build Coastguard Worker 
493*61c4878aSAndroid Build Coastguard Worker   StatusWithSize result = entry.Copy(64);
494*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
495*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(AlignUp(kEntry1.size(), 64), result.size());
496*61c4878aSAndroid Build Coastguard Worker 
497*61c4878aSAndroid Build Coastguard Worker   constexpr auto new_data = MakeNewFormatWithSumEntry<64>();
498*61c4878aSAndroid Build Coastguard Worker   static_assert(new_data.size() == 64);
499*61c4878aSAndroid Build Coastguard Worker 
500*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0,
501*61c4878aSAndroid Build Coastguard Worker             std::memcmp(&flash.buffer()[64], new_data.data(), new_data.size()));
502*61c4878aSAndroid Build Coastguard Worker 
503*61c4878aSAndroid Build Coastguard Worker   Entry new_entry;
504*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(),
505*61c4878aSAndroid Build Coastguard Worker             Entry::Read(partition, 64, kFormatsWithSum, &new_entry));
506*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), new_entry.VerifyChecksumInFlash());
507*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kTransactionId1 + 1, new_entry.transaction_id());
508*61c4878aSAndroid Build Coastguard Worker }
509*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,UpdateAndCopy_NoChecksum_UpdatesToNewFormat)510*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, UpdateAndCopy_NoChecksum_UpdatesToNewFormat) {
511*61c4878aSAndroid Build Coastguard Worker   // For magic value always use a random 32 bit integer rather than a human
512*61c4878aSAndroid Build Coastguard Worker   // readable 4 bytes. See pw_kvs/format.h for more information.
513*61c4878aSAndroid Build Coastguard Worker   constexpr EntryFormat no_checksum{.magic = 0x43fae18f, .checksum = nullptr};
514*61c4878aSAndroid Build Coastguard Worker 
515*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(no_checksum, kTransactionId1 + 1));
516*61c4878aSAndroid Build Coastguard Worker 
517*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.Copy(kEntry1.size());
518*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), result.status());
519*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kEntry1.size(), result.size());
520*61c4878aSAndroid Build Coastguard Worker 
521*61c4878aSAndroid Build Coastguard Worker   constexpr auto kNewHeader1 =
522*61c4878aSAndroid Build Coastguard Worker       bytes::Concat(no_checksum.magic,  // magic
523*61c4878aSAndroid Build Coastguard Worker                     uint32_t(0),        // checksum (none)
524*61c4878aSAndroid Build Coastguard Worker                     uint8_t(0),         // alignment (changed to 16 B from 32)
525*61c4878aSAndroid Build Coastguard Worker                     uint8_t(kKey1.size()),     // key length
526*61c4878aSAndroid Build Coastguard Worker                     uint16_t(kValue1.size()),  // value size
527*61c4878aSAndroid Build Coastguard Worker                     kTransactionId1 + 1);      // transaction ID
528*61c4878aSAndroid Build Coastguard Worker   constexpr auto kNewEntry1 =
529*61c4878aSAndroid Build Coastguard Worker       bytes::Concat(kNewHeader1, kKey1, kValue1, kPadding1);
530*61c4878aSAndroid Build Coastguard Worker 
531*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0,
532*61c4878aSAndroid Build Coastguard Worker             std::memcmp(&flash_.buffer()[kEntry1.size()],
533*61c4878aSAndroid Build Coastguard Worker                         kNewEntry1.data(),
534*61c4878aSAndroid Build Coastguard Worker                         kNewEntry1.size()));
535*61c4878aSAndroid Build Coastguard Worker }
536*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,UpdateAndCopyMultple_DifferentFormat)537*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, UpdateAndCopyMultple_DifferentFormat) {
538*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(kFormatWithSum, kTransactionId1 + 6));
539*61c4878aSAndroid Build Coastguard Worker 
540*61c4878aSAndroid Build Coastguard Worker   FlashPartition::Address new_address = entry_.size();
541*61c4878aSAndroid Build Coastguard Worker 
542*61c4878aSAndroid Build Coastguard Worker   for (int i = 0; i < 10; i++) {
543*61c4878aSAndroid Build Coastguard Worker     StatusWithSize copy_result = entry_.Copy(new_address + (i * entry_.size()));
544*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(OkStatus(), copy_result.status());
545*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(kEntry1.size(), copy_result.size());
546*61c4878aSAndroid Build Coastguard Worker   }
547*61c4878aSAndroid Build Coastguard Worker 
548*61c4878aSAndroid Build Coastguard Worker   for (int j = 0; j < 10; j++) {
549*61c4878aSAndroid Build Coastguard Worker     Entry entry;
550*61c4878aSAndroid Build Coastguard Worker     FlashPartition::Address read_address = (new_address + (j * entry_.size()));
551*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(OkStatus(),
552*61c4878aSAndroid Build Coastguard Worker               Entry::Read(partition_, read_address, kFormatsWithSum, &entry));
553*61c4878aSAndroid Build Coastguard Worker 
554*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(OkStatus(), entry.VerifyChecksumInFlash());
555*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(kFormatWithSum.magic, entry.magic());
556*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(read_address, entry.address());
557*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(kTransactionId1 + 6, entry.transaction_id());
558*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(entry.deleted());
559*61c4878aSAndroid Build Coastguard Worker   }
560*61c4878aSAndroid Build Coastguard Worker }
561*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,DifferentFormat_UpdatedCopy_FailsWithWrongMagic)562*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, DifferentFormat_UpdatedCopy_FailsWithWrongMagic) {
563*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(kFormatWithSum, kTransactionId1 + 6));
564*61c4878aSAndroid Build Coastguard Worker 
565*61c4878aSAndroid Build Coastguard Worker   FlashPartition::Address new_address = entry_.size();
566*61c4878aSAndroid Build Coastguard Worker 
567*61c4878aSAndroid Build Coastguard Worker   StatusWithSize copy_result = entry_.Copy(new_address);
568*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), copy_result.status());
569*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(kEntry1.size(), copy_result.size());
570*61c4878aSAndroid Build Coastguard Worker 
571*61c4878aSAndroid Build Coastguard Worker   Entry entry;
572*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(Status::DataLoss(),
573*61c4878aSAndroid Build Coastguard Worker             Entry::Read(partition_, new_address, kFormats, &entry));
574*61c4878aSAndroid Build Coastguard Worker }
575*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ValidEntryInFlash,UpdateAndCopy_WriteError)576*61c4878aSAndroid Build Coastguard Worker TEST_F(ValidEntryInFlash, UpdateAndCopy_WriteError) {
577*61c4878aSAndroid Build Coastguard Worker   flash_.InjectWriteError(FlashError::Unconditional(Status::Cancelled()));
578*61c4878aSAndroid Build Coastguard Worker 
579*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), entry_.Update(kNoChecksumFormat, kTransactionId1 + 1));
580*61c4878aSAndroid Build Coastguard Worker 
581*61c4878aSAndroid Build Coastguard Worker   auto result = entry_.Copy(kEntry1.size());
582*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::Cancelled(), result.status());
583*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kEntry1.size(), result.size());
584*61c4878aSAndroid Build Coastguard Worker }
585*61c4878aSAndroid Build Coastguard Worker 
586*61c4878aSAndroid Build Coastguard Worker }  // namespace
587*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::kvs::internal
588