310f63455cda89fe16051d49533227b87b7eb660
[platform/framework/web/crosswalk.git] / src / chrome / browser / safe_browsing / safe_browsing_store_file_unittest.cc
1 // Copyright (c) 2012 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 "chrome/browser/safe_browsing/safe_browsing_store_file.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_file.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/md5.h"
12 #include "base/path_service.h"
13 #include "chrome/common/chrome_paths.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/platform_test.h"
16
17 namespace {
18
19 const int kAddChunk1 = 1;
20 const int kAddChunk2 = 3;
21 const int kAddChunk3 = 5;
22 const int kAddChunk4 = 7;
23 // Disjoint chunk numbers for subs to flush out typos.
24 const int kSubChunk1 = 2;
25 const int kSubChunk2 = 4;
26
27 const SBFullHash kHash1 = SBFullHashForString("one");
28 const SBFullHash kHash2 = SBFullHashForString("two");
29 const SBFullHash kHash3 = SBFullHashForString("three");
30 const SBFullHash kHash4 = SBFullHashForString("four");
31 const SBFullHash kHash5 = SBFullHashForString("five");
32 const SBFullHash kHash6 = SBFullHashForString("six");
33
34 const SBPrefix kMinSBPrefix = 0u;
35 const SBPrefix kMaxSBPrefix = ~kMinSBPrefix;
36
37 }  // namespace
38
39 namespace safe_browsing {
40
41 class SafeBrowsingStoreFileTest : public PlatformTest {
42  public:
43   virtual void SetUp() {
44     PlatformTest::SetUp();
45
46     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
47
48     filename_ = temp_dir_.path();
49     filename_ = filename_.AppendASCII("SafeBrowsingTestStore");
50
51     store_.reset(new SafeBrowsingStoreFile());
52     store_->Init(filename_,
53                  base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
54                             base::Unretained(this)));
55     corruption_detected_ = false;
56   }
57   virtual void TearDown() {
58     if (store_.get())
59       store_->Delete();
60     store_.reset();
61
62     PlatformTest::TearDown();
63   }
64
65   void OnCorruptionDetected() {
66     corruption_detected_ = true;
67   }
68
69   // Populate the store with some testing data.
70   void PopulateStore() {
71     ASSERT_TRUE(store_->BeginUpdate());
72
73     EXPECT_TRUE(store_->BeginChunk());
74     store_->SetAddChunk(kAddChunk1);
75     EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
76     EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
77     EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
78     EXPECT_TRUE(store_->FinishChunk());
79
80     EXPECT_TRUE(store_->BeginChunk());
81     store_->SetSubChunk(kSubChunk1);
82     EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
83     EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
84     EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash3));
85     EXPECT_TRUE(store_->FinishChunk());
86
87     EXPECT_TRUE(store_->BeginChunk());
88     store_->SetAddChunk(kAddChunk2);
89     EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
90     EXPECT_TRUE(store_->WriteAddHash(kAddChunk2, kHash4));
91     EXPECT_TRUE(store_->FinishChunk());
92
93     // Chunk numbers shouldn't leak over.
94     EXPECT_FALSE(store_->CheckAddChunk(kSubChunk1));
95     EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
96     EXPECT_FALSE(store_->CheckSubChunk(kAddChunk1));
97     EXPECT_FALSE(store_->CheckSubChunk(kAddChunk2));
98
99     safe_browsing::PrefixSetBuilder builder;
100     std::vector<SBAddFullHash> add_full_hashes_result;
101
102     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
103   }
104
105   // Manually read the shard stride info from the file.
106   uint32 ReadStride() {
107     base::ScopedFILE file(base::OpenFile(filename_, "rb"));
108     const long kOffset = 4 * sizeof(uint32);
109     EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
110     uint32 shard_stride = 0;
111     EXPECT_EQ(fread(&shard_stride, sizeof(shard_stride), 1, file.get()), 1U);
112     return shard_stride;
113   }
114
115   base::ScopedTempDir temp_dir_;
116   base::FilePath filename_;
117   scoped_ptr<SafeBrowsingStoreFile> store_;
118   bool corruption_detected_;
119 };
120
121 // Test that the empty store looks empty.
122 TEST_F(SafeBrowsingStoreFileTest, Empty) {
123   ASSERT_TRUE(store_->BeginUpdate());
124
125   std::vector<int> chunks;
126   store_->GetAddChunks(&chunks);
127   EXPECT_TRUE(chunks.empty());
128   store_->GetSubChunks(&chunks);
129   EXPECT_TRUE(chunks.empty());
130
131   // Shouldn't see anything, but anything is a big set to test.
132   EXPECT_FALSE(store_->CheckAddChunk(0));
133   EXPECT_FALSE(store_->CheckAddChunk(1));
134   EXPECT_FALSE(store_->CheckAddChunk(-1));
135
136   EXPECT_FALSE(store_->CheckSubChunk(0));
137   EXPECT_FALSE(store_->CheckSubChunk(1));
138   EXPECT_FALSE(store_->CheckSubChunk(-1));
139
140   safe_browsing::PrefixSetBuilder builder;
141   std::vector<SBAddFullHash> add_full_hashes_result;
142
143   EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
144   EXPECT_TRUE(add_full_hashes_result.empty());
145
146   std::vector<SBPrefix> prefixes_result;
147   builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
148   EXPECT_TRUE(prefixes_result.empty());
149 }
150
151 // Write some prefix and hash data to the store, add more data in another
152 // transaction, then verify that the union of all the data is present.
153 TEST_F(SafeBrowsingStoreFileTest, BasicStore) {
154   PopulateStore();
155
156   ASSERT_TRUE(store_->BeginUpdate());
157
158   std::vector<int> chunks;
159   store_->GetAddChunks(&chunks);
160   ASSERT_EQ(2U, chunks.size());
161   EXPECT_EQ(kAddChunk1, chunks[0]);
162   EXPECT_EQ(kAddChunk2, chunks[1]);
163
164   store_->GetSubChunks(&chunks);
165   ASSERT_EQ(1U, chunks.size());
166   EXPECT_EQ(kSubChunk1, chunks[0]);
167
168   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
169   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
170
171   EXPECT_TRUE(store_->BeginChunk());
172   store_->SetAddChunk(kAddChunk3);
173   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash5.prefix));
174   EXPECT_TRUE(store_->FinishChunk());
175
176   // Still has the chunks expected in the next update.
177   {
178     safe_browsing::PrefixSetBuilder builder;
179     std::vector<SBAddFullHash> add_full_hashes_result;
180     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
181
182     std::vector<SBPrefix> prefixes_result;
183     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
184     ASSERT_EQ(3U, prefixes_result.size());
185     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
186     EXPECT_EQ(kHash5.prefix, prefixes_result[1]);
187     EXPECT_EQ(kHash2.prefix, prefixes_result[2]);
188
189     ASSERT_EQ(1U, add_full_hashes_result.size());
190     EXPECT_EQ(kAddChunk2, add_full_hashes_result[0].chunk_id);
191     EXPECT_TRUE(SBFullHashEqual(kHash4, add_full_hashes_result[0].full_hash));
192   }
193 }
194
195 // Verify that the min and max prefixes are stored and operated on.
196 TEST_F(SafeBrowsingStoreFileTest, PrefixMinMax) {
197   PopulateStore();
198
199   ASSERT_TRUE(store_->BeginUpdate());
200
201   EXPECT_TRUE(store_->BeginChunk());
202   store_->SetAddChunk(kAddChunk3);
203   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kMinSBPrefix));
204   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kMaxSBPrefix));
205   EXPECT_TRUE(store_->FinishChunk());
206
207   {
208     safe_browsing::PrefixSetBuilder builder;
209     std::vector<SBAddFullHash> add_full_hashes_result;
210     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
211
212     std::vector<SBPrefix> prefixes_result;
213     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
214     ASSERT_EQ(4U, prefixes_result.size());
215     EXPECT_EQ(kMinSBPrefix, prefixes_result[0]);
216     EXPECT_EQ(kHash1.prefix, prefixes_result[1]);
217     EXPECT_EQ(kHash2.prefix, prefixes_result[2]);
218     EXPECT_EQ(kMaxSBPrefix, prefixes_result[3]);
219   }
220
221   ASSERT_TRUE(store_->BeginUpdate());
222
223   EXPECT_TRUE(store_->BeginChunk());
224   store_->SetAddChunk(kSubChunk2);
225   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk2, kAddChunk3, kMinSBPrefix));
226   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk2, kAddChunk3, kMaxSBPrefix));
227   EXPECT_TRUE(store_->FinishChunk());
228
229   {
230     safe_browsing::PrefixSetBuilder builder;
231     std::vector<SBAddFullHash> add_full_hashes_result;
232     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
233
234     std::vector<SBPrefix> prefixes_result;
235     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
236     ASSERT_EQ(2U, prefixes_result.size());
237     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
238     EXPECT_EQ(kHash2.prefix, prefixes_result[1]);
239   }
240 }
241
242 // Test that subs knockout adds.
243 TEST_F(SafeBrowsingStoreFileTest, SubKnockout) {
244   ASSERT_TRUE(store_->BeginUpdate());
245
246   EXPECT_TRUE(store_->BeginChunk());
247   store_->SetAddChunk(kAddChunk1);
248   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
249   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
250   EXPECT_TRUE(store_->FinishChunk());
251
252   EXPECT_TRUE(store_->BeginChunk());
253   store_->SetAddChunk(kAddChunk2);
254   EXPECT_TRUE(store_->WriteAddHash(kAddChunk2, kHash4));
255   EXPECT_TRUE(store_->FinishChunk());
256
257   EXPECT_TRUE(store_->BeginChunk());
258   store_->SetSubChunk(kSubChunk1);
259   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
260   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
261   EXPECT_TRUE(store_->FinishChunk());
262
263   {
264     safe_browsing::PrefixSetBuilder builder;
265     std::vector<SBAddFullHash> add_full_hashes_result;
266     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
267
268     // Knocked out the chunk expected.
269     std::vector<SBPrefix> prefixes_result;
270     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
271     ASSERT_EQ(1U, prefixes_result.size());
272     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
273
274     ASSERT_EQ(1U, add_full_hashes_result.size());
275     EXPECT_EQ(kAddChunk2, add_full_hashes_result[0].chunk_id);
276     EXPECT_TRUE(SBFullHashEqual(kHash4, add_full_hashes_result[0].full_hash));
277   }
278
279   ASSERT_TRUE(store_->BeginUpdate());
280
281   // This add should be knocked out by an existing sub.
282   EXPECT_TRUE(store_->BeginChunk());
283   store_->SetAddChunk(kAddChunk3);
284   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash3.prefix));
285   EXPECT_TRUE(store_->FinishChunk());
286
287   {
288     safe_browsing::PrefixSetBuilder builder;
289     std::vector<SBAddFullHash> add_full_hashes_result;
290     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
291
292     std::vector<SBPrefix> prefixes_result;
293     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
294     ASSERT_EQ(1U, prefixes_result.size());
295     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
296
297     ASSERT_EQ(1U, add_full_hashes_result.size());
298     EXPECT_EQ(kAddChunk2, add_full_hashes_result[0].chunk_id);
299     EXPECT_TRUE(SBFullHashEqual(kHash4, add_full_hashes_result[0].full_hash));
300   }
301
302   ASSERT_TRUE(store_->BeginUpdate());
303
304   // But by here the sub should be gone, so it should stick this time.
305   EXPECT_TRUE(store_->BeginChunk());
306   store_->SetAddChunk(kAddChunk3);
307   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash3.prefix));
308   EXPECT_TRUE(store_->FinishChunk());
309
310   {
311     safe_browsing::PrefixSetBuilder builder;
312     std::vector<SBAddFullHash> add_full_hashes_result;
313     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
314
315     std::vector<SBPrefix> prefixes_result;
316     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
317     ASSERT_EQ(2U, prefixes_result.size());
318     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
319     EXPECT_EQ(kHash3.prefix, prefixes_result[1]);
320
321     ASSERT_EQ(1U, add_full_hashes_result.size());
322     EXPECT_EQ(kAddChunk2, add_full_hashes_result[0].chunk_id);
323     EXPECT_TRUE(SBFullHashEqual(kHash4, add_full_hashes_result[0].full_hash));
324   }
325 }
326
327 // Test that deletes delete the chunk's data.
328 TEST_F(SafeBrowsingStoreFileTest, DeleteChunks) {
329   ASSERT_TRUE(store_->BeginUpdate());
330
331   // A prefix chunk which will be deleted.
332   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
333   store_->SetAddChunk(kAddChunk1);
334   EXPECT_TRUE(store_->BeginChunk());
335   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
336   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
337   EXPECT_TRUE(store_->FinishChunk());
338
339   // A prefix chunk which won't be deleted.
340   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk2));
341   store_->SetAddChunk(kAddChunk2);
342   EXPECT_TRUE(store_->BeginChunk());
343   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk2, kHash3.prefix));
344   EXPECT_TRUE(store_->FinishChunk());
345
346   // A full-hash chunk which won't be deleted.
347   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
348   store_->SetAddChunk(kAddChunk3);
349   EXPECT_TRUE(store_->BeginChunk());
350   EXPECT_TRUE(store_->WriteAddHash(kAddChunk3, kHash6));
351   EXPECT_TRUE(store_->FinishChunk());
352
353   // A sub chunk to delete.
354   EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
355   store_->SetSubChunk(kSubChunk1);
356   EXPECT_TRUE(store_->BeginChunk());
357   EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash4));
358   EXPECT_TRUE(store_->FinishChunk());
359
360   // A sub chunk to keep.
361   EXPECT_FALSE(store_->CheckSubChunk(kSubChunk2));
362   store_->SetSubChunk(kSubChunk2);
363   EXPECT_TRUE(store_->BeginChunk());
364   EXPECT_TRUE(store_->WriteSubHash(kSubChunk2, kAddChunk4, kHash5));
365   EXPECT_TRUE(store_->FinishChunk());
366
367   store_->DeleteAddChunk(kAddChunk1);
368   store_->DeleteSubChunk(kSubChunk1);
369
370   // Not actually deleted until finish.
371   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
372   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
373   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk3));
374   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
375   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk2));
376
377   {
378     safe_browsing::PrefixSetBuilder builder;
379     std::vector<SBAddFullHash> add_full_hashes_result;
380     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
381
382     std::vector<SBPrefix> prefixes_result;
383     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
384     ASSERT_EQ(1U, prefixes_result.size());
385     EXPECT_EQ(kHash3.prefix, prefixes_result[0]);
386
387     ASSERT_EQ(1U, add_full_hashes_result.size());
388     EXPECT_EQ(kAddChunk3, add_full_hashes_result[0].chunk_id);
389     EXPECT_TRUE(SBFullHashEqual(kHash6, add_full_hashes_result[0].full_hash));
390   }
391
392   // Expected chunks are there in another update.
393   ASSERT_TRUE(store_->BeginUpdate());
394   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
395   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
396   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk3));
397   EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
398   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk2));
399
400   // Delete them, too.
401   store_->DeleteAddChunk(kAddChunk2);
402   store_->DeleteAddChunk(kAddChunk3);
403   store_->DeleteSubChunk(kSubChunk2);
404
405   {
406     safe_browsing::PrefixSetBuilder builder;
407     std::vector<SBAddFullHash> add_full_hashes_result;
408     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
409
410     std::vector<SBPrefix> prefixes_result;
411     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
412     EXPECT_TRUE(prefixes_result.empty());
413     EXPECT_TRUE(add_full_hashes_result.empty());
414   }
415
416   // Expect no more chunks.
417   ASSERT_TRUE(store_->BeginUpdate());
418   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
419   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk2));
420   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
421   EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
422   EXPECT_FALSE(store_->CheckSubChunk(kSubChunk2));
423
424   {
425     safe_browsing::PrefixSetBuilder builder;
426     std::vector<SBAddFullHash> add_full_hashes_result;
427     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
428
429     std::vector<SBPrefix> prefixes_result;
430     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
431     EXPECT_TRUE(prefixes_result.empty());
432     EXPECT_TRUE(add_full_hashes_result.empty());
433   }
434 }
435
436 // Test that deleting the store deletes the store.
437 TEST_F(SafeBrowsingStoreFileTest, Delete) {
438   // Delete should work if the file wasn't there in the first place.
439   EXPECT_FALSE(base::PathExists(filename_));
440   EXPECT_TRUE(store_->Delete());
441
442   // Create a store file.
443   PopulateStore();
444
445   EXPECT_TRUE(base::PathExists(filename_));
446   EXPECT_TRUE(store_->Delete());
447   EXPECT_FALSE(base::PathExists(filename_));
448 }
449
450 // Test that Delete() deletes the temporary store, if present.
451 TEST_F(SafeBrowsingStoreFileTest, DeleteTemp) {
452   const base::FilePath temp_file =
453       SafeBrowsingStoreFile::TemporaryFileForFilename(filename_);
454
455   EXPECT_FALSE(base::PathExists(filename_));
456   EXPECT_FALSE(base::PathExists(temp_file));
457
458   // Starting a transaction creates a temporary file.
459   ASSERT_TRUE(store_->BeginUpdate());
460   EXPECT_TRUE(base::PathExists(temp_file));
461
462   // Pull the rug out from under the existing store, simulating a
463   // crash.
464   store_.reset(new SafeBrowsingStoreFile());
465   store_->Init(filename_, base::Closure());
466   EXPECT_FALSE(base::PathExists(filename_));
467   EXPECT_TRUE(base::PathExists(temp_file));
468
469   // Make sure the temporary file is deleted.
470   EXPECT_TRUE(store_->Delete());
471   EXPECT_FALSE(base::PathExists(filename_));
472   EXPECT_FALSE(base::PathExists(temp_file));
473 }
474
475 // Test basic corruption-handling.
476 TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
477   // Load a store with some data.
478   PopulateStore();
479
480   // Can successfully open and read the store.
481   {
482     std::vector<SBPrefix> orig_prefixes;
483     std::vector<SBAddFullHash> orig_hashes;
484     safe_browsing::PrefixSetBuilder builder;
485     ASSERT_TRUE(store_->BeginUpdate());
486     EXPECT_TRUE(store_->FinishUpdate(&builder, &orig_hashes));
487     builder.GetPrefixSetNoHashes()->GetPrefixes(&orig_prefixes);
488     EXPECT_GT(orig_prefixes.size(), 0U);
489     EXPECT_GT(orig_hashes.size(), 0U);
490     EXPECT_FALSE(corruption_detected_);
491   }
492
493   // Corrupt the store.
494   base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
495   const long kOffset = 60;
496   EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
497   const uint32 kZero = 0;
498   uint32 previous = kZero;
499   EXPECT_EQ(fread(&previous, sizeof(previous), 1, file.get()), 1U);
500   EXPECT_NE(previous, kZero);
501   EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
502   EXPECT_EQ(fwrite(&kZero, sizeof(kZero), 1, file.get()), 1U);
503   file.reset();
504
505   // Update fails and corruption callback is called.
506   std::vector<SBAddFullHash> add_hashes;
507   corruption_detected_ = false;
508   {
509     safe_browsing::PrefixSetBuilder builder;
510     ASSERT_TRUE(store_->BeginUpdate());
511     EXPECT_FALSE(store_->FinishUpdate(&builder, &add_hashes));
512     EXPECT_TRUE(corruption_detected_);
513   }
514
515   // Make it look like there is a lot of add-chunks-seen data.
516   const long kAddChunkCountOffset = 2 * sizeof(int32);
517   const int32 kLargeCount = 1000 * 1000 * 1000;
518   file.reset(base::OpenFile(filename_, "rb+"));
519   EXPECT_EQ(fseek(file.get(), kAddChunkCountOffset, SEEK_SET), 0);
520   EXPECT_EQ(fwrite(&kLargeCount, sizeof(kLargeCount), 1, file.get()), 1U);
521   file.reset();
522
523   // Detects corruption and fails to even begin the update.
524   corruption_detected_ = false;
525   EXPECT_FALSE(store_->BeginUpdate());
526   EXPECT_TRUE(corruption_detected_);
527 }
528
529 TEST_F(SafeBrowsingStoreFileTest, CheckValidity) {
530   // Empty store is valid.
531   EXPECT_FALSE(base::PathExists(filename_));
532   ASSERT_TRUE(store_->BeginUpdate());
533   EXPECT_FALSE(corruption_detected_);
534   EXPECT_TRUE(store_->CheckValidity());
535   EXPECT_FALSE(corruption_detected_);
536   EXPECT_TRUE(store_->CancelUpdate());
537
538   // A store with some data is valid.
539   EXPECT_FALSE(base::PathExists(filename_));
540   PopulateStore();
541   EXPECT_TRUE(base::PathExists(filename_));
542   ASSERT_TRUE(store_->BeginUpdate());
543   EXPECT_FALSE(corruption_detected_);
544   EXPECT_TRUE(store_->CheckValidity());
545   EXPECT_FALSE(corruption_detected_);
546   EXPECT_TRUE(store_->CancelUpdate());
547 }
548
549 // Corrupt the header.
550 TEST_F(SafeBrowsingStoreFileTest, CheckValidityHeader) {
551   PopulateStore();
552   EXPECT_TRUE(base::PathExists(filename_));
553
554   // 37 is the most random prime number.  It's also past the initial header
555   // struct, somewhere in the chunk list.
556   const size_t kOffset = 37;
557
558   {
559     base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
560     EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_SET));
561     EXPECT_GE(fputs("hello", file.get()), 0);
562   }
563   ASSERT_FALSE(store_->BeginUpdate());
564   EXPECT_TRUE(corruption_detected_);
565 }
566
567 // Corrupt the prefix payload.
568 TEST_F(SafeBrowsingStoreFileTest, CheckValidityPayload) {
569   PopulateStore();
570   EXPECT_TRUE(base::PathExists(filename_));
571
572   // 137 is the second most random prime number.  It's also past the header and
573   // chunk-id area.  Corrupting the header would fail BeginUpdate() in which
574   // case CheckValidity() cannot be called.
575   const size_t kOffset = 137;
576
577   {
578     base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
579     EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_SET));
580     EXPECT_GE(fputs("hello", file.get()), 0);
581   }
582   ASSERT_TRUE(store_->BeginUpdate());
583   EXPECT_FALSE(corruption_detected_);
584   EXPECT_FALSE(store_->CheckValidity());
585   EXPECT_TRUE(corruption_detected_);
586   EXPECT_TRUE(store_->CancelUpdate());
587 }
588
589 // Corrupt the checksum.
590 TEST_F(SafeBrowsingStoreFileTest, CheckValidityChecksum) {
591   PopulateStore();
592   EXPECT_TRUE(base::PathExists(filename_));
593
594   // An offset from the end of the file which is in the checksum.
595   const int kOffset = -static_cast<int>(sizeof(base::MD5Digest));
596
597   {
598     base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
599     EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_END));
600     EXPECT_GE(fputs("hello", file.get()), 0);
601   }
602   ASSERT_TRUE(store_->BeginUpdate());
603   EXPECT_FALSE(corruption_detected_);
604   EXPECT_FALSE(store_->CheckValidity());
605   EXPECT_TRUE(corruption_detected_);
606   EXPECT_TRUE(store_->CancelUpdate());
607 }
608
609 TEST_F(SafeBrowsingStoreFileTest, GetAddPrefixesAndHashes) {
610   ASSERT_TRUE(store_->BeginUpdate());
611
612   EXPECT_TRUE(store_->BeginChunk());
613   store_->SetAddChunk(kAddChunk1);
614   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
615   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
616   EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
617   EXPECT_TRUE(store_->FinishChunk());
618
619   EXPECT_TRUE(store_->BeginChunk());
620   store_->SetAddChunk(kAddChunk2);
621   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
622   EXPECT_TRUE(store_->WriteAddHash(kAddChunk2, kHash4));
623   EXPECT_TRUE(store_->FinishChunk());
624
625   store_->SetSubChunk(kSubChunk1);
626   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
627   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
628   EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash3));
629   EXPECT_TRUE(store_->FinishChunk());
630
631   // Chunk numbers shouldn't leak over.
632   EXPECT_FALSE(store_->CheckAddChunk(kSubChunk1));
633   EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
634   EXPECT_FALSE(store_->CheckSubChunk(kAddChunk1));
635
636   std::vector<int> chunks;
637   store_->GetAddChunks(&chunks);
638   ASSERT_EQ(2U, chunks.size());
639   EXPECT_EQ(kAddChunk1, chunks[0]);
640   EXPECT_EQ(kAddChunk2, chunks[1]);
641
642   store_->GetSubChunks(&chunks);
643   ASSERT_EQ(1U, chunks.size());
644   EXPECT_EQ(kSubChunk1, chunks[0]);
645
646   safe_browsing::PrefixSetBuilder builder;
647   std::vector<SBAddFullHash> add_full_hashes_result;
648   EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
649
650   SBAddPrefixes add_prefixes;
651   EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
652   ASSERT_EQ(2U, add_prefixes.size());
653   EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
654   EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
655   EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
656   EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
657
658   std::vector<SBAddFullHash> add_hashes;
659   EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
660   ASSERT_EQ(1U, add_hashes.size());
661   EXPECT_EQ(kAddChunk2, add_hashes[0].chunk_id);
662   EXPECT_TRUE(SBFullHashEqual(kHash4, add_hashes[0].full_hash));
663 }
664
665 // Test that the database handles resharding correctly, both when growing and
666 // which shrinking.
667 TEST_F(SafeBrowsingStoreFileTest, Resharding) {
668   // Loop through multiple stride boundaries (1<<32, 1<<31, 1<<30, 1<<29).
669   const uint32 kTargetStride = 1 << 29;
670
671   // Each chunk will require 8 bytes per prefix, plus 4 bytes for chunk
672   // information.  It should be less than |kTargetFootprint| in the
673   // implementation, but high enough to keep the number of rewrites modest (to
674   // keep the test fast).
675   const size_t kPrefixesPerChunk = 10000;
676
677   uint32 shard_stride = 0;
678   int chunk_id = 1;
679
680   // Add a series of chunks, tracking that the stride size changes in a
681   // direction appropriate to increasing file size.
682   do {
683     ASSERT_TRUE(store_->BeginUpdate());
684
685     EXPECT_TRUE(store_->BeginChunk());
686     store_->SetAddChunk(chunk_id);
687     EXPECT_TRUE(store_->CheckAddChunk(chunk_id));
688     for (size_t i = 0; i < kPrefixesPerChunk; ++i) {
689       EXPECT_TRUE(store_->WriteAddPrefix(chunk_id, static_cast<SBPrefix>(i)));
690     }
691     EXPECT_TRUE(store_->FinishChunk());
692
693     safe_browsing::PrefixSetBuilder builder;
694     std::vector<SBAddFullHash> add_full_hashes_result;
695     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
696
697     SBAddPrefixes add_prefixes;
698     EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
699     ASSERT_EQ(chunk_id * kPrefixesPerChunk, add_prefixes.size());
700
701     // New stride should be the same, or shifted one right.
702     const uint32 new_shard_stride = ReadStride();
703     EXPECT_TRUE((new_shard_stride == shard_stride) ||
704                 ((new_shard_stride << 1) == shard_stride));
705     shard_stride = new_shard_stride;
706     ++chunk_id;
707   } while (!shard_stride || shard_stride > kTargetStride);
708
709   // Guard against writing too many chunks.  If this gets too big, adjust
710   // |kPrefixesPerChunk|.
711   EXPECT_LT(chunk_id, 20);
712
713   // Remove each chunk and check that the stride goes back to 0.
714   while (--chunk_id) {
715     ASSERT_TRUE(store_->BeginUpdate());
716     EXPECT_TRUE(store_->CheckAddChunk(chunk_id));
717     EXPECT_FALSE(store_->CheckAddChunk(chunk_id + 1));
718     store_->DeleteAddChunk(chunk_id);
719
720     safe_browsing::PrefixSetBuilder builder;
721     std::vector<SBAddFullHash> add_full_hashes_result;
722     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
723
724     // New stride should be the same, or shifted one left.
725     const uint32 new_shard_stride = ReadStride();
726     EXPECT_TRUE((new_shard_stride == shard_stride) ||
727                 (new_shard_stride == (shard_stride << 1)));
728     shard_stride = new_shard_stride;
729   }
730   EXPECT_EQ(0u, shard_stride);
731 }
732
733 // Test that a golden v7 file can no longer be read.  All platforms generating
734 // v7 files were little-endian, so there is no point to testing this transition
735 // if/when a big-endian port is added.
736 #if defined(ARCH_CPU_LITTLE_ENDIAN)
737 TEST_F(SafeBrowsingStoreFileTest, Version7) {
738   store_.reset();
739
740   // Copy the golden file into temporary storage.  The golden file contains:
741   // - Add chunk kAddChunk1 containing kHash1.prefix and kHash2.
742   // - Sub chunk kSubChunk1 containing kHash3.
743   const char kBasename[] = "FileStoreVersion7";
744   base::FilePath golden_path;
745   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &golden_path));
746   golden_path = golden_path.AppendASCII("SafeBrowsing");
747   golden_path = golden_path.AppendASCII(kBasename);
748   ASSERT_TRUE(base::CopyFile(golden_path, filename_));
749
750   // Reset the store to make sure it re-reads the file.
751   store_.reset(new SafeBrowsingStoreFile());
752   store_->Init(filename_,
753                base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
754                           base::Unretained(this)));
755   EXPECT_FALSE(corruption_detected_);
756
757   // The unknown version should be encountered on the first read.
758   EXPECT_FALSE(store_->BeginUpdate());
759   EXPECT_TRUE(corruption_detected_);
760
761   // No more to test because corrupt file stores are cleaned up by the database
762   // containing them.
763 }
764 #endif
765
766 // Test that a golden v8 file can be read by the current code.  All platforms
767 // generating v8 files are little-endian, so there is no point to testing this
768 // transition if/when a big-endian port is added.
769 #if defined(ARCH_CPU_LITTLE_ENDIAN)
770 TEST_F(SafeBrowsingStoreFileTest, Version8) {
771   store_.reset();
772
773   // Copy the golden file into temporary storage.  The golden file contains:
774   // - Add chunk kAddChunk1 containing kHash1.prefix and kHash2.
775   // - Sub chunk kSubChunk1 containing kHash3.
776   const char kBasename[] = "FileStoreVersion8";
777   base::FilePath golden_path;
778   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &golden_path));
779   golden_path = golden_path.AppendASCII("SafeBrowsing");
780   golden_path = golden_path.AppendASCII(kBasename);
781   ASSERT_TRUE(base::CopyFile(golden_path, filename_));
782
783   // Reset the store to make sure it re-reads the file.
784   store_.reset(new SafeBrowsingStoreFile());
785   store_->Init(filename_,
786                base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
787                           base::Unretained(this)));
788
789   // Check that the expected prefixes and hashes are in place.
790   SBAddPrefixes add_prefixes;
791   EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
792   ASSERT_EQ(2U, add_prefixes.size());
793   EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
794   EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
795   EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
796   EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
797
798   std::vector<SBAddFullHash> add_hashes;
799   EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
800   ASSERT_EQ(1U, add_hashes.size());
801   EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
802   EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
803
804   // Attempt an update to make sure things work end-to-end.
805   EXPECT_TRUE(store_->BeginUpdate());
806
807   // Still has the chunks expected in the next update.
808   std::vector<int> chunks;
809   store_->GetAddChunks(&chunks);
810   ASSERT_EQ(1U, chunks.size());
811   EXPECT_EQ(kAddChunk1, chunks[0]);
812
813   store_->GetSubChunks(&chunks);
814   ASSERT_EQ(1U, chunks.size());
815   EXPECT_EQ(kSubChunk1, chunks[0]);
816
817   EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
818   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
819
820   // Sub chunk kAddChunk1 hash kHash2.
821   // NOTE(shess): Having full hashes and prefixes in the same chunk is no longer
822   // supported, though it was when this code was written.
823   store_->SetSubChunk(kSubChunk2);
824   EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
825   EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
826   EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk1, kHash2));
827   EXPECT_TRUE(store_->FinishChunk());
828
829   {
830     safe_browsing::PrefixSetBuilder builder;
831     std::vector<SBAddFullHash> add_full_hashes_result;
832     EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
833
834     // The sub'ed prefix and hash are gone.
835     std::vector<SBPrefix> prefixes_result;
836     builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
837     ASSERT_EQ(1U, prefixes_result.size());
838     EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
839     EXPECT_TRUE(add_full_hashes_result.empty());
840   }
841 }
842 #endif
843
844 }  // namespace safe_browsing