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 SBAddPrefixes orig_prefixes
;
85 std::vector
<SBAddFullHash
> orig_hashes
;
86 EXPECT_TRUE(store_
->BeginUpdate());
87 EXPECT_TRUE(store_
->FinishUpdate(pending_adds
, &orig_prefixes
, &orig_hashes
));
88 EXPECT_GT(orig_prefixes
.size(), 0U);
89 EXPECT_GT(orig_hashes
.size(), 0U);
90 EXPECT_FALSE(corruption_detected_
);
93 file_util::ScopedFILE
file(base::OpenFile(filename_
, "rb+"));
94 const long kOffset
= 60;
95 EXPECT_EQ(fseek(file
.get(), kOffset
, SEEK_SET
), 0);
96 const int32 kZero
= 0;
97 int32 previous
= kZero
;
98 EXPECT_EQ(fread(&previous
, sizeof(previous
), 1, file
.get()), 1U);
99 EXPECT_NE(previous
, kZero
);
100 EXPECT_EQ(fseek(file
.get(), kOffset
, SEEK_SET
), 0);
101 EXPECT_EQ(fwrite(&kZero
, sizeof(kZero
), 1, file
.get()), 1U);
104 // Update fails and corruption callback is called.
105 SBAddPrefixes add_prefixes
;
106 std::vector
<SBAddFullHash
> add_hashes
;
107 corruption_detected_
= false;
108 EXPECT_TRUE(store_
->BeginUpdate());
109 EXPECT_FALSE(store_
->FinishUpdate(pending_adds
, &add_prefixes
, &add_hashes
));
110 EXPECT_TRUE(corruption_detected_
);
111 EXPECT_EQ(add_prefixes
.size(), 0U);
112 EXPECT_EQ(add_hashes
.size(), 0U);
114 // Make it look like there is a lot of add-chunks-seen data.
115 const long kAddChunkCountOffset
= 2 * sizeof(int32
);
116 const int32 kLargeCount
= 1000 * 1000 * 1000;
117 file
.reset(base::OpenFile(filename_
, "rb+"));
118 EXPECT_EQ(fseek(file
.get(), kAddChunkCountOffset
, SEEK_SET
), 0);
119 EXPECT_EQ(fwrite(&kLargeCount
, sizeof(kLargeCount
), 1, file
.get()), 1U);
122 // Detects corruption and fails to even begin the update.
123 corruption_detected_
= false;
124 EXPECT_FALSE(store_
->BeginUpdate());
125 EXPECT_TRUE(corruption_detected_
);
128 TEST_F(SafeBrowsingStoreFileTest
, CheckValidity
) {
129 // Empty store is valid.
130 EXPECT_FALSE(base::PathExists(filename_
));
131 ASSERT_TRUE(store_
->BeginUpdate());
132 EXPECT_FALSE(corruption_detected_
);
133 EXPECT_TRUE(store_
->CheckValidity());
134 EXPECT_FALSE(corruption_detected_
);
135 EXPECT_TRUE(store_
->CancelUpdate());
137 // A store with some data is valid.
138 EXPECT_FALSE(base::PathExists(filename_
));
139 SafeBrowsingStoreTestStorePrefix(store_
.get());
140 EXPECT_TRUE(base::PathExists(filename_
));
141 ASSERT_TRUE(store_
->BeginUpdate());
142 EXPECT_FALSE(corruption_detected_
);
143 EXPECT_TRUE(store_
->CheckValidity());
144 EXPECT_FALSE(corruption_detected_
);
145 EXPECT_TRUE(store_
->CancelUpdate());
148 // Corrupt the payload.
149 TEST_F(SafeBrowsingStoreFileTest
, CheckValidityPayload
) {
150 SafeBrowsingStoreTestStorePrefix(store_
.get());
151 EXPECT_TRUE(base::PathExists(filename_
));
153 // 37 is the most random prime number. It's also past the header,
154 // as corrupting the header would fail BeginUpdate() in which case
155 // CheckValidity() cannot be called.
156 const size_t kOffset
= 37;
159 file_util::ScopedFILE
file(base::OpenFile(filename_
, "rb+"));
160 EXPECT_EQ(0, fseek(file
.get(), kOffset
, SEEK_SET
));
161 EXPECT_GE(fputs("hello", file
.get()), 0);
163 ASSERT_TRUE(store_
->BeginUpdate());
164 EXPECT_FALSE(corruption_detected_
);
165 EXPECT_FALSE(store_
->CheckValidity());
166 EXPECT_TRUE(corruption_detected_
);
167 EXPECT_TRUE(store_
->CancelUpdate());
170 // Corrupt the checksum.
171 TEST_F(SafeBrowsingStoreFileTest
, CheckValidityChecksum
) {
172 SafeBrowsingStoreTestStorePrefix(store_
.get());
173 EXPECT_TRUE(base::PathExists(filename_
));
175 // An offset from the end of the file which is in the checksum.
176 const int kOffset
= -static_cast<int>(sizeof(base::MD5Digest
));
179 file_util::ScopedFILE
file(base::OpenFile(filename_
, "rb+"));
180 EXPECT_EQ(0, fseek(file
.get(), kOffset
, SEEK_END
));
181 EXPECT_GE(fputs("hello", file
.get()), 0);
183 ASSERT_TRUE(store_
->BeginUpdate());
184 EXPECT_FALSE(corruption_detected_
);
185 EXPECT_FALSE(store_
->CheckValidity());
186 EXPECT_TRUE(corruption_detected_
);
187 EXPECT_TRUE(store_
->CancelUpdate());