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