[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_store_file_unittest.cc
blobb0284469db923f3895c5645d1fb57b5b04951ac2
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.
5 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
7 #include "base/bind.h"
8 #include "base/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"
17 namespace {
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;
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");
34 const SBPrefix kMinSBPrefix = 0u;
35 const SBPrefix kMaxSBPrefix = ~kMinSBPrefix;
37 } // namespace
39 namespace safe_browsing {
41 class SafeBrowsingStoreFileTest : public PlatformTest {
42 public:
43 virtual void SetUp() {
44 PlatformTest::SetUp();
46 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
48 filename_ = temp_dir_.path();
49 filename_ = filename_.AppendASCII("SafeBrowsingTestStore");
51 store_.reset(new SafeBrowsingStoreFile());
52 store_->Init(filename_,
53 base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
54 base::Unretained(this)));
55 corruption_detected_ = false;
57 virtual void TearDown() {
58 if (store_.get())
59 store_->Delete();
60 store_.reset();
62 PlatformTest::TearDown();
65 void OnCorruptionDetected() {
66 corruption_detected_ = true;
69 // Populate the store with some testing data.
70 void PopulateStore() {
71 ASSERT_TRUE(store_->BeginUpdate());
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());
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());
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());
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));
99 safe_browsing::PrefixSetBuilder builder;
100 std::vector<SBAddFullHash> add_full_hashes_result;
102 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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;
115 base::ScopedTempDir temp_dir_;
116 base::FilePath filename_;
117 scoped_ptr<SafeBrowsingStoreFile> store_;
118 bool corruption_detected_;
121 // Test that the empty store looks empty.
122 TEST_F(SafeBrowsingStoreFileTest, Empty) {
123 ASSERT_TRUE(store_->BeginUpdate());
125 std::vector<int> chunks;
126 store_->GetAddChunks(&chunks);
127 EXPECT_TRUE(chunks.empty());
128 store_->GetSubChunks(&chunks);
129 EXPECT_TRUE(chunks.empty());
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));
136 EXPECT_FALSE(store_->CheckSubChunk(0));
137 EXPECT_FALSE(store_->CheckSubChunk(1));
138 EXPECT_FALSE(store_->CheckSubChunk(-1));
140 safe_browsing::PrefixSetBuilder builder;
141 std::vector<SBAddFullHash> add_full_hashes_result;
143 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
144 EXPECT_TRUE(add_full_hashes_result.empty());
146 std::vector<SBPrefix> prefixes_result;
147 builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
148 EXPECT_TRUE(prefixes_result.empty());
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();
156 ASSERT_TRUE(store_->BeginUpdate());
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]);
164 store_->GetSubChunks(&chunks);
165 ASSERT_EQ(1U, chunks.size());
166 EXPECT_EQ(kSubChunk1, chunks[0]);
168 EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
169 EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
171 EXPECT_TRUE(store_->BeginChunk());
172 store_->SetAddChunk(kAddChunk3);
173 EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash5.prefix));
174 EXPECT_TRUE(store_->FinishChunk());
176 // Still has the chunks expected in the next update.
178 safe_browsing::PrefixSetBuilder builder;
179 std::vector<SBAddFullHash> add_full_hashes_result;
180 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
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));
195 // Verify that the min and max prefixes are stored and operated on.
196 TEST_F(SafeBrowsingStoreFileTest, PrefixMinMax) {
197 PopulateStore();
199 ASSERT_TRUE(store_->BeginUpdate());
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());
208 safe_browsing::PrefixSetBuilder builder;
209 std::vector<SBAddFullHash> add_full_hashes_result;
210 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
221 ASSERT_TRUE(store_->BeginUpdate());
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());
230 safe_browsing::PrefixSetBuilder builder;
231 std::vector<SBAddFullHash> add_full_hashes_result;
232 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
242 // Test that subs knockout adds.
243 TEST_F(SafeBrowsingStoreFileTest, SubKnockout) {
244 ASSERT_TRUE(store_->BeginUpdate());
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());
252 EXPECT_TRUE(store_->BeginChunk());
253 store_->SetAddChunk(kAddChunk2);
254 EXPECT_TRUE(store_->WriteAddHash(kAddChunk2, kHash4));
255 EXPECT_TRUE(store_->FinishChunk());
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());
264 safe_browsing::PrefixSetBuilder builder;
265 std::vector<SBAddFullHash> add_full_hashes_result;
266 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
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));
279 ASSERT_TRUE(store_->BeginUpdate());
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());
288 safe_browsing::PrefixSetBuilder builder;
289 std::vector<SBAddFullHash> add_full_hashes_result;
290 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
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));
302 ASSERT_TRUE(store_->BeginUpdate());
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());
311 safe_browsing::PrefixSetBuilder builder;
312 std::vector<SBAddFullHash> add_full_hashes_result;
313 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
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));
327 // Test that deletes delete the chunk's data.
328 TEST_F(SafeBrowsingStoreFileTest, DeleteChunks) {
329 ASSERT_TRUE(store_->BeginUpdate());
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());
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());
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());
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());
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());
367 store_->DeleteAddChunk(kAddChunk1);
368 store_->DeleteSubChunk(kSubChunk1);
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));
378 safe_browsing::PrefixSetBuilder builder;
379 std::vector<SBAddFullHash> add_full_hashes_result;
380 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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]);
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));
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));
400 // Delete them, too.
401 store_->DeleteAddChunk(kAddChunk2);
402 store_->DeleteAddChunk(kAddChunk3);
403 store_->DeleteSubChunk(kSubChunk2);
406 safe_browsing::PrefixSetBuilder builder;
407 std::vector<SBAddFullHash> add_full_hashes_result;
408 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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());
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));
425 safe_browsing::PrefixSetBuilder builder;
426 std::vector<SBAddFullHash> add_full_hashes_result;
427 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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());
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());
442 // Create a store file.
443 PopulateStore();
445 EXPECT_TRUE(base::PathExists(filename_));
446 EXPECT_TRUE(store_->Delete());
447 EXPECT_FALSE(base::PathExists(filename_));
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_);
455 EXPECT_FALSE(base::PathExists(filename_));
456 EXPECT_FALSE(base::PathExists(temp_file));
458 // Starting a transaction creates a temporary file.
459 ASSERT_TRUE(store_->BeginUpdate());
460 EXPECT_TRUE(base::PathExists(temp_file));
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));
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));
475 // Test basic corruption-handling.
476 TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
477 // Load a store with some data.
478 PopulateStore();
480 // Can successfully open and read the store.
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_);
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();
505 // Update fails and corruption callback is called.
506 std::vector<SBAddFullHash> add_hashes;
507 corruption_detected_ = false;
509 safe_browsing::PrefixSetBuilder builder;
510 ASSERT_TRUE(store_->BeginUpdate());
511 EXPECT_FALSE(store_->FinishUpdate(&builder, &add_hashes));
512 EXPECT_TRUE(corruption_detected_);
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();
523 // Detects corruption and fails to even begin the update.
524 corruption_detected_ = false;
525 EXPECT_FALSE(store_->BeginUpdate());
526 EXPECT_TRUE(corruption_detected_);
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());
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());
549 // Corrupt the header.
550 TEST_F(SafeBrowsingStoreFileTest, CheckValidityHeader) {
551 PopulateStore();
552 EXPECT_TRUE(base::PathExists(filename_));
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;
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);
563 ASSERT_FALSE(store_->BeginUpdate());
564 EXPECT_TRUE(corruption_detected_);
567 // Corrupt the prefix payload.
568 TEST_F(SafeBrowsingStoreFileTest, CheckValidityPayload) {
569 PopulateStore();
570 EXPECT_TRUE(base::PathExists(filename_));
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;
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);
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());
589 // Corrupt the checksum.
590 TEST_F(SafeBrowsingStoreFileTest, CheckValidityChecksum) {
591 PopulateStore();
592 EXPECT_TRUE(base::PathExists(filename_));
594 // An offset from the end of the file which is in the checksum.
595 const int kOffset = -static_cast<int>(sizeof(base::MD5Digest));
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);
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());
609 TEST_F(SafeBrowsingStoreFileTest, GetAddPrefixesAndHashes) {
610 ASSERT_TRUE(store_->BeginUpdate());
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());
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());
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());
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));
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]);
642 store_->GetSubChunks(&chunks);
643 ASSERT_EQ(1U, chunks.size());
644 EXPECT_EQ(kSubChunk1, chunks[0]);
646 safe_browsing::PrefixSetBuilder builder;
647 std::vector<SBAddFullHash> add_full_hashes_result;
648 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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);
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));
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;
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;
677 uint32 shard_stride = 0;
678 int chunk_id = 1;
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());
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)));
691 EXPECT_TRUE(store_->FinishChunk());
693 safe_browsing::PrefixSetBuilder builder;
694 std::vector<SBAddFullHash> add_full_hashes_result;
695 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
697 SBAddPrefixes add_prefixes;
698 EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
699 ASSERT_EQ(chunk_id * kPrefixesPerChunk, add_prefixes.size());
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);
709 // Guard against writing too many chunks. If this gets too big, adjust
710 // |kPrefixesPerChunk|.
711 EXPECT_LT(chunk_id, 20);
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);
720 safe_browsing::PrefixSetBuilder builder;
721 std::vector<SBAddFullHash> add_full_hashes_result;
722 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
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;
730 EXPECT_EQ(0u, shard_stride);
733 // Test that a golden v7 file can be read by the current code. All platforms
734 // generating v7 files are little-endian, so there is no point to testing this
735 // transition if/when a big-endian port is added.
736 #if defined(ARCH_CPU_LITTLE_ENDIAN)
737 TEST_F(SafeBrowsingStoreFileTest, Version7) {
738 store_.reset();
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_));
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)));
756 // Check that the expected prefixes and hashes are in place.
757 SBAddPrefixes add_prefixes;
758 EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
759 ASSERT_EQ(2U, add_prefixes.size());
760 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
761 EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
762 EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
763 EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
765 std::vector<SBAddFullHash> add_hashes;
766 EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
767 ASSERT_EQ(1U, add_hashes.size());
768 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
769 EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
771 // Attempt an update to make sure things work end-to-end.
772 EXPECT_TRUE(store_->BeginUpdate());
774 // Still has the chunks expected in the next update.
775 std::vector<int> chunks;
776 store_->GetAddChunks(&chunks);
777 ASSERT_EQ(1U, chunks.size());
778 EXPECT_EQ(kAddChunk1, chunks[0]);
780 store_->GetSubChunks(&chunks);
781 ASSERT_EQ(1U, chunks.size());
782 EXPECT_EQ(kSubChunk1, chunks[0]);
784 EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
785 EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
787 // Sub chunk kAddChunk1 hash kHash2.
788 store_->SetSubChunk(kSubChunk2);
789 EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
790 EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
791 EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk1, kHash2));
792 EXPECT_TRUE(store_->FinishChunk());
795 safe_browsing::PrefixSetBuilder builder;
796 std::vector<SBAddFullHash> add_full_hashes_result;
797 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
799 // The sub'ed prefix and hash are gone.
800 std::vector<SBPrefix> prefixes_result;
801 builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
802 ASSERT_EQ(1U, prefixes_result.size());
803 EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
804 EXPECT_TRUE(add_full_hashes_result.empty());
807 #endif
809 // Test that a golden v8 file can be read by the current code. All platforms
810 // generating v8 files are little-endian, so there is no point to testing this
811 // transition if/when a big-endian port is added.
812 #if defined(ARCH_CPU_LITTLE_ENDIAN)
813 TEST_F(SafeBrowsingStoreFileTest, Version8) {
814 store_.reset();
816 // Copy the golden file into temporary storage. The golden file contains:
817 // - Add chunk kAddChunk1 containing kHash1.prefix and kHash2.
818 // - Sub chunk kSubChunk1 containing kHash3.
819 const char kBasename[] = "FileStoreVersion8";
820 base::FilePath golden_path;
821 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &golden_path));
822 golden_path = golden_path.AppendASCII("SafeBrowsing");
823 golden_path = golden_path.AppendASCII(kBasename);
824 ASSERT_TRUE(base::CopyFile(golden_path, filename_));
826 // Reset the store to make sure it re-reads the file.
827 store_.reset(new SafeBrowsingStoreFile());
828 store_->Init(filename_,
829 base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
830 base::Unretained(this)));
832 // Check that the expected prefixes and hashes are in place.
833 SBAddPrefixes add_prefixes;
834 EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
835 ASSERT_EQ(2U, add_prefixes.size());
836 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
837 EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
838 EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
839 EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
841 std::vector<SBAddFullHash> add_hashes;
842 EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
843 ASSERT_EQ(1U, add_hashes.size());
844 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
845 EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
847 // Attempt an update to make sure things work end-to-end.
848 EXPECT_TRUE(store_->BeginUpdate());
850 // Still has the chunks expected in the next update.
851 std::vector<int> chunks;
852 store_->GetAddChunks(&chunks);
853 ASSERT_EQ(1U, chunks.size());
854 EXPECT_EQ(kAddChunk1, chunks[0]);
856 store_->GetSubChunks(&chunks);
857 ASSERT_EQ(1U, chunks.size());
858 EXPECT_EQ(kSubChunk1, chunks[0]);
860 EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
861 EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
863 // Sub chunk kAddChunk1 hash kHash2.
864 store_->SetSubChunk(kSubChunk2);
865 EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
866 EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
867 EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk1, kHash2));
868 EXPECT_TRUE(store_->FinishChunk());
871 safe_browsing::PrefixSetBuilder builder;
872 std::vector<SBAddFullHash> add_full_hashes_result;
873 EXPECT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
875 // The sub'ed prefix and hash are gone.
876 std::vector<SBPrefix> prefixes_result;
877 builder.GetPrefixSetNoHashes()->GetPrefixes(&prefixes_result);
878 ASSERT_EQ(1U, prefixes_result.size());
879 EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
880 EXPECT_TRUE(add_full_hashes_result.empty());
883 #endif
885 // Test that when the v8 golden file is updated, the add prefix injected from
886 // the full hash is removed. All platforms generating v8 files are
887 // little-endian, so there is no point to testing this transition if/when a
888 // big-endian port is added.
889 #if defined(ARCH_CPU_LITTLE_ENDIAN)
890 TEST_F(SafeBrowsingStoreFileTest, KnockoutPrefixVolunteers) {
891 store_.reset();
893 // Copy the golden file into temporary storage. The golden file contains:
894 // - Add chunk kAddChunk1 containing kHash1.prefix and kHash2.
895 // - Sub chunk kSubChunk1 containing kHash3.
896 const char kBasename[] = "FileStoreVersion8";
897 base::FilePath golden_path;
898 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &golden_path));
899 golden_path = golden_path.AppendASCII("SafeBrowsing");
900 golden_path = golden_path.AppendASCII(kBasename);
901 ASSERT_TRUE(base::CopyFile(golden_path, filename_));
903 // Reset the store to make sure it re-reads the file.
904 store_.reset(new SafeBrowsingStoreFile());
905 store_->Init(filename_,
906 base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
907 base::Unretained(this)));
909 // Check that the expected prefixes and hashes are in place.
911 SBAddPrefixes add_prefixes;
912 EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
913 ASSERT_EQ(2U, add_prefixes.size());
914 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
915 EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
916 EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
917 EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
919 std::vector<SBAddFullHash> add_hashes;
920 EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
921 ASSERT_EQ(1U, add_hashes.size());
922 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
923 EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
926 // Update the store.
928 EXPECT_TRUE(store_->BeginUpdate());
930 safe_browsing::PrefixSetBuilder builder;
931 std::vector<SBAddFullHash> add_full_hashes_result;
932 ASSERT_TRUE(store_->FinishUpdate(&builder, &add_full_hashes_result));
935 // Reset the store to make sure it re-reads the file.
936 store_.reset(new SafeBrowsingStoreFile());
937 store_->Init(filename_,
938 base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
939 base::Unretained(this)));
941 // |kHash2.prefix| should have dropped.
943 SBAddPrefixes add_prefixes;
944 EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
945 ASSERT_EQ(1U, add_prefixes.size());
946 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
947 EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
949 std::vector<SBAddFullHash> add_hashes;
950 EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
951 ASSERT_EQ(1U, add_hashes.size());
952 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
953 EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
956 #endif
958 } // namespace safe_browsing