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_file.h" 6 7#include "base/callback.h" 8#include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" 9#include "chrome/test/file_test_utils.h" 10#include "testing/gtest/include/gtest/gtest.h" 11#include "testing/platform_test.h" 12 13namespace { 14 15const FilePath::CharType kFolderPrefix[] = 16 FILE_PATH_LITERAL("SafeBrowsingTestStoreFile"); 17 18class SafeBrowsingStoreFileTest : public PlatformTest { 19 public: 20 virtual void SetUp() { 21 PlatformTest::SetUp(); 22 23 FilePath temp_dir; 24 ASSERT_TRUE(file_util::CreateNewTempDirectory(kFolderPrefix, &temp_dir)); 25 26 file_deleter_.reset(new FileAutoDeleter(temp_dir)); 27 28 filename_ = temp_dir; 29 filename_ = filename_.AppendASCII("SafeBrowsingTestStore"); 30 file_util::Delete(filename_, false); 31 32 // Make sure an old temporary file isn't hanging around. 33 const FilePath temp_file = 34 SafeBrowsingStoreFile::TemporaryFileForFilename(filename_); 35 file_util::Delete(temp_file, false); 36 37 store_.reset(new SafeBrowsingStoreFile()); 38 store_->Init(filename_, NULL); 39 } 40 virtual void TearDown() { 41 if (store_.get()) 42 store_->Delete(); 43 store_.reset(); 44 file_deleter_.reset(); 45 46 PlatformTest::TearDown(); 47 } 48 49 void OnCorruptionDetected() { 50 corruption_detected_ = true; 51 } 52 53 scoped_ptr<FileAutoDeleter> file_deleter_; 54 FilePath filename_; 55 scoped_ptr<SafeBrowsingStoreFile> store_; 56 bool corruption_detected_; 57}; 58 59TEST_STORE(SafeBrowsingStoreFileTest, store_.get(), filename_); 60 61// Test that Delete() deletes the temporary store, if present. 62TEST_F(SafeBrowsingStoreFileTest, DeleteTemp) { 63 const FilePath temp_file = 64 SafeBrowsingStoreFile::TemporaryFileForFilename(filename_); 65 66 EXPECT_FALSE(file_util::PathExists(filename_)); 67 EXPECT_FALSE(file_util::PathExists(temp_file)); 68 69 // Starting a transaction creates a temporary file. 70 EXPECT_TRUE(store_->BeginUpdate()); 71 EXPECT_TRUE(file_util::PathExists(temp_file)); 72 73 // Pull the rug out from under the existing store, simulating a 74 // crash. 75 store_.reset(new SafeBrowsingStoreFile()); 76 store_->Init(filename_, NULL); 77 EXPECT_FALSE(file_util::PathExists(filename_)); 78 EXPECT_TRUE(file_util::PathExists(temp_file)); 79 80 // Make sure the temporary file is deleted. 81 EXPECT_TRUE(store_->Delete()); 82 EXPECT_FALSE(file_util::PathExists(filename_)); 83 EXPECT_FALSE(file_util::PathExists(temp_file)); 84} 85 86// Test basic corruption-handling. 87TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) { 88 // Load a store with some data. 89 SafeBrowsingStoreTestStorePrefix(store_.get()); 90 91 SafeBrowsingStoreFile test_store; 92 test_store.Init( 93 filename_, 94 NewCallback(static_cast<SafeBrowsingStoreFileTest*>(this), 95 &SafeBrowsingStoreFileTest::OnCorruptionDetected)); 96 97 corruption_detected_ = false; 98 99 // Can successfully open and read the store. 100 std::vector<SBAddFullHash> pending_adds; 101 std::set<SBPrefix> prefix_misses; 102 std::vector<SBAddPrefix> orig_prefixes; 103 std::vector<SBAddFullHash> orig_hashes; 104 EXPECT_TRUE(test_store.BeginUpdate()); 105 EXPECT_TRUE(test_store.FinishUpdate(pending_adds, prefix_misses, 106 &orig_prefixes, &orig_hashes)); 107 EXPECT_GT(orig_prefixes.size(), 0U); 108 EXPECT_GT(orig_hashes.size(), 0U); 109 EXPECT_FALSE(corruption_detected_); 110 111 // Corrupt the store. 112 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb+")); 113 const long kOffset = 60; 114 EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0); 115 const int32 kZero = 0; 116 int32 previous = kZero; 117 EXPECT_EQ(fread(&previous, sizeof(previous), 1, file.get()), 1U); 118 EXPECT_NE(previous, kZero); 119 EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0); 120 EXPECT_EQ(fwrite(&kZero, sizeof(kZero), 1, file.get()), 1U); 121 file.reset(); 122 123 // Update fails and corruption callback is called. 124 std::vector<SBAddPrefix> add_prefixes; 125 std::vector<SBAddFullHash> add_hashes; 126 corruption_detected_ = false; 127 EXPECT_TRUE(test_store.BeginUpdate()); 128 EXPECT_FALSE(test_store.FinishUpdate(pending_adds, prefix_misses, 129 &add_prefixes, &add_hashes)); 130 EXPECT_TRUE(corruption_detected_); 131 EXPECT_EQ(add_prefixes.size(), 0U); 132 EXPECT_EQ(add_hashes.size(), 0U); 133 134 // Make it look like there is a lot of add-chunks-seen data. 135 const long kAddChunkCountOffset = 2 * sizeof(int32); 136 const int32 kLargeCount = 1000 * 1000 * 1000; 137 file.reset(file_util::OpenFile(filename_, "rb+")); 138 EXPECT_EQ(fseek(file.get(), kAddChunkCountOffset, SEEK_SET), 0); 139 EXPECT_EQ(fwrite(&kLargeCount, sizeof(kLargeCount), 1, file.get()), 1U); 140 file.reset(); 141 142 // Detects corruption and fails to even begin the update. 143 corruption_detected_ = false; 144 EXPECT_FALSE(test_store.BeginUpdate()); 145 EXPECT_TRUE(corruption_detected_); 146} 147 148} // namespace 149