1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/safe_browsing/core/db/v4_store.h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/run_loop.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "base/time/time.h"
14 #include "components/safe_browsing/core/common/test_task_environment.h"
15 #include "components/safe_browsing/core/db/v4_store.pb.h"
16 #include "crypto/sha2.h"
17 #include "testing/platform_test.h"
18
19 namespace safe_browsing {
20
21 using ::google::protobuf::RepeatedField;
22 using ::google::protobuf::RepeatedPtrField;
23 using ::google::protobuf::int32;
24
25 class V4StoreTest : public PlatformTest {
26 public:
V4StoreTest()27 V4StoreTest() : task_runner_(new base::TestSimpleTaskRunner) {}
28
SetUp()29 void SetUp() override {
30 PlatformTest::SetUp();
31
32 task_environment_ = CreateTestTaskEnvironment();
33 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
34 store_path_ = temp_dir_.GetPath().AppendASCII("V4StoreTest.store");
35 DVLOG(1) << "store_path_: " << store_path_.value();
36 }
37
TearDown()38 void TearDown() override {
39 base::DeleteFile(store_path_, false);
40 PlatformTest::TearDown();
41 }
42
WriteFileFormatProtoToFile(uint32_t magic,uint32_t version=0,ListUpdateResponse * response=nullptr)43 void WriteFileFormatProtoToFile(uint32_t magic,
44 uint32_t version = 0,
45 ListUpdateResponse* response = nullptr) {
46 V4StoreFileFormat file_format;
47 file_format.set_magic_number(magic);
48 file_format.set_version_number(version);
49 if (response != nullptr) {
50 ListUpdateResponse* list_update_response =
51 file_format.mutable_list_update_response();
52 *list_update_response = *response;
53 }
54
55 std::string file_format_string;
56 file_format.SerializeToString(&file_format_string);
57 base::WriteFile(store_path_, file_format_string.data(),
58 file_format_string.size());
59 }
60
UpdatedStoreReady(bool * called_back,bool expect_store,std::unique_ptr<V4Store> store)61 void UpdatedStoreReady(bool* called_back,
62 bool expect_store,
63 std::unique_ptr<V4Store> store) {
64 *called_back = true;
65 if (expect_store) {
66 ASSERT_TRUE(store);
67 EXPECT_EQ(2u, store->hash_prefix_map_.size());
68 EXPECT_EQ("22222", store->hash_prefix_map_[5]);
69 EXPECT_EQ("abcd", store->hash_prefix_map_[4]);
70 } else {
71 ASSERT_FALSE(store);
72 }
73
74 updated_store_ = std::move(store);
75 }
76
77 base::ScopedTempDir temp_dir_;
78 base::FilePath store_path_;
79 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
80 std::unique_ptr<base::test::TaskEnvironment> task_environment_;
81 std::unique_ptr<V4Store> updated_store_;
82 };
83
TEST_F(V4StoreTest,TestReadFromEmptyFile)84 TEST_F(V4StoreTest, TestReadFromEmptyFile) {
85 base::CloseFile(base::OpenFile(store_path_, "wb+"));
86
87 V4Store store(task_runner_, store_path_);
88 EXPECT_EQ(FILE_EMPTY_FAILURE, store.ReadFromDisk());
89 EXPECT_FALSE(store.HasValidData());
90 }
91
TEST_F(V4StoreTest,TestReadFromAbsentFile)92 TEST_F(V4StoreTest, TestReadFromAbsentFile) {
93 EXPECT_EQ(FILE_UNREADABLE_FAILURE,
94 V4Store(task_runner_, store_path_).ReadFromDisk());
95 }
96
TEST_F(V4StoreTest,TestReadFromInvalidContentsFile)97 TEST_F(V4StoreTest, TestReadFromInvalidContentsFile) {
98 const char kInvalidContents[] = "Chromium";
99 base::WriteFile(store_path_, kInvalidContents, strlen(kInvalidContents));
100 EXPECT_EQ(PROTO_PARSING_FAILURE,
101 V4Store(task_runner_, store_path_).ReadFromDisk());
102 }
103
TEST_F(V4StoreTest,TestReadFromFileWithUnknownProto)104 TEST_F(V4StoreTest, TestReadFromFileWithUnknownProto) {
105 Checksum checksum;
106 checksum.set_sha256("checksum");
107 std::string checksum_string;
108 checksum.SerializeToString(&checksum_string);
109 base::WriteFile(store_path_, checksum_string.data(), checksum_string.size());
110
111 // Even though we wrote a completely different proto to file, the proto
112 // parsing method does not fail. This shows the importance of a magic number.
113 EXPECT_EQ(UNEXPECTED_MAGIC_NUMBER_FAILURE,
114 V4Store(task_runner_, store_path_).ReadFromDisk());
115 }
116
TEST_F(V4StoreTest,TestReadFromUnexpectedMagicFile)117 TEST_F(V4StoreTest, TestReadFromUnexpectedMagicFile) {
118 WriteFileFormatProtoToFile(111);
119 EXPECT_EQ(UNEXPECTED_MAGIC_NUMBER_FAILURE,
120 V4Store(task_runner_, store_path_).ReadFromDisk());
121 }
122
TEST_F(V4StoreTest,TestReadFromLowVersionFile)123 TEST_F(V4StoreTest, TestReadFromLowVersionFile) {
124 WriteFileFormatProtoToFile(0x600D71FE, 2);
125 EXPECT_EQ(FILE_VERSION_INCOMPATIBLE_FAILURE,
126 V4Store(task_runner_, store_path_).ReadFromDisk());
127 }
128
TEST_F(V4StoreTest,TestReadFromNoHashPrefixInfoFile)129 TEST_F(V4StoreTest, TestReadFromNoHashPrefixInfoFile) {
130 WriteFileFormatProtoToFile(0x600D71FE, 9);
131 EXPECT_EQ(HASH_PREFIX_INFO_MISSING_FAILURE,
132 V4Store(task_runner_, store_path_).ReadFromDisk());
133 }
134
TEST_F(V4StoreTest,TestReadFromNoHashPrefixesFile)135 TEST_F(V4StoreTest, TestReadFromNoHashPrefixesFile) {
136 ListUpdateResponse list_update_response;
137 list_update_response.set_platform_type(LINUX_PLATFORM);
138 list_update_response.set_response_type(ListUpdateResponse::FULL_UPDATE);
139 WriteFileFormatProtoToFile(0x600D71FE, 9, &list_update_response);
140 V4Store store(task_runner_, store_path_);
141 EXPECT_EQ(READ_SUCCESS, store.ReadFromDisk());
142 EXPECT_TRUE(store.hash_prefix_map_.empty());
143 EXPECT_EQ(14, store.file_size_);
144 EXPECT_FALSE(store.HasValidData());
145 }
146
TEST_F(V4StoreTest,TestAddUnlumpedHashesWithInvalidAddition)147 TEST_F(V4StoreTest, TestAddUnlumpedHashesWithInvalidAddition) {
148 HashPrefixMap prefix_map;
149 EXPECT_EQ(ADDITIONS_SIZE_UNEXPECTED_FAILURE,
150 V4Store::AddUnlumpedHashes(5, "a", &prefix_map));
151 EXPECT_TRUE(prefix_map.empty());
152 }
153
TEST_F(V4StoreTest,TestAddUnlumpedHashesWithEmptyString)154 TEST_F(V4StoreTest, TestAddUnlumpedHashesWithEmptyString) {
155 HashPrefixMap prefix_map;
156 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
157 V4Store::AddUnlumpedHashes(5, "", &prefix_map));
158 EXPECT_TRUE(prefix_map[5].empty());
159 }
160
TEST_F(V4StoreTest,TestAddUnlumpedHashes)161 TEST_F(V4StoreTest, TestAddUnlumpedHashes) {
162 HashPrefixMap prefix_map;
163 PrefixSize prefix_size = 5;
164 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
165 V4Store::AddUnlumpedHashes(prefix_size, "abcde5432100000-----",
166 &prefix_map));
167 EXPECT_EQ(1u, prefix_map.size());
168 HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
169 EXPECT_EQ(4 * prefix_size, hash_prefixes.size());
170 EXPECT_EQ("abcde5432100000-----", hash_prefixes);
171
172 prefix_size = 4;
173 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
174 V4Store::AddUnlumpedHashes(prefix_size, "abcde5432100000-----",
175 &prefix_map));
176 EXPECT_EQ(2u, prefix_map.size());
177 hash_prefixes = prefix_map.at(prefix_size);
178 EXPECT_EQ(5 * prefix_size, hash_prefixes.size());
179 EXPECT_EQ("abcde5432100000-----", hash_prefixes);
180 }
181
TEST_F(V4StoreTest,TestGetNextSmallestUnmergedPrefixWithEmptyPrefixMap)182 TEST_F(V4StoreTest, TestGetNextSmallestUnmergedPrefixWithEmptyPrefixMap) {
183 HashPrefixMap prefix_map;
184 IteratorMap iterator_map;
185 V4Store::InitializeIteratorMap(prefix_map, &iterator_map);
186
187 HashPrefix prefix;
188 EXPECT_FALSE(V4Store::GetNextSmallestUnmergedPrefix(prefix_map, iterator_map,
189 &prefix));
190 }
191
TEST_F(V4StoreTest,TestGetNextSmallestUnmergedPrefix)192 TEST_F(V4StoreTest, TestGetNextSmallestUnmergedPrefix) {
193 HashPrefixMap prefix_map;
194 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
195 V4Store::AddUnlumpedHashes(5, "-----0000054321abcde", &prefix_map));
196 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
197 V4Store::AddUnlumpedHashes(4, "*****0000054321abcde", &prefix_map));
198 IteratorMap iterator_map;
199 V4Store::InitializeIteratorMap(prefix_map, &iterator_map);
200
201 HashPrefix prefix;
202 EXPECT_TRUE(V4Store::GetNextSmallestUnmergedPrefix(prefix_map, iterator_map,
203 &prefix));
204 EXPECT_EQ("****", prefix);
205 }
206
TEST_F(V4StoreTest,TestMergeUpdatesWithSameSizesInEachMap)207 TEST_F(V4StoreTest, TestMergeUpdatesWithSameSizesInEachMap) {
208 HashPrefixMap prefix_map_old;
209 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
210 V4Store::AddUnlumpedHashes(4, "abcdefgh", &prefix_map_old));
211 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
212 V4Store::AddUnlumpedHashes(5, "54321abcde", &prefix_map_old));
213 HashPrefixMap prefix_map_additions;
214 EXPECT_EQ(
215 APPLY_UPDATE_SUCCESS,
216 V4Store::AddUnlumpedHashes(4, "----1111bbbb", &prefix_map_additions));
217 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
218 V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
219
220 V4Store store(task_runner_, store_path_);
221 // Proof of checksum validity using python:
222 // >>> import hashlib
223 // >>> m = hashlib.sha256()
224 // >>> m.update("----11112222254321abcdabcdebbbbbcdefefgh")
225 // >>> m.digest()
226 // "\xbc\xb3\xedk\xe3x\xd1(\xa9\xedz7]"
227 // "x\x18\xbdn]\xa5\xa8R\xf7\xab\xcf\xc1\xa3\xa3\xc5Z,\xa6o"
228 std::string expected_checksum = std::string(
229 "\xBC\xB3\xEDk\xE3x\xD1(\xA9\xEDz7]x\x18\xBDn]"
230 "\xA5\xA8R\xF7\xAB\xCF\xC1\xA3\xA3\xC5Z,\xA6o",
231 crypto::kSHA256Length);
232 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
233 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
234 expected_checksum));
235
236 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
237 EXPECT_EQ(2u, prefix_map.size());
238
239 PrefixSize prefix_size = 4;
240 HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
241 EXPECT_EQ(5 * prefix_size, hash_prefixes.size());
242 EXPECT_EQ("----", hash_prefixes.substr(0 * prefix_size, prefix_size));
243 EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
244 EXPECT_EQ("abcd", hash_prefixes.substr(2 * prefix_size, prefix_size));
245 EXPECT_EQ("bbbb", hash_prefixes.substr(3 * prefix_size, prefix_size));
246 EXPECT_EQ("efgh", hash_prefixes.substr(4 * prefix_size, prefix_size));
247
248 prefix_size = 5;
249 hash_prefixes = prefix_map.at(prefix_size);
250 EXPECT_EQ(4 * prefix_size, hash_prefixes.size());
251 EXPECT_EQ("22222", hash_prefixes.substr(0 * prefix_size, prefix_size));
252 EXPECT_EQ("54321", hash_prefixes.substr(1 * prefix_size, prefix_size));
253 EXPECT_EQ("abcde", hash_prefixes.substr(2 * prefix_size, prefix_size));
254 EXPECT_EQ("bcdef", hash_prefixes.substr(3 * prefix_size, prefix_size));
255 }
256
TEST_F(V4StoreTest,TestMergeUpdatesWithDifferentSizesInEachMap)257 TEST_F(V4StoreTest, TestMergeUpdatesWithDifferentSizesInEachMap) {
258 HashPrefixMap prefix_map_old;
259 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
260 V4Store::AddUnlumpedHashes(4, "1111abcdefgh", &prefix_map_old));
261 HashPrefixMap prefix_map_additions;
262 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
263 V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
264
265 V4Store store(task_runner_, store_path_);
266 std::string expected_checksum = std::string(
267 "\xA5\x8B\xCAsD\xC7\xF9\xCE\xD2\xF4\x4="
268 "\xB2\"\x82\x1A\xC1\xB8\x1F\x10\r\v\x9A\x93\xFD\xE1\xB8"
269 "B\x1Eh\xF7\xB4",
270 crypto::kSHA256Length);
271 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
272 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
273 expected_checksum));
274
275 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
276 EXPECT_EQ(2u, prefix_map.size());
277
278 PrefixSize prefix_size = 4;
279 HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
280 EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
281 EXPECT_EQ("1111abcdefgh", hash_prefixes);
282
283 prefix_size = 5;
284 hash_prefixes = prefix_map.at(prefix_size);
285 EXPECT_EQ(2 * prefix_size, hash_prefixes.size());
286 EXPECT_EQ("22222bcdef", hash_prefixes);
287 }
288
TEST_F(V4StoreTest,TestMergeUpdatesOldMapRunsOutFirst)289 TEST_F(V4StoreTest, TestMergeUpdatesOldMapRunsOutFirst) {
290 HashPrefixMap prefix_map_old;
291 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
292 V4Store::AddUnlumpedHashes(4, "00001111", &prefix_map_old));
293 HashPrefixMap prefix_map_additions;
294 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
295 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_additions));
296
297 V4Store store(task_runner_, store_path_);
298 std::string expected_checksum = std::string(
299 "\x84\x92\xET\xED\xF7\x97"
300 "C\xCE}\xFF"
301 "E\x1\xAB-\b>\xDB\x95\b\xD8H\xD5\x1D\xF9]8x\xA4\xD4\xC2\xFA",
302 crypto::kSHA256Length);
303 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
304 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
305 expected_checksum));
306
307 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
308 EXPECT_EQ(1u, prefix_map.size());
309
310 PrefixSize prefix_size = 4;
311 HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
312 EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
313 EXPECT_EQ("0000", hash_prefixes.substr(0 * prefix_size, prefix_size));
314 EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
315 EXPECT_EQ("2222", hash_prefixes.substr(2 * prefix_size, prefix_size));
316 }
317
TEST_F(V4StoreTest,TestMergeUpdatesAdditionsMapRunsOutFirst)318 TEST_F(V4StoreTest, TestMergeUpdatesAdditionsMapRunsOutFirst) {
319 HashPrefixMap prefix_map_old;
320 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
321 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
322 HashPrefixMap prefix_map_additions;
323 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
324 V4Store::AddUnlumpedHashes(4, "00001111", &prefix_map_additions));
325
326 V4Store store(task_runner_, store_path_);
327 std::string expected_checksum = std::string(
328 "\x84\x92\xET\xED\xF7\x97"
329 "C\xCE}\xFF"
330 "E\x1\xAB-\b>\xDB\x95\b\xD8H\xD5\x1D\xF9]8x\xA4\xD4\xC2\xFA",
331 crypto::kSHA256Length);
332 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
333 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
334 expected_checksum));
335
336 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
337 EXPECT_EQ(1u, prefix_map.size());
338
339 PrefixSize prefix_size = 4;
340 HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
341 EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
342 EXPECT_EQ("0000", hash_prefixes.substr(0 * prefix_size, prefix_size));
343 EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
344 EXPECT_EQ("2222", hash_prefixes.substr(2 * prefix_size, prefix_size));
345 }
346
TEST_F(V4StoreTest,TestMergeUpdatesFailsForRepeatedHashPrefix)347 TEST_F(V4StoreTest, TestMergeUpdatesFailsForRepeatedHashPrefix) {
348 HashPrefixMap prefix_map_old;
349 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
350 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
351 HashPrefixMap prefix_map_additions;
352 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
353 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_additions));
354
355 V4Store store(task_runner_, store_path_);
356 std::string expected_checksum;
357 EXPECT_EQ(ADDITIONS_HAS_EXISTING_PREFIX_FAILURE,
358 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
359 expected_checksum));
360 }
361
TEST_F(V4StoreTest,TestMergeUpdatesFailsWhenRemovalsIndexTooLarge)362 TEST_F(V4StoreTest, TestMergeUpdatesFailsWhenRemovalsIndexTooLarge) {
363 HashPrefixMap prefix_map_old;
364 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
365 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
366 HashPrefixMap prefix_map_additions;
367 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
368 V4Store::AddUnlumpedHashes(4, "11113333", &prefix_map_additions));
369
370 // Even though the merged map could have size 3 without removals, the
371 // removals index should only count the entries in the old map.
372 V4Store store(task_runner_, store_path_);
373 RepeatedField<int32> raw_removals;
374 // old_store: ["2222"]
375 raw_removals.Add(1);
376 std::string expected_checksum;
377 EXPECT_EQ(REMOVALS_INDEX_TOO_LARGE_FAILURE,
378 store.MergeUpdate(prefix_map_old, prefix_map_additions,
379 &raw_removals, expected_checksum));
380 }
381
TEST_F(V4StoreTest,TestMergeUpdatesRemovesOnlyElement)382 TEST_F(V4StoreTest, TestMergeUpdatesRemovesOnlyElement) {
383 HashPrefixMap prefix_map_old;
384 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
385 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
386 HashPrefixMap prefix_map_additions;
387 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
388 V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
389
390 V4Store store(task_runner_, store_path_);
391 RepeatedField<int32> raw_removals;
392 // old_store: ["2222"]
393 raw_removals.Add(0); // Removes "2222"
394 std::string expected_checksum = std::string(
395 "\xE6\xB0\x1\x12\x89\x83\xF0/"
396 "\xE7\xD2\xE6\xDC\x16\xB9\x8C+\xA2\xB3\x9E\x89<,\x88"
397 "B3\xA5\xB1"
398 "D\x9E\x9E'\x14",
399 crypto::kSHA256Length);
400 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
401 store.MergeUpdate(prefix_map_old, prefix_map_additions,
402 &raw_removals, expected_checksum));
403
404 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
405 // The size is 2 since we reserve space anyway.
406 EXPECT_EQ(2u, prefix_map.size());
407 EXPECT_TRUE(prefix_map.at(4).empty());
408 EXPECT_EQ("1111133333", prefix_map.at(5));
409 }
410
TEST_F(V4StoreTest,TestMergeUpdatesRemovesFirstElement)411 TEST_F(V4StoreTest, TestMergeUpdatesRemovesFirstElement) {
412 HashPrefixMap prefix_map_old;
413 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
414 V4Store::AddUnlumpedHashes(4, "22224444", &prefix_map_old));
415 HashPrefixMap prefix_map_additions;
416 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
417 V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
418
419 V4Store store(task_runner_, store_path_);
420 RepeatedField<int32> raw_removals;
421 // old_store: ["2222", "4444"]
422 raw_removals.Add(0); // Removes "2222"
423 std::string expected_checksum = std::string(
424 "\x9D\xF3\xF2\x82\0\x1E{\xDF\xCD\xC0V\xBE\xD6<\x85"
425 "D7=\xB5v\xAD\b1\xC9\xB3"
426 "A\xAC"
427 "b\xF1lf\xA4",
428 crypto::kSHA256Length);
429 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
430 store.MergeUpdate(prefix_map_old, prefix_map_additions,
431 &raw_removals, expected_checksum));
432
433 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
434 // The size is 2 since we reserve space anyway.
435 EXPECT_EQ(2u, prefix_map.size());
436 EXPECT_EQ("4444", prefix_map.at(4));
437 EXPECT_EQ("1111133333", prefix_map.at(5));
438 }
439
TEST_F(V4StoreTest,TestMergeUpdatesRemovesMiddleElement)440 TEST_F(V4StoreTest, TestMergeUpdatesRemovesMiddleElement) {
441 HashPrefixMap prefix_map_old;
442 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
443 V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
444 HashPrefixMap prefix_map_additions;
445 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
446 V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
447
448 V4Store store(task_runner_, store_path_);
449 RepeatedField<int32> raw_removals;
450 // old_store: ["2222", "3333", 4444"]
451 raw_removals.Add(1); // Removes "3333"
452 std::string expected_checksum = std::string(
453 "\xFA-A\x15{\x17\0>\xAE"
454 "8\xACigR\xD1\x93<\xB2\xC9\xB5\x81\xC0\xFB\xBB\x2\f\xAFpN\xEA"
455 "44",
456 crypto::kSHA256Length);
457 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
458 store.MergeUpdate(prefix_map_old, prefix_map_additions,
459 &raw_removals, expected_checksum));
460
461 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
462 // The size is 2 since we reserve space anyway.
463 EXPECT_EQ(2u, prefix_map.size());
464 EXPECT_EQ("22224444", prefix_map.at(4));
465 EXPECT_EQ("1111133333", prefix_map.at(5));
466 }
467
TEST_F(V4StoreTest,TestMergeUpdatesRemovesLastElement)468 TEST_F(V4StoreTest, TestMergeUpdatesRemovesLastElement) {
469 HashPrefixMap prefix_map_old;
470 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
471 V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
472 HashPrefixMap prefix_map_additions;
473 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
474 V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
475
476 V4Store store(task_runner_, store_path_);
477 RepeatedField<int32> raw_removals;
478 // old_store: ["2222", "3333", 4444"]
479 raw_removals.Add(2); // Removes "4444"
480 std::string expected_checksum = std::string(
481 "a\xE1\xAD\x96\xFE\xA6"
482 "A\xCA~7W\xF6z\xD8\n\xCA?\x96\x8A\x17U\x5\v\r\x88]\n\xB2JX\xC4S",
483 crypto::kSHA256Length);
484 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
485 store.MergeUpdate(prefix_map_old, prefix_map_additions,
486 &raw_removals, expected_checksum));
487
488 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
489 // The size is 2 since we reserve space anyway.
490 EXPECT_EQ(2u, prefix_map.size());
491 EXPECT_EQ("22223333", prefix_map.at(4));
492 EXPECT_EQ("1111133333", prefix_map.at(5));
493 }
494
TEST_F(V4StoreTest,TestMergeUpdatesRemovesWhenOldHasDifferentSizes)495 TEST_F(V4StoreTest, TestMergeUpdatesRemovesWhenOldHasDifferentSizes) {
496 HashPrefixMap prefix_map_old;
497 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
498 V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
499 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
500 V4Store::AddUnlumpedHashes(5, "aaaaabbbbb", &prefix_map_old));
501 HashPrefixMap prefix_map_additions;
502 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
503 V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
504
505 V4Store store(task_runner_, store_path_);
506 RepeatedField<int32> raw_removals;
507 // old_store: ["2222", "3333", 4444", "aaaaa", "bbbbb"]
508 raw_removals.Add(3); // Removes "aaaaa"
509 std::string expected_checksum = std::string(
510 "\xA7OG\x9D\x83.\x9D-f\x8A\xE\x8B\r&\x19"
511 "6\xE3\xF0\xEFTi\xA7\x5\xEA\xF7"
512 "ej,\xA8\x9D\xAD\x91",
513 crypto::kSHA256Length);
514 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
515 store.MergeUpdate(prefix_map_old, prefix_map_additions,
516 &raw_removals, expected_checksum));
517
518 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
519 // The size is 2 since we reserve space anyway.
520 EXPECT_EQ(2u, prefix_map.size());
521 EXPECT_EQ("222233334444", prefix_map.at(4));
522 EXPECT_EQ("1111133333bbbbb", prefix_map.at(5));
523 }
524
TEST_F(V4StoreTest,TestMergeUpdatesRemovesMultipleAcrossDifferentSizes)525 TEST_F(V4StoreTest, TestMergeUpdatesRemovesMultipleAcrossDifferentSizes) {
526 HashPrefixMap prefix_map_old;
527 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
528 V4Store::AddUnlumpedHashes(4, "22223333aaaa", &prefix_map_old));
529 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
530 V4Store::AddUnlumpedHashes(5, "3333344444bbbbb", &prefix_map_old));
531 HashPrefixMap prefix_map_additions;
532 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
533 V4Store::AddUnlumpedHashes(5, "11111", &prefix_map_additions));
534
535 V4Store store(task_runner_, store_path_);
536 RepeatedField<int32> raw_removals;
537 // old_store: ["2222", "3333", "33333", "44444", "aaaa", "bbbbb"]
538 raw_removals.Add(1); // Removes "3333"
539 raw_removals.Add(3); // Removes "44444"
540 std::string expected_checksum = std::string(
541 "!D\xB7&L\xA7&G0\x85\xB4"
542 "E\xDD\x10\"\x9A\xCA\xF1"
543 "3^\x83w\xBBL\x19n\xAD\xBDM\x9D"
544 "b\x9F",
545 crypto::kSHA256Length);
546 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
547 store.MergeUpdate(prefix_map_old, prefix_map_additions,
548 &raw_removals, expected_checksum));
549
550 const HashPrefixMap& prefix_map = store.hash_prefix_map_;
551 // The size is 2 since we reserve space anyway.
552 EXPECT_EQ(2u, prefix_map.size());
553 EXPECT_EQ("2222aaaa", prefix_map.at(4));
554 EXPECT_EQ("1111133333bbbbb", prefix_map.at(5));
555 }
556
TEST_F(V4StoreTest,TestReadFullResponseWithValidHashPrefixMap)557 TEST_F(V4StoreTest, TestReadFullResponseWithValidHashPrefixMap) {
558 V4Store write_store(task_runner_, store_path_);
559 write_store.hash_prefix_map_[4] = "00000abc";
560 write_store.hash_prefix_map_[5] = "00000abcde";
561 write_store.state_ = "test_client_state";
562 EXPECT_FALSE(base::PathExists(write_store.store_path_));
563 EXPECT_EQ(WRITE_SUCCESS, write_store.WriteToDisk(Checksum()));
564 EXPECT_TRUE(base::PathExists(write_store.store_path_));
565
566 V4Store read_store(task_runner_, store_path_);
567 EXPECT_EQ(READ_SUCCESS, read_store.ReadFromDisk());
568 EXPECT_EQ("test_client_state", read_store.state_);
569 ASSERT_EQ(2u, read_store.hash_prefix_map_.size());
570 EXPECT_EQ("00000abc", read_store.hash_prefix_map_[4]);
571 EXPECT_EQ("00000abcde", read_store.hash_prefix_map_[5]);
572 EXPECT_EQ(71, read_store.file_size_);
573 }
574
575 // This tests fails to read the prefix map from the disk because the file on
576 // disk is invalid. The hash prefixes string is 6 bytes long, but the prefix
577 // size is 5 so the parser isn't able to split the hash prefixes list
578 // completely.
TEST_F(V4StoreTest,TestReadFullResponseWithInvalidHashPrefixMap)579 TEST_F(V4StoreTest, TestReadFullResponseWithInvalidHashPrefixMap) {
580 V4Store write_store(task_runner_, store_path_);
581 write_store.hash_prefix_map_[5] = "abcdef";
582 write_store.state_ = "test_client_state";
583 EXPECT_FALSE(base::PathExists(write_store.store_path_));
584 EXPECT_EQ(WRITE_SUCCESS, write_store.WriteToDisk(Checksum()));
585 EXPECT_TRUE(base::PathExists(write_store.store_path_));
586
587 V4Store read_store(task_runner_, store_path_);
588 EXPECT_EQ(HASH_PREFIX_MAP_GENERATION_FAILURE, read_store.ReadFromDisk());
589 EXPECT_TRUE(read_store.state_.empty());
590 EXPECT_TRUE(read_store.hash_prefix_map_.empty());
591 EXPECT_EQ(0, read_store.file_size_);
592 }
593
TEST_F(V4StoreTest,TestHashPrefixExistsAtTheBeginning)594 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginning) {
595 HashPrefixes hash_prefixes = "abcdebbbbbccccc";
596 HashPrefix hash_prefix = "abcde";
597 EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
598 }
599
TEST_F(V4StoreTest,TestHashPrefixExistsInTheMiddle)600 TEST_F(V4StoreTest, TestHashPrefixExistsInTheMiddle) {
601 HashPrefixes hash_prefixes = "abcdebbbbbccccc";
602 HashPrefix hash_prefix = "bbbbb";
603 EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
604 }
605
TEST_F(V4StoreTest,TestHashPrefixExistsAtTheEnd)606 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEnd) {
607 HashPrefixes hash_prefixes = "abcdebbbbbccccc";
608 HashPrefix hash_prefix = "ccccc";
609 EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
610 }
611
TEST_F(V4StoreTest,TestHashPrefixExistsAtTheBeginningOfEven)612 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginningOfEven) {
613 HashPrefixes hash_prefixes = "abcdebbbbb";
614 HashPrefix hash_prefix = "abcde";
615 EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
616 }
617
TEST_F(V4StoreTest,TestHashPrefixExistsAtTheEndOfEven)618 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEndOfEven) {
619 HashPrefixes hash_prefixes = "abcdebbbbb";
620 HashPrefix hash_prefix = "bbbbb";
621 EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
622 }
623
TEST_F(V4StoreTest,TestHashPrefixDoesNotExistInConcatenatedList)624 TEST_F(V4StoreTest, TestHashPrefixDoesNotExistInConcatenatedList) {
625 HashPrefixes hash_prefixes = "abcdebbbbb";
626 HashPrefix hash_prefix = "bbbbc";
627 EXPECT_FALSE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
628 }
629
TEST_F(V4StoreTest,TestFullHashExistsInMapWithSingleSize)630 TEST_F(V4StoreTest, TestFullHashExistsInMapWithSingleSize) {
631 V4Store store(task_runner_, store_path_);
632 store.hash_prefix_map_[32] =
633 "0111222233334444555566667777888811112222333344445555666677778888";
634 FullHash full_hash = "11112222333344445555666677778888";
635 EXPECT_EQ("11112222333344445555666677778888",
636 store.GetMatchingHashPrefix(full_hash));
637 }
638
TEST_F(V4StoreTest,TestFullHashExistsInMapWithDifferentSizes)639 TEST_F(V4StoreTest, TestFullHashExistsInMapWithDifferentSizes) {
640 V4Store store(task_runner_, store_path_);
641 store.hash_prefix_map_[4] = "22223333aaaa";
642 store.hash_prefix_map_[32] = "11112222333344445555666677778888";
643 FullHash full_hash = "11112222333344445555666677778888";
644 EXPECT_EQ("11112222333344445555666677778888",
645 store.GetMatchingHashPrefix(full_hash));
646 }
647
TEST_F(V4StoreTest,TestHashPrefixExistsInMapWithSingleSize)648 TEST_F(V4StoreTest, TestHashPrefixExistsInMapWithSingleSize) {
649 V4Store store(task_runner_, store_path_);
650 store.hash_prefix_map_[4] = "22223333aaaa";
651 FullHash full_hash = "22222222222222222222222222222222";
652 EXPECT_EQ("2222", store.GetMatchingHashPrefix(full_hash));
653 }
654
TEST_F(V4StoreTest,TestHashPrefixExistsInMapWithDifferentSizes)655 TEST_F(V4StoreTest, TestHashPrefixExistsInMapWithDifferentSizes) {
656 V4Store store(task_runner_, store_path_);
657 store.hash_prefix_map_[4] = "22223333aaaa";
658 store.hash_prefix_map_[5] = "11111hhhhh";
659 FullHash full_hash = "22222222222222222222222222222222";
660 EXPECT_EQ("2222", store.GetMatchingHashPrefix(full_hash));
661 }
662
TEST_F(V4StoreTest,TestHashPrefixDoesNotExistInMapWithDifferentSizes)663 TEST_F(V4StoreTest, TestHashPrefixDoesNotExistInMapWithDifferentSizes) {
664 V4Store store(task_runner_, store_path_);
665 store.hash_prefix_map_[4] = "3333aaaa";
666 store.hash_prefix_map_[5] = "11111hhhhh";
667 FullHash full_hash = "22222222222222222222222222222222";
668 EXPECT_TRUE(store.GetMatchingHashPrefix(full_hash).empty());
669 }
670
TEST_F(V4StoreTest,GetMatchingHashPrefixSize32Or21)671 TEST_F(V4StoreTest, GetMatchingHashPrefixSize32Or21) {
672 HashPrefix prefix = "0123";
673 V4Store store(task_runner_, store_path_);
674 store.hash_prefix_map_[4] = prefix;
675
676 FullHash full_hash_21 = "0123456789ABCDEF01234";
677 EXPECT_EQ(prefix, store.GetMatchingHashPrefix(full_hash_21));
678 FullHash full_hash_32 = "0123456789ABCDEF0123456789ABCDEF";
679 EXPECT_EQ(prefix, store.GetMatchingHashPrefix(full_hash_32));
680 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
681 // This hits a DCHECK so it is release mode only.
682 FullHash full_hash_22 = "0123456789ABCDEF012345";
683 EXPECT_EQ(prefix, store.GetMatchingHashPrefix(full_hash_22));
684 #endif
685 }
686
687 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
688 // This test hits a NOTREACHED so it is a release mode only test.
TEST_F(V4StoreTest,TestAdditionsWithRiceEncodingFailsWithInvalidInput)689 TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingFailsWithInvalidInput) {
690 RepeatedPtrField<ThreatEntrySet> additions;
691 ThreatEntrySet* addition = additions.Add();
692 addition->set_compression_type(RICE);
693 addition->mutable_rice_hashes()->set_num_entries(-1);
694 HashPrefixMap additions_map;
695 EXPECT_EQ(RICE_DECODING_FAILURE,
696 V4Store(task_runner_, store_path_)
697 .UpdateHashPrefixMapFromAdditions("V4Metric", additions,
698 &additions_map));
699 }
700 #endif
701
TEST_F(V4StoreTest,TestAdditionsWithRiceEncodingSucceeds)702 TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingSucceeds) {
703 RepeatedPtrField<ThreatEntrySet> additions;
704 ThreatEntrySet* addition = additions.Add();
705 addition->set_compression_type(RICE);
706 RiceDeltaEncoding* rice_hashes = addition->mutable_rice_hashes();
707 rice_hashes->set_first_value(5);
708 rice_hashes->set_num_entries(3);
709 rice_hashes->set_rice_parameter(28);
710 // The following value is hand-crafted by getting inspiration from:
711 // https://goto.google.com/testlargenumbersriceencoded
712 // The value listed at that place fails the "integer overflow" check so I
713 // modified it until the decoder parsed it successfully.
714 rice_hashes->set_encoded_data(
715 "\xbf\xa8\x3f\xfb\xf\xf\x5e\x27\xe6\xc3\x1d\xc6\x38");
716 HashPrefixMap additions_map;
717 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
718 V4Store(task_runner_, store_path_)
719 .UpdateHashPrefixMapFromAdditions("V4Metric", additions,
720 &additions_map));
721 EXPECT_EQ(1u, additions_map.size());
722 EXPECT_EQ(std::string("\x5\0\0\0\fL\x93\xADV\x7F\xF6o\xCEo1\x81", 16),
723 additions_map[4]);
724 }
725
TEST_F(V4StoreTest,TestRemovalsWithRiceEncodingSucceeds)726 TEST_F(V4StoreTest, TestRemovalsWithRiceEncodingSucceeds) {
727 HashPrefixMap prefix_map_old;
728 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
729 V4Store::AddUnlumpedHashes(4, "1111abcdefgh", &prefix_map_old));
730 HashPrefixMap prefix_map_additions;
731 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
732 V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
733
734 V4Store store(task_runner_, store_path_);
735 std::string expected_checksum = std::string(
736 "\xA5\x8B\xCAsD\xC7\xF9\xCE\xD2\xF4\x4="
737 "\xB2\"\x82\x1A\xC1\xB8\x1F\x10\r\v\x9A\x93\xFD\xE1\xB8"
738 "B\x1Eh\xF7\xB4",
739 crypto::kSHA256Length);
740 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
741 store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
742 expected_checksum));
743 EXPECT_FALSE(store.HasValidData()); // Never actually read from disk.
744
745 // At this point, the store map looks like this:
746 // 4: 1111abcdefgh
747 // 5: 22222bcdef
748 // sorted: 1111, 22222, abcd, bcdef, efgh
749 // We'll now try to delete hashes at indexes 0, 3 and 4 in the sorted list.
750
751 std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
752 lur->set_response_type(ListUpdateResponse::PARTIAL_UPDATE);
753 ThreatEntrySet* removal = lur->add_removals();
754 removal->set_compression_type(RICE);
755 RiceDeltaEncoding* rice_indices = removal->mutable_rice_indices();
756 rice_indices->set_first_value(0);
757 rice_indices->set_num_entries(2);
758 rice_indices->set_rice_parameter(2);
759 rice_indices->set_encoded_data("\x16");
760
761 bool called_back = false;
762 UpdatedStoreReadyCallback store_ready_callback =
763 base::BindOnce(&V4StoreTest::UpdatedStoreReady, base::Unretained(this),
764 &called_back, true /* expect_store */);
765 EXPECT_FALSE(base::PathExists(store.store_path_));
766 store.ApplyUpdate(std::move(lur), task_runner_,
767 std::move(store_ready_callback));
768 EXPECT_TRUE(base::PathExists(store.store_path_));
769
770 task_runner_->RunPendingTasks();
771 base::RunLoop().RunUntilIdle();
772
773 // This ensures that the callback was called.
774 EXPECT_TRUE(called_back);
775 // ApplyUpdate was successful, so we have valid data.
776 ASSERT_TRUE(updated_store_);
777 EXPECT_TRUE(updated_store_->HasValidData());
778 }
779
TEST_F(V4StoreTest,TestMergeUpdatesFailsChecksum)780 TEST_F(V4StoreTest, TestMergeUpdatesFailsChecksum) {
781 // Proof of checksum mismatch using python:
782 // >>> import hashlib
783 // >>> m = hashlib.sha256()
784 // >>> m.update("2222")
785 // >>> m.digest()
786 // "\xed\xee)\xf8\x82T;\x95f
787 // \xb2m\x0e\xe0\xe7\xe9P9\x9b\x1cB"\xf5\xde\x05\xe0d%\xb4\xc9\x95\xe9"
788
789 HashPrefixMap prefix_map_old;
790 EXPECT_EQ(APPLY_UPDATE_SUCCESS,
791 V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
792 EXPECT_EQ(CHECKSUM_MISMATCH_FAILURE,
793 V4Store(task_runner_, store_path_)
794 .MergeUpdate(prefix_map_old, HashPrefixMap(), nullptr, "aawc"));
795 }
796
TEST_F(V4StoreTest,TestChecksumErrorOnStartup)797 TEST_F(V4StoreTest, TestChecksumErrorOnStartup) {
798 // First the case of checksum not matching after reading from disk.
799 ListUpdateResponse list_update_response;
800 list_update_response.set_new_client_state("test_client_state");
801 list_update_response.set_platform_type(LINUX_PLATFORM);
802 list_update_response.set_response_type(ListUpdateResponse::FULL_UPDATE);
803 list_update_response.mutable_checksum()->set_sha256(
804 std::string(crypto::kSHA256Length, 0));
805 WriteFileFormatProtoToFile(0x600D71FE, 9, &list_update_response);
806 V4Store store(task_runner_, store_path_);
807 EXPECT_TRUE(store.expected_checksum_.empty());
808 EXPECT_EQ(READ_SUCCESS, store.ReadFromDisk());
809 EXPECT_TRUE(!store.expected_checksum_.empty());
810 EXPECT_EQ(69, store.file_size_);
811 EXPECT_EQ("test_client_state", store.state());
812
813 EXPECT_FALSE(store.VerifyChecksum());
814
815 // Now the case of checksum matching after reading from disk.
816 // Proof of checksum mismatch using python:
817 // >>> import hashlib
818 // >>> m = hashlib.sha256()
819 // >>> m.update("abcde")
820 // >>> import base64
821 // >>> encoded = base64.b64encode(m.digest())
822 // >>> encoded
823 // 'NrvlDtloQdEEQ7y2cNZVTwo0t2G+Z+ycSorSwMRMpCw='
824 std::string expected_checksum;
825 base::Base64Decode("NrvlDtloQdEEQ7y2cNZVTwo0t2G+Z+ycSorSwMRMpCw=",
826 &expected_checksum);
827 ThreatEntrySet* additions = list_update_response.add_additions();
828 additions->set_compression_type(RAW);
829 additions->mutable_raw_hashes()->set_prefix_size(5);
830 additions->mutable_raw_hashes()->set_raw_hashes("abcde");
831 list_update_response.mutable_checksum()->set_sha256(expected_checksum);
832 WriteFileFormatProtoToFile(0x600D71FE, 9, &list_update_response);
833 V4Store another_store(task_runner_, store_path_);
834 EXPECT_TRUE(another_store.expected_checksum_.empty());
835
836 EXPECT_EQ(READ_SUCCESS, another_store.ReadFromDisk());
837 EXPECT_TRUE(!another_store.expected_checksum_.empty());
838 EXPECT_EQ("test_client_state", another_store.state());
839 EXPECT_EQ(69, store.file_size_);
840
841 EXPECT_TRUE(another_store.VerifyChecksum());
842 }
843
TEST_F(V4StoreTest,WriteToDiskFails)844 TEST_F(V4StoreTest, WriteToDiskFails) {
845 // Pass the directory name as file name so that when the code tries to rename
846 // the temp store file to |store_path_| it fails.
847 EXPECT_EQ(UNABLE_TO_RENAME_FAILURE,
848 V4Store(task_runner_, temp_dir_.GetPath()).WriteToDisk(Checksum()));
849
850 // Give a location that isn't writable, even for the tmp file.
851 base::FilePath non_writable_dir =
852 temp_dir_.GetPath()
853 .Append(FILE_PATH_LITERAL("nonexistent_dir"))
854 .Append(FILE_PATH_LITERAL("some.store"));
855 EXPECT_EQ(UNEXPECTED_BYTES_WRITTEN_FAILURE,
856 V4Store(task_runner_, non_writable_dir).WriteToDisk(Checksum()));
857 }
858
TEST_F(V4StoreTest,FullUpdateFailsChecksumSynchronously)859 TEST_F(V4StoreTest, FullUpdateFailsChecksumSynchronously) {
860 V4Store store(task_runner_, store_path_);
861 bool called_back = false;
862 UpdatedStoreReadyCallback store_ready_callback =
863 base::BindOnce(&V4StoreTest::UpdatedStoreReady, base::Unretained(this),
864 &called_back, false /* expect_store */);
865 EXPECT_FALSE(base::PathExists(store.store_path_));
866 EXPECT_FALSE(store.HasValidData()); // Never actually read from disk.
867
868 // Now create a response with invalid checksum.
869 std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
870 lur->set_response_type(ListUpdateResponse::FULL_UPDATE);
871 lur->mutable_checksum()->set_sha256(std::string(crypto::kSHA256Length, 0));
872 store.ApplyUpdate(std::move(lur), task_runner_,
873 std::move(store_ready_callback));
874 // The update should fail synchronously and not create a store file.
875 EXPECT_FALSE(base::PathExists(store.store_path_));
876
877 // Run everything on the task runner to ensure there are no pending tasks.
878 task_runner_->RunPendingTasks();
879 base::RunLoop().RunUntilIdle();
880
881 // This ensures that the callback was called.
882 EXPECT_TRUE(called_back);
883 // Ensure that the file is still not created.
884 EXPECT_FALSE(base::PathExists(store.store_path_));
885 EXPECT_FALSE(updated_store_);
886 }
887
888 } // namespace safe_browsing
889