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"
8 #include "base/files/scoped_temp_dir.h"
10 #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "testing/platform_test.h"
16 class SafeBrowsingStoreFileTest : public PlatformTest {
18 virtual void SetUp() {
19 PlatformTest::SetUp();
21 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
23 filename_ = temp_dir_.path();
24 filename_ = filename_.AppendASCII("SafeBrowsingTestStore");
26 store_.reset(new SafeBrowsingStoreFile());
27 store_->Init(filename_,
28 base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
29 base::Unretained(this)));
30 corruption_detected_ = false;
32 virtual void TearDown() {
37 PlatformTest::TearDown();
40 void OnCorruptionDetected() {
41 corruption_detected_ = true;
44 base::ScopedTempDir temp_dir_;
45 base::FilePath filename_;
46 scoped_ptr<SafeBrowsingStoreFile> store_;
47 bool corruption_detected_;
50 TEST_STORE(SafeBrowsingStoreFileTest, store_.get(), filename_);
52 // Test that Delete() deletes the temporary store, if present.
53 TEST_F(SafeBrowsingStoreFileTest, DeleteTemp) {
54 const base::FilePath temp_file =
55 SafeBrowsingStoreFile::TemporaryFileForFilename(filename_);
57 EXPECT_FALSE(base::PathExists(filename_));
58 EXPECT_FALSE(base::PathExists(temp_file));
60 // Starting a transaction creates a temporary file.
61 EXPECT_TRUE(store_->BeginUpdate());
62 EXPECT_TRUE(base::PathExists(temp_file));
64 // Pull the rug out from under the existing store, simulating a
66 store_.reset(new SafeBrowsingStoreFile());
67 store_->Init(filename_, base::Closure());
68 EXPECT_FALSE(base::PathExists(filename_));
69 EXPECT_TRUE(base::PathExists(temp_file));
71 // Make sure the temporary file is deleted.
72 EXPECT_TRUE(store_->Delete());
73 EXPECT_FALSE(base::PathExists(filename_));
74 EXPECT_FALSE(base::PathExists(temp_file));
77 // Test basic corruption-handling.
78 TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
79 // Load a store with some data.
80 SafeBrowsingStoreTestStorePrefix(store_.get());
82 // Can successfully open and read the store.
83 std::vector<SBAddFullHash> pending_adds;
84 std::set<SBPrefix> prefix_misses;
85 SBAddPrefixes orig_prefixes;
86 std::vector<SBAddFullHash> orig_hashes;
87 EXPECT_TRUE(store_->BeginUpdate());
88 EXPECT_TRUE(store_->FinishUpdate(pending_adds, prefix_misses,
89 &orig_prefixes, &orig_hashes));
90 EXPECT_GT(orig_prefixes.size(), 0U);
91 EXPECT_GT(orig_hashes.size(), 0U);
92 EXPECT_FALSE(corruption_detected_);
95 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb+"));
96 const long kOffset = 60;
97 EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
98 const int32 kZero = 0;
99 int32 previous = kZero;
100 EXPECT_EQ(fread(&previous, sizeof(previous), 1, file.get()), 1U);
101 EXPECT_NE(previous, kZero);
102 EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
103 EXPECT_EQ(fwrite(&kZero, sizeof(kZero), 1, file.get()), 1U);
106 // Update fails and corruption callback is called.
107 SBAddPrefixes add_prefixes;
108 std::vector<SBAddFullHash> add_hashes;
109 corruption_detected_ = false;
110 EXPECT_TRUE(store_->BeginUpdate());
111 EXPECT_FALSE(store_->FinishUpdate(pending_adds, prefix_misses,
112 &add_prefixes, &add_hashes));
113 EXPECT_TRUE(corruption_detected_);
114 EXPECT_EQ(add_prefixes.size(), 0U);
115 EXPECT_EQ(add_hashes.size(), 0U);
117 // Make it look like there is a lot of add-chunks-seen data.
118 const long kAddChunkCountOffset = 2 * sizeof(int32);
119 const int32 kLargeCount = 1000 * 1000 * 1000;
120 file.reset(file_util::OpenFile(filename_, "rb+"));
121 EXPECT_EQ(fseek(file.get(), kAddChunkCountOffset, SEEK_SET), 0);
122 EXPECT_EQ(fwrite(&kLargeCount, sizeof(kLargeCount), 1, file.get()), 1U);
125 // Detects corruption and fails to even begin the update.
126 corruption_detected_ = false;
127 EXPECT_FALSE(store_->BeginUpdate());
128 EXPECT_TRUE(corruption_detected_);
131 TEST_F(SafeBrowsingStoreFileTest, CheckValidity) {
132 // Empty store is valid.
133 EXPECT_FALSE(base::PathExists(filename_));
134 ASSERT_TRUE(store_->BeginUpdate());
135 EXPECT_FALSE(corruption_detected_);
136 EXPECT_TRUE(store_->CheckValidity());
137 EXPECT_FALSE(corruption_detected_);
138 EXPECT_TRUE(store_->CancelUpdate());
140 // A store with some data is valid.
141 EXPECT_FALSE(base::PathExists(filename_));
142 SafeBrowsingStoreTestStorePrefix(store_.get());
143 EXPECT_TRUE(base::PathExists(filename_));
144 ASSERT_TRUE(store_->BeginUpdate());
145 EXPECT_FALSE(corruption_detected_);
146 EXPECT_TRUE(store_->CheckValidity());
147 EXPECT_FALSE(corruption_detected_);
148 EXPECT_TRUE(store_->CancelUpdate());
151 // Corrupt the payload.
152 TEST_F(SafeBrowsingStoreFileTest, CheckValidityPayload) {
153 SafeBrowsingStoreTestStorePrefix(store_.get());
154 EXPECT_TRUE(base::PathExists(filename_));
156 // 37 is the most random prime number. It's also past the header,
157 // as corrupting the header would fail BeginUpdate() in which case
158 // CheckValidity() cannot be called.
159 const size_t kOffset = 37;
162 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb+"));
163 EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_SET));
164 EXPECT_GE(fputs("hello", file.get()), 0);
166 ASSERT_TRUE(store_->BeginUpdate());
167 EXPECT_FALSE(corruption_detected_);
168 EXPECT_FALSE(store_->CheckValidity());
169 EXPECT_TRUE(corruption_detected_);
170 EXPECT_TRUE(store_->CancelUpdate());
173 // Corrupt the checksum.
174 TEST_F(SafeBrowsingStoreFileTest, CheckValidityChecksum) {
175 SafeBrowsingStoreTestStorePrefix(store_.get());
176 EXPECT_TRUE(base::PathExists(filename_));
178 // An offset from the end of the file which is in the checksum.
179 const int kOffset = -static_cast<int>(sizeof(base::MD5Digest));
182 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb+"));
183 EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_END));
184 EXPECT_GE(fputs("hello", file.get()), 0);
186 ASSERT_TRUE(store_->BeginUpdate());
187 EXPECT_FALSE(corruption_detected_);
188 EXPECT_FALSE(store_->CheckValidity());
189 EXPECT_TRUE(corruption_detected_);
190 EXPECT_TRUE(store_->CancelUpdate());