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