1 // Copyright (c) 2010 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.h"
6 #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h"
7
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace {
11
TEST(SafeBrowsingStoreTest,SBAddPrefixLess)12 TEST(SafeBrowsingStoreTest, SBAddPrefixLess) {
13 // chunk_id then prefix.
14 EXPECT_TRUE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(11, 1)));
15 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(11, 1), SBAddPrefix(10, 1)));
16 EXPECT_TRUE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(10, 2)));
17 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(10, 2), SBAddPrefix(10, 1)));
18
19 // Equal is not less.
20 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(10, 1)));
21 }
22
TEST(SafeBrowsingStoreTest,SBAddPrefixHashLess)23 TEST(SafeBrowsingStoreTest, SBAddPrefixHashLess) {
24 // The first four bytes of SBFullHash can be read as an int32, which
25 // means that byte-ordering issues can come up. To test this, |one|
26 // and |two| differ in the prefix, while |one| and |onetwo| have the
27 // same prefix, but differ in the byte after the prefix.
28 SBFullHash one, onetwo, two;
29 memset(&one, 0, sizeof(one));
30 memset(&onetwo, 0, sizeof(onetwo));
31 memset(&two, 0, sizeof(two));
32 one.prefix = 1;
33 one.full_hash[sizeof(int32)] = 1;
34 onetwo.prefix = 1;
35 onetwo.full_hash[sizeof(int32)] = 2;
36 two.prefix = 2;
37
38 const base::Time now = base::Time::Now();
39
40 // add_id dominates.
41 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, two),
42 SBAddFullHash(11, now, one)));
43 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(11, now, two),
44 SBAddFullHash(10, now, one)));
45
46 // After add_id, prefix.
47 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, one),
48 SBAddFullHash(10, now, two)));
49 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, two),
50 SBAddFullHash(10, now, one)));
51
52 // After prefix, full hash.
53 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, one),
54 SBAddFullHash(10, now, onetwo)));
55 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, onetwo),
56 SBAddFullHash(10, now, one)));
57
58 // Equal is not less-than.
59 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, one),
60 SBAddFullHash(10, now, one)));
61 }
62
TEST(SafeBrowsingStoreTest,SBSubPrefixLess)63 TEST(SafeBrowsingStoreTest, SBSubPrefixLess) {
64 // add_id dominates.
65 EXPECT_TRUE(SBAddPrefixLess(SBSubPrefix(12, 10, 2), SBSubPrefix(9, 11, 1)));
66 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 11, 2), SBSubPrefix(9, 10, 1)));
67
68 // After add_id, prefix.
69 EXPECT_TRUE(SBAddPrefixLess(SBSubPrefix(12, 10, 1), SBSubPrefix(9, 10, 2)));
70 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 10, 2), SBSubPrefix(9, 10, 1)));
71
72 // Equal is not less-than.
73 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 10, 1), SBSubPrefix(12, 10, 1)));
74
75 // chunk_id doesn't matter.
76 }
77
TEST(SafeBrowsingStoreTest,SBSubFullHashLess)78 TEST(SafeBrowsingStoreTest, SBSubFullHashLess) {
79 SBFullHash one, onetwo, two;
80 memset(&one, 0, sizeof(one));
81 memset(&onetwo, 0, sizeof(onetwo));
82 memset(&two, 0, sizeof(two));
83 one.prefix = 1;
84 one.full_hash[sizeof(int32)] = 1;
85 onetwo.prefix = 1;
86 onetwo.full_hash[sizeof(int32)] = 2;
87 two.prefix = 2;
88
89 // add_id dominates.
90 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, two),
91 SBSubFullHash(9, 11, one)));
92 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 11, two),
93 SBSubFullHash(9, 10, one)));
94
95 // After add_id, prefix.
96 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one),
97 SBSubFullHash(9, 10, two)));
98 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, two),
99 SBSubFullHash(9, 10, one)));
100
101 // After prefix, full_hash.
102 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one),
103 SBSubFullHash(9, 10, onetwo)));
104 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, onetwo),
105 SBSubFullHash(9, 10, one)));
106
107 // Equal is not less-than.
108 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one),
109 SBSubFullHash(9, 10, one)));
110 }
111
112 // SBProcessSubs does a lot of iteration, run through empty just to
113 // make sure degenerate cases work.
TEST(SafeBrowsingStoreTest,SBProcessSubsEmpty)114 TEST(SafeBrowsingStoreTest, SBProcessSubsEmpty) {
115 std::vector<SBAddPrefix> add_prefixes;
116 std::vector<SBAddFullHash> add_hashes;
117 std::vector<SBSubPrefix> sub_prefixes;
118 std::vector<SBSubFullHash> sub_hashes;
119
120 const base::hash_set<int32> no_deletions;
121 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
122 no_deletions, no_deletions);
123 EXPECT_TRUE(add_prefixes.empty());
124 EXPECT_TRUE(sub_prefixes.empty());
125 EXPECT_TRUE(add_hashes.empty());
126 EXPECT_TRUE(sub_hashes.empty());
127 }
128
129 // Test that subs knock out adds.
TEST(SafeBrowsingStoreTest,SBProcessSubsKnockout)130 TEST(SafeBrowsingStoreTest, SBProcessSubsKnockout) {
131 const base::Time kNow = base::Time::Now();
132 const SBFullHash kHash1(SBFullHashFromString("one"));
133 const SBFullHash kHash2(SBFullHashFromString("two"));
134 const SBFullHash kHash3(SBFullHashFromString("three"));
135 const int kAddChunk1 = 1; // Use different chunk numbers just in case.
136 const int kSubChunk1 = 2;
137
138 // Construct some full hashes which share prefix with another.
139 SBFullHash kHash1mod1 = kHash1;
140 kHash1mod1.full_hash[sizeof(kHash1mod1.full_hash) - 1] ++;
141 SBFullHash kHash1mod2 = kHash1mod1;
142 kHash1mod2.full_hash[sizeof(kHash1mod2.full_hash) - 1] ++;
143 SBFullHash kHash1mod3 = kHash1mod2;
144 kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++;
145
146 std::vector<SBAddPrefix> add_prefixes;
147 std::vector<SBAddFullHash> add_hashes;
148 std::vector<SBSubPrefix> sub_prefixes;
149 std::vector<SBSubFullHash> sub_hashes;
150
151 // An add with prefix and a couple hashes, plus a sub for the prefix
152 // and a couple sub hashes. The sub should knock all of them out.
153 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix));
154 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1));
155 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1mod1));
156 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash1.prefix));
157 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod2));
158 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod3));
159
160 // An add with no corresponding sub. Both items should be retained.
161 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash2));
162 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash2.prefix));
163
164 // A sub with no corresponding add. Both items should be retained.
165 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3));
166 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix));
167
168 const base::hash_set<int32> no_deletions;
169 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
170 no_deletions, no_deletions);
171
172 EXPECT_EQ(1U, add_prefixes.size());
173 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
174 EXPECT_EQ(kHash2.prefix, add_prefixes[0].prefix);
175
176 EXPECT_EQ(1U, add_hashes.size());
177 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
178 EXPECT_TRUE(SBFullHashEq(kHash2, add_hashes[0].full_hash));
179
180 EXPECT_EQ(1U, sub_prefixes.size());
181 EXPECT_EQ(kSubChunk1, sub_prefixes[0].chunk_id);
182 EXPECT_EQ(kAddChunk1, sub_prefixes[0].add_chunk_id);
183 EXPECT_EQ(kHash3.prefix, sub_prefixes[0].add_prefix);
184
185 EXPECT_EQ(1U, sub_hashes.size());
186 EXPECT_EQ(kSubChunk1, sub_hashes[0].chunk_id);
187 EXPECT_EQ(kAddChunk1, sub_hashes[0].add_chunk_id);
188 EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash));
189 }
190
191 // Test chunk deletions, and ordering of deletions WRT subs knocking
192 // out adds.
TEST(SafeBrowsingStoreTest,SBProcessSubsDeleteChunk)193 TEST(SafeBrowsingStoreTest, SBProcessSubsDeleteChunk) {
194 const base::Time kNow = base::Time::Now();
195 const SBFullHash kHash1(SBFullHashFromString("one"));
196 const SBFullHash kHash2(SBFullHashFromString("two"));
197 const SBFullHash kHash3(SBFullHashFromString("three"));
198 const int kAddChunk1 = 1; // Use different chunk numbers just in case.
199 const int kSubChunk1 = 2;
200
201 // Construct some full hashes which share prefix with another.
202 SBFullHash kHash1mod1 = kHash1;
203 kHash1mod1.full_hash[sizeof(kHash1mod1.full_hash) - 1] ++;
204 SBFullHash kHash1mod2 = kHash1mod1;
205 kHash1mod2.full_hash[sizeof(kHash1mod2.full_hash) - 1] ++;
206 SBFullHash kHash1mod3 = kHash1mod2;
207 kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++;
208
209 std::vector<SBAddPrefix> add_prefixes;
210 std::vector<SBAddFullHash> add_hashes;
211 std::vector<SBSubPrefix> sub_prefixes;
212 std::vector<SBSubFullHash> sub_hashes;
213
214 // An add with prefix and a couple hashes, plus a sub for the prefix
215 // and a couple sub hashes. The sub should knock all of them out.
216 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix));
217 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1));
218 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1mod1));
219 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash1.prefix));
220 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod2));
221 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod3));
222
223 // An add with no corresponding sub. Both items should be retained.
224 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash2));
225 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash2.prefix));
226
227 // A sub with no corresponding add. Both items should be retained.
228 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3));
229 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix));
230
231 const base::hash_set<int32> no_deletions;
232 base::hash_set<int32> add_deletions;
233 add_deletions.insert(kAddChunk1);
234 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
235 add_deletions, no_deletions);
236
237 EXPECT_TRUE(add_prefixes.empty());
238 EXPECT_TRUE(add_hashes.empty());
239
240 EXPECT_EQ(1U, sub_prefixes.size());
241 EXPECT_EQ(kSubChunk1, sub_prefixes[0].chunk_id);
242 EXPECT_EQ(kAddChunk1, sub_prefixes[0].add_chunk_id);
243 EXPECT_EQ(kHash3.prefix, sub_prefixes[0].add_prefix);
244
245 EXPECT_EQ(1U, sub_hashes.size());
246 EXPECT_EQ(kSubChunk1, sub_hashes[0].chunk_id);
247 EXPECT_EQ(kAddChunk1, sub_hashes[0].add_chunk_id);
248 EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash));
249
250 base::hash_set<int32> sub_deletions;
251 sub_deletions.insert(kSubChunk1);
252 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
253 no_deletions, sub_deletions);
254
255 EXPECT_TRUE(add_prefixes.empty());
256 EXPECT_TRUE(add_hashes.empty());
257 EXPECT_TRUE(sub_prefixes.empty());
258 EXPECT_TRUE(sub_hashes.empty());
259 }
260
TEST(SafeBrowsingStoreTest,Y2K38)261 TEST(SafeBrowsingStoreTest, Y2K38) {
262 const base::Time now = base::Time::Now();
263 const base::Time future = now + base::TimeDelta::FromDays(3*365);
264
265 // TODO: Fix file format before 2035.
266 EXPECT_GT(static_cast<int32>(future.ToTimeT()), 0)
267 << " (int32)time_t is running out.";
268 }
269
270 } // namespace
271