Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2011 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/bloom_filter.h"
      6 
      7 #include <limits.h>
      8 
      9 #include <set>
     10 #include <vector>
     11 
     12 #include "base/file_util.h"
     13 #include "base/logging.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/path_service.h"
     16 #include "base/rand_util.h"
     17 #include "base/string_util.h"
     18 #include "base/memory/scoped_temp_dir.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace {
     22 
     23 SBPrefix GenHash() {
     24   return static_cast<SBPrefix>(base::RandUint64());
     25 }
     26 
     27 }
     28 
     29 TEST(SafeBrowsingBloomFilter, BloomFilterUse) {
     30   // Use a small number for unit test so it's not slow.
     31   int count = 1000;
     32 
     33   // Build up the bloom filter.
     34   scoped_refptr<BloomFilter> filter(
     35       new BloomFilter(count * BloomFilter::kBloomFilterSizeRatio));
     36 
     37   typedef std::set<SBPrefix> Values;
     38   Values values;
     39   for (int i = 0; i < count; ++i) {
     40     SBPrefix value = GenHash();
     41     values.insert(value);
     42     filter->Insert(value);
     43   }
     44 
     45   // Check serialization works.
     46   char* data_copy = new char[filter->size()];
     47   memcpy(data_copy, filter->data(), filter->size());
     48   scoped_refptr<BloomFilter> filter_copy(
     49       new BloomFilter(data_copy, filter->size(), filter->hash_keys_));
     50 
     51   // Check no false negatives by ensuring that every time we inserted exists.
     52   for (Values::const_iterator i = values.begin(); i != values.end(); ++i)
     53     EXPECT_TRUE(filter_copy->Exists(*i));
     54 
     55   // Check false positive error rate by checking the same number of items that
     56   // we inserted, but of different values, and calculating what percentage are
     57   // "found".
     58   int found_count = 0;
     59   int checked = 0;
     60   while (true) {
     61     SBPrefix value = GenHash();
     62     if (values.count(value))
     63       continue;
     64 
     65     if (filter_copy->Exists(value))
     66       found_count++;
     67 
     68     checked++;
     69     if (checked == count)
     70       break;
     71   }
     72 
     73   // The FP rate should be 1.2%.  Keep a large margin of error because we don't
     74   // want to fail this test because we happened to randomly pick a lot of FPs.
     75   double fp_rate = found_count * 100.0 / count;
     76   CHECK(fp_rate < 5.0);
     77 
     78   VLOG(1) << "For safe browsing bloom filter of size " << count
     79           << ", the FP rate was " << fp_rate << " %";
     80 }
     81 
     82 // Test that we can read and write the bloom filter file.
     83 TEST(SafeBrowsingBloomFilter, BloomFilterFile) {
     84   // Create initial filter.
     85   const int kTestEntries = BloomFilter::kBloomFilterMinSize;
     86   scoped_refptr<BloomFilter> filter_write(
     87       new BloomFilter(kTestEntries * BloomFilter::kBloomFilterSizeRatio));
     88 
     89   for (int i = 0; i < kTestEntries; ++i)
     90     filter_write->Insert(GenHash());
     91 
     92   // Remove any left over test filters and serialize.
     93   ScopedTempDir temp_dir;
     94   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
     95   FilePath filter_path = temp_dir.path().AppendASCII("SafeBrowsingTestFilter");
     96   ASSERT_TRUE(filter_write->WriteFile(filter_path));
     97 
     98   // Create new empty filter and load from disk.
     99   BloomFilter* filter = BloomFilter::LoadFile(filter_path);
    100   ASSERT_TRUE(filter != NULL);
    101   scoped_refptr<BloomFilter> filter_read(filter);
    102 
    103   // Check data consistency.
    104   EXPECT_EQ(filter_write->hash_keys_.size(), filter_read->hash_keys_.size());
    105 
    106   for (size_t i = 0; i < filter_write->hash_keys_.size(); ++i)
    107     EXPECT_EQ(filter_write->hash_keys_[i], filter_read->hash_keys_[i]);
    108 
    109   EXPECT_EQ(filter_write->size(), filter_read->size());
    110 
    111   EXPECT_EQ(0,
    112       memcmp(filter_write->data(), filter_read->data(), filter_read->size()));
    113 }
    114