Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: components/safe_browsing_db/prefix_set_unittest.cc

Issue 1420143002: Revert of Move prefix_set and parts of s_b_util into a new component safe_browsing_db. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "components/safe_browsing_db/prefix_set.h"
6
7 #include <algorithm>
8 #include <iterator>
9 #include <set>
10 #include <string>
11
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_file.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/logging.h"
16 #include "base/md5.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/path_service.h"
19 #include "base/rand_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "components/safe_browsing_db/safe_browsing_db_util.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "testing/platform_test.h"
25
26 namespace {
27
28 const SBPrefix kHighBitClear = 1000u * 1000u * 1000u;
29 const SBPrefix kHighBitSet = 3u * 1000u * 1000u * 1000u;
30
31 } // namespace
32
33 namespace safe_browsing {
34
35 class PrefixSetTest : public PlatformTest {
36 protected:
37 // Constants for the v1 format.
38 static const size_t kMagicOffset = 0 * sizeof(uint32);
39 static const size_t kVersionOffset = 1 * sizeof(uint32);
40 static const size_t kIndexSizeOffset = 2 * sizeof(uint32);
41 static const size_t kDeltasSizeOffset = 3 * sizeof(uint32);
42 static const size_t kFullHashesSizeOffset = 4 * sizeof(uint32);
43 static const size_t kPayloadOffset = 5 * sizeof(uint32);
44
45 // Generate a set of random prefixes to share between tests. For
46 // most tests this generation was a large fraction of the test time.
47 //
48 // The set should contain sparse areas where adjacent items are more
49 // than 2^16 apart, and dense areas where adjacent items are less
50 // than 2^16 apart.
51 static void SetUpTestCase() {
52 // Distribute clusters of prefixes.
53 for (size_t i = 0; i < 250; ++i) {
54 // Unsigned for overflow characteristics.
55 const uint32 base = static_cast<uint32>(base::RandUint64());
56 for (size_t j = 0; j < 10; ++j) {
57 const uint32 delta = static_cast<uint32>(base::RandUint64() & 0xFFFF);
58 const SBPrefix prefix = static_cast<SBPrefix>(base + delta);
59 shared_prefixes_.push_back(prefix);
60 }
61 }
62
63 // Lay down a sparsely-distributed layer.
64 const size_t count = shared_prefixes_.size();
65 for (size_t i = 0; i < count; ++i) {
66 const SBPrefix prefix = static_cast<SBPrefix>(base::RandUint64());
67 shared_prefixes_.push_back(prefix);
68 }
69
70 // Sort for use with PrefixSet constructor.
71 std::sort(shared_prefixes_.begin(), shared_prefixes_.end());
72 }
73
74 // Check that all elements of |prefixes| are in |prefix_set|, and
75 // that nearby elements are not (for lack of a more sensible set of
76 // items to check for absence).
77 static void CheckPrefixes(const PrefixSet& prefix_set,
78 const std::vector<SBPrefix> &prefixes) {
79 // The set can generate the prefixes it believes it has, so that's
80 // a good starting point.
81 std::set<SBPrefix> check(prefixes.begin(), prefixes.end());
82 std::vector<SBPrefix> prefixes_copy;
83 prefix_set.GetPrefixes(&prefixes_copy);
84 EXPECT_EQ(prefixes_copy.size(), check.size());
85 EXPECT_TRUE(std::equal(check.begin(), check.end(), prefixes_copy.begin()));
86
87 for (size_t i = 0; i < prefixes.size(); ++i) {
88 EXPECT_TRUE(prefix_set.PrefixExists(prefixes[i]));
89
90 const SBPrefix left_sibling = prefixes[i] - 1;
91 if (check.count(left_sibling) == 0)
92 EXPECT_FALSE(prefix_set.PrefixExists(left_sibling));
93
94 const SBPrefix right_sibling = prefixes[i] + 1;
95 if (check.count(right_sibling) == 0)
96 EXPECT_FALSE(prefix_set.PrefixExists(right_sibling));
97 }
98 }
99
100 // Generate a |PrefixSet| file from |shared_prefixes_|, store it in
101 // a temporary file, and return the filename in |filenamep|.
102 // Returns |true| on success.
103 bool GetPrefixSetFile(base::FilePath* filenamep) {
104 if (!temp_dir_.IsValid() && !temp_dir_.CreateUniqueTempDir())
105 return false;
106
107 base::FilePath filename = temp_dir_.path().AppendASCII("PrefixSetTest");
108
109 PrefixSetBuilder builder(shared_prefixes_);
110 if (!builder.GetPrefixSetNoHashes()->WriteFile(filename))
111 return false;
112
113 *filenamep = filename;
114 return true;
115 }
116
117 // Helper function to read the uint32 value at |offset|, increment it
118 // by |inc|, and write it back in place. |fp| should be opened in
119 // r+ mode.
120 static void IncrementIntAt(FILE* fp, long offset, int inc) {
121 uint32 value = 0;
122
123 ASSERT_NE(-1, fseek(fp, offset, SEEK_SET));
124 ASSERT_EQ(1U, fread(&value, sizeof(value), 1, fp));
125
126 value += inc;
127
128 ASSERT_NE(-1, fseek(fp, offset, SEEK_SET));
129 ASSERT_EQ(1U, fwrite(&value, sizeof(value), 1, fp));
130 }
131
132 // Helper function to re-generated |fp|'s checksum to be correct for
133 // the file's contents. |fp| should be opened in r+ mode.
134 static void CleanChecksum(FILE* fp) {
135 base::MD5Context context;
136 base::MD5Init(&context);
137
138 ASSERT_NE(-1, fseek(fp, 0, SEEK_END));
139 long file_size = ftell(fp);
140
141 using base::MD5Digest;
142 size_t payload_size = static_cast<size_t>(file_size) - sizeof(MD5Digest);
143 size_t digested_size = 0;
144 ASSERT_NE(-1, fseek(fp, 0, SEEK_SET));
145 while (digested_size < payload_size) {
146 char buf[1024];
147 size_t nitems = std::min(payload_size - digested_size, sizeof(buf));
148 ASSERT_EQ(nitems, fread(buf, 1, nitems, fp));
149 base::MD5Update(&context, base::StringPiece(buf, nitems));
150 digested_size += nitems;
151 }
152 ASSERT_EQ(digested_size, payload_size);
153 ASSERT_EQ(static_cast<long>(digested_size), ftell(fp));
154
155 base::MD5Digest new_digest;
156 base::MD5Final(&new_digest, &context);
157 ASSERT_NE(-1, fseek(fp, digested_size, SEEK_SET));
158 ASSERT_EQ(1U, fwrite(&new_digest, sizeof(new_digest), 1, fp));
159 ASSERT_EQ(file_size, ftell(fp));
160 }
161
162 // Open |filename| and increment the uint32 at |offset| by |inc|.
163 // Then re-generate the checksum to account for the new contents.
164 void ModifyAndCleanChecksum(const base::FilePath& filename, long offset,
165 int inc) {
166 int64 size_64;
167 ASSERT_TRUE(base::GetFileSize(filename, &size_64));
168
169 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
170 IncrementIntAt(file.get(), offset, inc);
171 CleanChecksum(file.get());
172 file.reset();
173
174 int64 new_size_64;
175 ASSERT_TRUE(base::GetFileSize(filename, &new_size_64));
176 ASSERT_EQ(new_size_64, size_64);
177 }
178
179 base::FilePath TestFilePath() {
180 base::FilePath path;
181 PathService::Get(base::DIR_SOURCE_ROOT, &path);
182 return path.AppendASCII("components")
183 .AppendASCII("test")
184 .AppendASCII("data")
185 .AppendASCII("SafeBrowsingDb");
186 }
187
188 // Fill |prefixes| with values read from a reference file. The reference file
189 // was generated from a specific |shared_prefixes_|.
190 bool ReadReferencePrefixes(std::vector<SBPrefix>* prefixes) {
191 const char kRefname[] = "PrefixSetRef";
192 base::FilePath ref_path = TestFilePath();
193 ref_path = ref_path.AppendASCII(kRefname);
194
195 base::ScopedFILE file(base::OpenFile(ref_path, "r"));
196 if (!file.get())
197 return false;
198 char buf[1024];
199 while (fgets(buf, sizeof(buf), file.get())) {
200 std::string trimmed;
201 if (base::TRIM_TRAILING !=
202 base::TrimWhitespace(buf, base::TRIM_ALL, &trimmed))
203 return false;
204 unsigned prefix;
205 if (!base::StringToUint(trimmed, &prefix))
206 return false;
207 prefixes->push_back(prefix);
208 }
209 return true;
210 }
211
212 // Tests should not modify this shared resource.
213 static std::vector<SBPrefix> shared_prefixes_;
214
215 base::ScopedTempDir temp_dir_;
216 };
217
218 std::vector<SBPrefix> PrefixSetTest::shared_prefixes_;
219
220 // Test that a small sparse random input works.
221 TEST_F(PrefixSetTest, Baseline) {
222 PrefixSetBuilder builder(shared_prefixes_);
223 CheckPrefixes(*builder.GetPrefixSetNoHashes(), shared_prefixes_);
224 }
225
226 // Test that the empty set doesn't appear to have anything in it.
227 TEST_F(PrefixSetTest, Empty) {
228 const std::vector<SBPrefix> empty;
229 PrefixSetBuilder builder(empty);
230 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSetNoHashes();
231 for (size_t i = 0; i < shared_prefixes_.size(); ++i) {
232 EXPECT_FALSE(prefix_set->PrefixExists(shared_prefixes_[i]));
233 }
234 }
235
236 // Single-element set should work fine.
237 TEST_F(PrefixSetTest, OneElement) {
238 const std::vector<SBPrefix> prefixes(100, 0u);
239 PrefixSetBuilder builder(prefixes);
240 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSetNoHashes();
241 EXPECT_FALSE(prefix_set->PrefixExists(static_cast<SBPrefix>(-1)));
242 EXPECT_TRUE(prefix_set->PrefixExists(prefixes[0]));
243 EXPECT_FALSE(prefix_set->PrefixExists(1u));
244
245 // Check that |GetPrefixes()| returns the same set of prefixes as
246 // was passed in.
247 std::vector<SBPrefix> prefixes_copy;
248 prefix_set->GetPrefixes(&prefixes_copy);
249 EXPECT_EQ(1U, prefixes_copy.size());
250 EXPECT_EQ(prefixes[0], prefixes_copy[0]);
251 }
252
253 // Edges of the 32-bit integer range.
254 TEST_F(PrefixSetTest, IntMinMax) {
255 std::vector<SBPrefix> prefixes;
256
257 // Using bit patterns rather than portable constants because this
258 // really is testing how the entire 32-bit integer range is handled.
259 prefixes.push_back(0x00000000);
260 prefixes.push_back(0x0000FFFF);
261 prefixes.push_back(0x7FFF0000);
262 prefixes.push_back(0x7FFFFFFF);
263 prefixes.push_back(0x80000000);
264 prefixes.push_back(0x8000FFFF);
265 prefixes.push_back(0xFFFF0000);
266 prefixes.push_back(0xFFFFFFFF);
267
268 std::sort(prefixes.begin(), prefixes.end());
269 PrefixSetBuilder builder(prefixes);
270 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSetNoHashes();
271
272 // Check that |GetPrefixes()| returns the same set of prefixes as
273 // was passed in.
274 std::vector<SBPrefix> prefixes_copy;
275 prefix_set->GetPrefixes(&prefixes_copy);
276 ASSERT_EQ(prefixes_copy.size(), prefixes.size());
277 EXPECT_TRUE(std::equal(prefixes.begin(), prefixes.end(),
278 prefixes_copy.begin()));
279 }
280
281 // A range with only large deltas.
282 TEST_F(PrefixSetTest, AllBig) {
283 std::vector<SBPrefix> prefixes;
284
285 const unsigned kDelta = 10 * 1000 * 1000;
286 for (SBPrefix prefix = kHighBitClear;
287 prefix < kHighBitSet; prefix += kDelta) {
288 prefixes.push_back(prefix);
289 }
290
291 std::sort(prefixes.begin(), prefixes.end());
292 PrefixSetBuilder builder(prefixes);
293 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSetNoHashes();
294
295 // Check that |GetPrefixes()| returns the same set of prefixes as
296 // was passed in.
297 std::vector<SBPrefix> prefixes_copy;
298 prefix_set->GetPrefixes(&prefixes_copy);
299 prefixes.erase(std::unique(prefixes.begin(), prefixes.end()), prefixes.end());
300 EXPECT_EQ(prefixes_copy.size(), prefixes.size());
301 EXPECT_TRUE(std::equal(prefixes.begin(), prefixes.end(),
302 prefixes_copy.begin()));
303 }
304
305 // Use artificial inputs to test various edge cases in PrefixExists(). Items
306 // before the lowest item aren't present. Items after the largest item aren't
307 // present. Create a sequence of items with deltas above and below 2^16, and
308 // make sure they're all present. Create a very long sequence with deltas below
309 // 2^16 to test crossing |kMaxRun|.
310 TEST_F(PrefixSetTest, EdgeCases) {
311 std::vector<SBPrefix> prefixes;
312
313 // Put in a high-bit prefix.
314 SBPrefix prefix = kHighBitSet;
315 prefixes.push_back(prefix);
316
317 // Add a sequence with very large deltas.
318 unsigned delta = 100 * 1000 * 1000;
319 for (int i = 0; i < 10; ++i) {
320 prefix += delta;
321 prefixes.push_back(prefix);
322 }
323
324 // Add a sequence with deltas that start out smaller than the
325 // maximum delta, and end up larger. Also include some duplicates.
326 delta = 256 * 256 - 100;
327 for (int i = 0; i < 200; ++i) {
328 prefix += delta;
329 prefixes.push_back(prefix);
330 prefixes.push_back(prefix);
331 delta++;
332 }
333
334 // Add a long sequence with deltas smaller than the maximum delta,
335 // so a new index item will be injected.
336 delta = 256 * 256 - 1;
337 prefix = kHighBitClear - delta * 1000;
338 prefixes.push_back(prefix);
339 for (int i = 0; i < 1000; ++i) {
340 prefix += delta;
341 prefixes.push_back(prefix);
342 delta--;
343 }
344
345 std::sort(prefixes.begin(), prefixes.end());
346 PrefixSetBuilder builder(prefixes);
347 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSetNoHashes();
348
349 // Check that |GetPrefixes()| returns the same set of prefixes as
350 // was passed in.
351 std::vector<SBPrefix> prefixes_copy;
352 prefix_set->GetPrefixes(&prefixes_copy);
353 prefixes.erase(std::unique(prefixes.begin(), prefixes.end()), prefixes.end());
354 EXPECT_EQ(prefixes_copy.size(), prefixes.size());
355 EXPECT_TRUE(std::equal(prefixes.begin(), prefixes.end(),
356 prefixes_copy.begin()));
357
358 // Items before and after the set are not present, and don't crash.
359 EXPECT_FALSE(prefix_set->PrefixExists(kHighBitSet - 100));
360 EXPECT_FALSE(prefix_set->PrefixExists(kHighBitClear + 100));
361
362 // Check that the set correctly flags all of the inputs, and also
363 // check items just above and below the inputs to make sure they
364 // aren't present.
365 for (size_t i = 0; i < prefixes.size(); ++i) {
366 EXPECT_TRUE(prefix_set->PrefixExists(prefixes[i]));
367
368 EXPECT_FALSE(prefix_set->PrefixExists(prefixes[i] - 1));
369 EXPECT_FALSE(prefix_set->PrefixExists(prefixes[i] + 1));
370 }
371 }
372
373 // Test writing a prefix set to disk and reading it back in.
374 TEST_F(PrefixSetTest, ReadWrite) {
375 base::FilePath filename;
376
377 // Write the sample prefix set out, read it back in, and check all
378 // the prefixes. Leaves the path in |filename|.
379 {
380 ASSERT_TRUE(GetPrefixSetFile(&filename));
381 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
382 ASSERT_TRUE(prefix_set.get());
383 CheckPrefixes(*prefix_set, shared_prefixes_);
384 }
385
386 // Test writing and reading a very sparse set containing no deltas.
387 {
388 std::vector<SBPrefix> prefixes;
389 prefixes.push_back(kHighBitClear);
390 prefixes.push_back(kHighBitSet);
391
392 PrefixSetBuilder builder(prefixes);
393 ASSERT_TRUE(builder.GetPrefixSetNoHashes()->WriteFile(filename));
394
395 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
396 ASSERT_TRUE(prefix_set.get());
397 CheckPrefixes(*prefix_set, prefixes);
398 }
399
400 // Test writing and reading an empty set.
401 {
402 std::vector<SBPrefix> prefixes;
403 PrefixSetBuilder builder(prefixes);
404 ASSERT_TRUE(builder.GetPrefixSetNoHashes()->WriteFile(filename));
405
406 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
407 ASSERT_TRUE(prefix_set.get());
408 CheckPrefixes(*prefix_set, prefixes);
409 }
410
411 // Test that full hashes are persisted.
412 {
413 std::vector<SBFullHash> hashes;
414 hashes.push_back(SBFullHashForString("one"));
415 hashes.push_back(SBFullHashForString("two"));
416 hashes.push_back(SBFullHashForString("three"));
417
418 std::vector<SBPrefix> prefixes(shared_prefixes_);
419
420 // Remove any collisions from the prefixes.
421 for (size_t i = 0; i < hashes.size(); ++i) {
422 std::vector<SBPrefix>::iterator iter =
423 std::lower_bound(prefixes.begin(), prefixes.end(), hashes[i].prefix);
424 if (iter != prefixes.end() && *iter == hashes[i].prefix)
425 prefixes.erase(iter);
426 }
427
428 PrefixSetBuilder builder(prefixes);
429 ASSERT_TRUE(builder.GetPrefixSet(hashes)->WriteFile(filename));
430
431 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
432 ASSERT_TRUE(prefix_set.get());
433 CheckPrefixes(*prefix_set, prefixes);
434
435 EXPECT_TRUE(prefix_set->Exists(hashes[0]));
436 EXPECT_TRUE(prefix_set->Exists(hashes[1]));
437 EXPECT_TRUE(prefix_set->Exists(hashes[2]));
438 EXPECT_FALSE(prefix_set->PrefixExists(hashes[0].prefix));
439 EXPECT_FALSE(prefix_set->PrefixExists(hashes[1].prefix));
440 EXPECT_FALSE(prefix_set->PrefixExists(hashes[2].prefix));
441 }
442 }
443
444 // Check that |CleanChecksum()| makes an acceptable checksum.
445 TEST_F(PrefixSetTest, CorruptionHelpers) {
446 base::FilePath filename;
447 ASSERT_TRUE(GetPrefixSetFile(&filename));
448
449 // This will modify data in |index_|, which will fail the digest check.
450 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
451 IncrementIntAt(file.get(), kPayloadOffset, 1);
452 file.reset();
453 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
454 ASSERT_FALSE(prefix_set.get());
455
456 // Fix up the checksum and it will read successfully (though the
457 // data will be wrong).
458 file.reset(base::OpenFile(filename, "r+b"));
459 CleanChecksum(file.get());
460 file.reset();
461 prefix_set = PrefixSet::LoadFile(filename);
462 ASSERT_TRUE(prefix_set.get());
463 }
464
465 // Bad magic is caught by the sanity check.
466 TEST_F(PrefixSetTest, CorruptionMagic) {
467 base::FilePath filename;
468 ASSERT_TRUE(GetPrefixSetFile(&filename));
469
470 ASSERT_NO_FATAL_FAILURE(
471 ModifyAndCleanChecksum(filename, kMagicOffset, 1));
472 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
473 ASSERT_FALSE(prefix_set.get());
474 }
475
476 // Bad version is caught by the sanity check.
477 TEST_F(PrefixSetTest, CorruptionVersion) {
478 base::FilePath filename;
479 ASSERT_TRUE(GetPrefixSetFile(&filename));
480
481 ASSERT_NO_FATAL_FAILURE(
482 ModifyAndCleanChecksum(filename, kVersionOffset, 10));
483 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
484 ASSERT_FALSE(prefix_set.get());
485 }
486
487 // Bad |index_| size is caught by the sanity check.
488 TEST_F(PrefixSetTest, CorruptionIndexSize) {
489 base::FilePath filename;
490 ASSERT_TRUE(GetPrefixSetFile(&filename));
491
492 ASSERT_NO_FATAL_FAILURE(
493 ModifyAndCleanChecksum(filename, kIndexSizeOffset, 1));
494 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
495 ASSERT_FALSE(prefix_set.get());
496 }
497
498 // Bad |deltas_| size is caught by the sanity check.
499 TEST_F(PrefixSetTest, CorruptionDeltasSize) {
500 base::FilePath filename;
501 ASSERT_TRUE(GetPrefixSetFile(&filename));
502
503 ASSERT_NO_FATAL_FAILURE(
504 ModifyAndCleanChecksum(filename, kDeltasSizeOffset, 1));
505 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
506 ASSERT_FALSE(prefix_set.get());
507 }
508
509 // Bad |full_hashes_| size is caught by the sanity check.
510 TEST_F(PrefixSetTest, CorruptionFullHashesSize) {
511 base::FilePath filename;
512 ASSERT_TRUE(GetPrefixSetFile(&filename));
513
514 ASSERT_NO_FATAL_FAILURE(
515 ModifyAndCleanChecksum(filename, kFullHashesSizeOffset, 1));
516 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
517 ASSERT_FALSE(prefix_set.get());
518 }
519
520 // Test that the digest catches corruption in the middle of the file
521 // (in the payload between the header and the digest).
522 TEST_F(PrefixSetTest, CorruptionPayload) {
523 base::FilePath filename;
524 ASSERT_TRUE(GetPrefixSetFile(&filename));
525
526 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
527 ASSERT_NO_FATAL_FAILURE(IncrementIntAt(file.get(), 666, 1));
528 file.reset();
529 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
530 ASSERT_FALSE(prefix_set.get());
531 }
532
533 // Test corruption in the digest itself.
534 TEST_F(PrefixSetTest, CorruptionDigest) {
535 base::FilePath filename;
536 ASSERT_TRUE(GetPrefixSetFile(&filename));
537
538 int64 size_64;
539 ASSERT_TRUE(base::GetFileSize(filename, &size_64));
540 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
541 long digest_offset = static_cast<long>(size_64 - sizeof(base::MD5Digest));
542 ASSERT_NO_FATAL_FAILURE(IncrementIntAt(file.get(), digest_offset, 1));
543 file.reset();
544 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
545 ASSERT_FALSE(prefix_set.get());
546 }
547
548 // Test excess data after the digest (fails the size test).
549 TEST_F(PrefixSetTest, CorruptionExcess) {
550 base::FilePath filename;
551 ASSERT_TRUE(GetPrefixSetFile(&filename));
552
553 // Add some junk to the trunk.
554 base::ScopedFILE file(base::OpenFile(filename, "ab"));
555 const char buf[] = "im in ur base, killing ur d00dz.";
556 ASSERT_EQ(strlen(buf), fwrite(buf, 1, strlen(buf), file.get()));
557 file.reset();
558 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
559 ASSERT_FALSE(prefix_set.get());
560 }
561
562 // Test that files which had 64-bit size_t are discarded.
563 TEST_F(PrefixSetTest, SizeTRecovery) {
564 base::FilePath filename;
565 ASSERT_TRUE(GetPrefixSetFile(&filename));
566
567 // Open the file for rewrite.
568 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
569
570 // Leave existing magic and version.
571 ASSERT_NE(-1, fseek(file.get(), sizeof(uint32) * 2, SEEK_SET));
572
573 // Indicate two index values and two deltas.
574 uint32 val = 2;
575 ASSERT_EQ(sizeof(val), fwrite(&val, 1, sizeof(val), file.get()));
576 ASSERT_EQ(sizeof(val), fwrite(&val, 1, sizeof(val), file.get()));
577
578 // Write two index values with 64-bit "size_t".
579 std::pair<SBPrefix, uint64> item;
580 memset(&item, 0, sizeof(item)); // Includes any padding.
581 item.first = 17;
582 item.second = 0;
583 ASSERT_EQ(sizeof(item), fwrite(&item, 1, sizeof(item), file.get()));
584 item.first = 100042;
585 item.second = 1;
586 ASSERT_EQ(sizeof(item), fwrite(&item, 1, sizeof(item), file.get()));
587
588 // Write two delta values.
589 uint16 delta = 23;
590 ASSERT_EQ(sizeof(delta), fwrite(&delta, 1, sizeof(delta), file.get()));
591 ASSERT_EQ(sizeof(delta), fwrite(&delta, 1, sizeof(delta), file.get()));
592
593 // Leave space for the digest at the end, and regenerate it.
594 base::MD5Digest dummy = { { 0 } };
595 ASSERT_EQ(sizeof(dummy), fwrite(&dummy, 1, sizeof(dummy), file.get()));
596 ASSERT_TRUE(base::TruncateFile(file.get()));
597 CleanChecksum(file.get());
598 file.reset(); // Flush updates.
599
600 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
601 ASSERT_FALSE(prefix_set.get());
602 }
603
604 // Test Exists() against full hashes passed to builder.
605 TEST_F(PrefixSetTest, FullHashBuild) {
606 const SBFullHash kHash1 = SBFullHashForString("one");
607 const SBFullHash kHash2 = SBFullHashForString("two");
608 const SBFullHash kHash3 = SBFullHashForString("three");
609 const SBFullHash kHash4 = SBFullHashForString("four");
610 const SBFullHash kHash5 = SBFullHashForString("five");
611 const SBFullHash kHash6 = SBFullHashForString("six");
612
613 std::vector<SBPrefix> prefixes;
614 prefixes.push_back(kHash1.prefix);
615 prefixes.push_back(kHash2.prefix);
616 std::sort(prefixes.begin(), prefixes.end());
617
618 std::vector<SBFullHash> hashes;
619 hashes.push_back(kHash4);
620 hashes.push_back(kHash5);
621
622 PrefixSetBuilder builder(prefixes);
623 scoped_ptr<const PrefixSet> prefix_set = builder.GetPrefixSet(hashes);
624
625 EXPECT_TRUE(prefix_set->Exists(kHash1));
626 EXPECT_TRUE(prefix_set->Exists(kHash2));
627 EXPECT_FALSE(prefix_set->Exists(kHash3));
628 EXPECT_TRUE(prefix_set->Exists(kHash4));
629 EXPECT_TRUE(prefix_set->Exists(kHash5));
630 EXPECT_FALSE(prefix_set->Exists(kHash6));
631
632 EXPECT_TRUE(prefix_set->PrefixExists(kHash1.prefix));
633 EXPECT_TRUE(prefix_set->PrefixExists(kHash2.prefix));
634 EXPECT_FALSE(prefix_set->PrefixExists(kHash3.prefix));
635 EXPECT_FALSE(prefix_set->PrefixExists(kHash4.prefix));
636 EXPECT_FALSE(prefix_set->PrefixExists(kHash5.prefix));
637 EXPECT_FALSE(prefix_set->PrefixExists(kHash6.prefix));
638 }
639
640 // Test that a version 1 file is discarded on read.
641 TEST_F(PrefixSetTest, ReadSigned) {
642 base::FilePath filename;
643 ASSERT_TRUE(GetPrefixSetFile(&filename));
644
645 // Open the file for rewrite.
646 base::ScopedFILE file(base::OpenFile(filename, "r+b"));
647
648 // Leave existing magic.
649 ASSERT_NE(-1, fseek(file.get(), sizeof(uint32), SEEK_SET));
650
651 // Version 1.
652 uint32 version = 1;
653 ASSERT_EQ(sizeof(version), fwrite(&version, 1, sizeof(version), file.get()));
654
655 // Indicate two index values and two deltas.
656 uint32 val = 2;
657 ASSERT_EQ(sizeof(val), fwrite(&val, 1, sizeof(val), file.get()));
658 ASSERT_EQ(sizeof(val), fwrite(&val, 1, sizeof(val), file.get()));
659
660 std::pair<int32, uint32> item;
661 memset(&item, 0, sizeof(item)); // Includes any padding.
662 item.first = -1000;
663 item.second = 0;
664 ASSERT_EQ(sizeof(item), fwrite(&item, 1, sizeof(item), file.get()));
665 item.first = 1000;
666 item.second = 1;
667 ASSERT_EQ(sizeof(item), fwrite(&item, 1, sizeof(item), file.get()));
668
669 // Write two delta values.
670 uint16 delta = 23;
671 ASSERT_EQ(sizeof(delta), fwrite(&delta, 1, sizeof(delta), file.get()));
672 ASSERT_EQ(sizeof(delta), fwrite(&delta, 1, sizeof(delta), file.get()));
673
674 // Leave space for the digest at the end, and regenerate it.
675 base::MD5Digest dummy = { { 0 } };
676 ASSERT_EQ(sizeof(dummy), fwrite(&dummy, 1, sizeof(dummy), file.get()));
677 ASSERT_TRUE(base::TruncateFile(file.get()));
678 CleanChecksum(file.get());
679 file.reset(); // Flush updates.
680
681 scoped_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
682 ASSERT_FALSE(prefix_set.get());
683 }
684
685 // Test that a golden v2 file is discarded on read. All platforms generating v2
686 // files are little-endian, so there is no point to testing this transition
687 // if/when a big-endian port is added.
688 #if defined(ARCH_CPU_LITTLE_ENDIAN)
689 TEST_F(PrefixSetTest, Version2) {
690 std::vector<SBPrefix> ref_prefixes;
691 ASSERT_TRUE(ReadReferencePrefixes(&ref_prefixes));
692
693 const char kBasename[] = "PrefixSetVersion2";
694 base::FilePath golden_path = TestFilePath();
695 golden_path = golden_path.AppendASCII(kBasename);
696
697 scoped_ptr<const PrefixSet> prefix_set(PrefixSet::LoadFile(golden_path));
698 ASSERT_FALSE(prefix_set.get());
699 }
700 #endif
701
702 // Test that a golden v3 file can be read by the current code. All platforms
703 // generating v3 files are little-endian, so there is no point to testing this
704 // transition if/when a big-endian port is added.
705 #if defined(ARCH_CPU_LITTLE_ENDIAN)
706 TEST_F(PrefixSetTest, Version3) {
707 std::vector<SBPrefix> ref_prefixes;
708 ASSERT_TRUE(ReadReferencePrefixes(&ref_prefixes));
709
710 const char kBasename[] = "PrefixSetVersion3";
711 base::FilePath golden_path = TestFilePath();
712 golden_path = golden_path.AppendASCII(kBasename);
713
714 scoped_ptr<const PrefixSet> prefix_set(PrefixSet::LoadFile(golden_path));
715 ASSERT_TRUE(prefix_set.get());
716 CheckPrefixes(*prefix_set, ref_prefixes);
717
718 const SBFullHash kHash1 = SBFullHashForString("www.evil.com/malware.html");
719 const SBFullHash kHash2 = SBFullHashForString("www.evil.com/phishing.html");
720
721 EXPECT_TRUE(prefix_set->Exists(kHash1));
722 EXPECT_TRUE(prefix_set->Exists(kHash2));
723 EXPECT_FALSE(prefix_set->PrefixExists(kHash1.prefix));
724 EXPECT_FALSE(prefix_set->PrefixExists(kHash2.prefix));
725 }
726 #endif
727
728 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « components/safe_browsing_db/prefix_set.cc ('k') | components/safe_browsing_db/safe_browsing_db_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698