1 // Copyright (C) 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "icing/legacy/index/icing-array-storage.h"
16
17 #include <cstdint>
18 #include <string>
19
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "icing/legacy/index/icing-filesystem.h"
23 #include "icing/testing/tmp-directory.h"
24 #include "icing/util/crc32.h"
25
26 namespace icing {
27 namespace lib {
28
29 namespace {
30
31 using testing::Eq;
32
33 class IcingArrayStorageTest : public ::testing::Test {
34 protected:
SetUp()35 void SetUp() override {
36 array_files_dir_ = GetTestTempDir() + "/array_files";
37 filesystem_.CreateDirectoryRecursively(array_files_dir_.c_str());
38 array_file_ = array_files_dir_ + "/array_file";
39 }
40
TearDown()41 void TearDown() override {
42 filesystem_.DeleteDirectoryRecursively(array_files_dir_.c_str());
43 }
44
45 IcingFilesystem filesystem_;
46 std::string array_files_dir_;
47 std::string array_file_;
48 };
49
TEST_F(IcingArrayStorageTest,UpdateCrcNoCrcPtr)50 TEST_F(IcingArrayStorageTest, UpdateCrcNoCrcPtr) {
51 IcingArrayStorage storage(filesystem_);
52 IcingScopedFd sfd(filesystem_.OpenForWrite(array_file_.c_str()));
53 ASSERT_TRUE(sfd.is_valid());
54 ASSERT_TRUE(storage.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
55 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/0,
56 /*max_num_elts=*/1000, /*crc_ptr=*/nullptr,
57 /*init_crc=*/false));
58
59 // Initial Crc should be 0.
60 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
61 EXPECT_THAT(storage.UpdateCrc(), Eq(Crc32()));
62 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
63
64 uint32_t* val = storage.GetMutableMem<uint32_t>(0, 1);
65 *val = 5;
66
67 // Because there is no crc_ptr, the crc should remain 0 even though we have
68 // added content.
69 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
70 EXPECT_THAT(storage.UpdateCrc(), Eq(Crc32()));
71 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
72 }
73
TEST_F(IcingArrayStorageTest,UpdateCrc)74 TEST_F(IcingArrayStorageTest, UpdateCrc) {
75 IcingArrayStorage storage(filesystem_);
76 uint32_t crc = 0;
77 IcingScopedFd sfd(filesystem_.OpenForWrite(array_file_.c_str()));
78 ASSERT_TRUE(sfd.is_valid());
79 ASSERT_TRUE(storage.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
80 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/0,
81 /*max_num_elts=*/1000, &crc, /*init_crc=*/false));
82
83 // Initial Crc should be 0.
84 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
85 EXPECT_THAT(storage.UpdateCrc(), Eq(Crc32()));
86 EXPECT_THAT(storage.GetCrc(), Eq(Crc32()));
87
88 uint32_t* val = storage.GetMutableMem<uint32_t>(0, 1);
89 *val = 5;
90
91 EXPECT_THAT(storage.GetCrc(), Eq(Crc32(937357362)));
92 EXPECT_THAT(storage.UpdateCrc(), Eq(Crc32(937357362)));
93 EXPECT_THAT(storage.GetCrc(), Eq(Crc32(937357362)));
94 }
95
TEST_F(IcingArrayStorageTest,GetCrcDoesNotUpdateHeader)96 TEST_F(IcingArrayStorageTest, GetCrcDoesNotUpdateHeader) {
97 uint32_t crc = 0;
98 IcingScopedFd sfd(filesystem_.OpenForWrite(array_file_.c_str()));
99 ASSERT_TRUE(sfd.is_valid());
100
101 {
102 IcingArrayStorage storage_one(filesystem_);
103 ASSERT_TRUE(
104 storage_one.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
105 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/0,
106 /*max_num_elts=*/1000, &crc, /*init_crc=*/false));
107
108 // Initial Crc should be 0.
109 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32()));
110 EXPECT_THAT(storage_one.UpdateCrc(), Eq(Crc32()));
111 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32()));
112
113 uint32_t* val = storage_one.GetMutableMem<uint32_t>(0, 1);
114 *val = 5;
115
116 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32(937357362)));
117 EXPECT_THAT(crc, Eq(0));
118 }
119
120 {
121 IcingArrayStorage storage_two(filesystem_);
122 // Init should fail because the updated checksum was never written to crc.
123 ASSERT_FALSE(
124 storage_two.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
125 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/1,
126 /*max_num_elts=*/1000, &crc, /*init_crc=*/false));
127 }
128 }
129
TEST_F(IcingArrayStorageTest,UpdateCrcDoesUpdateHeader)130 TEST_F(IcingArrayStorageTest, UpdateCrcDoesUpdateHeader) {
131 uint32_t crc = 0;
132 IcingScopedFd sfd(filesystem_.OpenForWrite(array_file_.c_str()));
133 ASSERT_TRUE(sfd.is_valid());
134
135 {
136 IcingArrayStorage storage_one(filesystem_);
137 ASSERT_TRUE(
138 storage_one.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
139 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/0,
140 /*max_num_elts=*/1000, &crc, /*init_crc=*/false));
141
142 // Initial Crc should be 0.
143 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32()));
144 EXPECT_THAT(storage_one.UpdateCrc(), Eq(Crc32()));
145 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32()));
146
147 uint32_t* val = storage_one.GetMutableMem<uint32_t>(0, 1);
148 *val = 5;
149
150 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32(937357362)));
151 EXPECT_THAT(storage_one.UpdateCrc(), Eq(Crc32(937357362)));
152 EXPECT_THAT(storage_one.GetCrc(), Eq(Crc32(937357362)));
153 EXPECT_THAT(crc, Eq(937357362));
154 }
155
156 {
157 IcingArrayStorage storage_two(filesystem_);
158 // Init should fail because the updated checksum was never written to crc.
159 ASSERT_TRUE(
160 storage_two.Init(sfd.get(), /*fd_offset=*/0, /*map_shared=*/true,
161 /*elt_size=*/sizeof(uint32_t), /*num_elts=*/1,
162 /*max_num_elts=*/1000, &crc, /*init_crc=*/false));
163 EXPECT_THAT(storage_two.GetCrc().Get(), Eq(937357362));
164 }
165 }
166
167 } // namespace
168
169 } // namespace lib
170 } // namespace icing