This source file includes following definitions.
- SetUp
- TearDown
- OnCorruptionDetected
- PopulateStore
- ReadStride
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/md5.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace {
const int kAddChunk1 = 1;
const int kAddChunk2 = 3;
const int kAddChunk3 = 5;
const int kAddChunk4 = 7;
const int kSubChunk1 = 2;
const int kSubChunk2 = 4;
const SBFullHash kHash1 = SBFullHashForString("one");
const SBFullHash kHash2 = SBFullHashForString("two");
const SBFullHash kHash3 = SBFullHashForString("three");
const SBFullHash kHash4 = SBFullHashForString("four");
const SBFullHash kHash5 = SBFullHashForString("five");
const SBPrefix kMinSBPrefix = 0u;
const SBPrefix kMaxSBPrefix = ~kMinSBPrefix;
class SafeBrowsingStoreFileTest : public PlatformTest {
public:
virtual void SetUp() {
PlatformTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
filename_ = temp_dir_.path();
filename_ = filename_.AppendASCII("SafeBrowsingTestStore");
store_.reset(new SafeBrowsingStoreFile());
store_->Init(filename_,
base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
base::Unretained(this)));
corruption_detected_ = false;
}
virtual void TearDown() {
if (store_.get())
store_->Delete();
store_.reset();
PlatformTest::TearDown();
}
void OnCorruptionDetected() {
corruption_detected_ = true;
}
void PopulateStore(const base::Time& now) {
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk1);
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->WriteAddHash(kAddChunk1, now, kHash2));
store_->SetSubChunk(kSubChunk1);
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash3));
EXPECT_TRUE(store_->FinishChunk());
EXPECT_FALSE(store_->CheckAddChunk(kSubChunk1));
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
EXPECT_FALSE(store_->CheckSubChunk(kAddChunk1));
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
}
uint32 ReadStride() {
base::ScopedFILE file(base::OpenFile(filename_, "rb"));
const long kOffset = 4 * sizeof(uint32);
EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
uint32 shard_stride = 0;
EXPECT_EQ(fread(&shard_stride, sizeof(shard_stride), 1, file.get()), 1U);
return shard_stride;
}
base::ScopedTempDir temp_dir_;
base::FilePath filename_;
scoped_ptr<SafeBrowsingStoreFile> store_;
bool corruption_detected_;
};
TEST_F(SafeBrowsingStoreFileTest, Empty) {
ASSERT_TRUE(store_->BeginUpdate());
std::vector<int> chunks;
store_->GetAddChunks(&chunks);
EXPECT_TRUE(chunks.empty());
store_->GetSubChunks(&chunks);
EXPECT_TRUE(chunks.empty());
EXPECT_FALSE(store_->CheckAddChunk(0));
EXPECT_FALSE(store_->CheckAddChunk(1));
EXPECT_FALSE(store_->CheckAddChunk(-1));
EXPECT_FALSE(store_->CheckSubChunk(0));
EXPECT_FALSE(store_->CheckSubChunk(1));
EXPECT_FALSE(store_->CheckSubChunk(-1));
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
EXPECT_TRUE(add_full_hashes_result.empty());
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
EXPECT_TRUE(prefixes_result.empty());
}
TEST_F(SafeBrowsingStoreFileTest, StorePrefix) {
const base::Time now = base::Time::Now();
PopulateStore(now);
ASSERT_TRUE(store_->BeginUpdate());
std::vector<int> chunks;
store_->GetAddChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kAddChunk1, chunks[0]);
store_->GetSubChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kSubChunk1, chunks[0]);
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(2U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_EQ(kHash2.prefix, prefixes_result[1]);
ASSERT_EQ(1U, add_full_hashes_result.size());
EXPECT_EQ(kAddChunk1, add_full_hashes_result[0].chunk_id);
EXPECT_EQ(now.ToTimeT(), add_full_hashes_result[0].received);
EXPECT_TRUE(SBFullHashEqual(kHash2, add_full_hashes_result[0].full_hash));
}
ASSERT_TRUE(store_->BeginUpdate());
store_->GetAddChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kAddChunk1, chunks[0]);
store_->GetSubChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kSubChunk1, chunks[0]);
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(2U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_EQ(kHash2.prefix, prefixes_result[1]);
ASSERT_EQ(1U, add_full_hashes_result.size());
EXPECT_EQ(kAddChunk1, add_full_hashes_result[0].chunk_id);
EXPECT_EQ(now.ToTimeT(), add_full_hashes_result[0].received);
EXPECT_TRUE(SBFullHashEqual(kHash2, add_full_hashes_result[0].full_hash));
}
}
TEST_F(SafeBrowsingStoreFileTest, PrefixMinMax) {
const base::Time now = base::Time::Now();
PopulateStore(now);
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk2);
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk2, kMinSBPrefix));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk2, kMaxSBPrefix));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(4U, prefixes_result.size());
EXPECT_EQ(kMinSBPrefix, prefixes_result[0]);
EXPECT_EQ(kHash1.prefix, prefixes_result[1]);
EXPECT_EQ(kHash2.prefix, prefixes_result[2]);
EXPECT_EQ(kMaxSBPrefix, prefixes_result[3]);
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kSubChunk2);
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk2, kAddChunk2, kMinSBPrefix));
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk2, kAddChunk2, kMaxSBPrefix));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(2U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_EQ(kHash2.prefix, prefixes_result[1]);
}
}
TEST_F(SafeBrowsingStoreFileTest, SubKnockout) {
ASSERT_TRUE(store_->BeginUpdate());
const base::Time now = base::Time::Now();
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk1);
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->WriteAddHash(kAddChunk1, now, kHash2));
store_->SetSubChunk(kSubChunk1);
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(1U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_TRUE(add_full_hashes_result.empty());
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk3);
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash3.prefix));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
EXPECT_EQ(1U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_TRUE(add_full_hashes_result.empty());
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk3);
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk3, kHash3.prefix));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(2U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_EQ(kHash3.prefix, prefixes_result[1]);
EXPECT_TRUE(add_full_hashes_result.empty());
}
}
TEST_F(SafeBrowsingStoreFileTest, DeleteChunks) {
ASSERT_TRUE(store_->BeginUpdate());
const base::Time now = base::Time::Now();
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
store_->SetAddChunk(kAddChunk1);
EXPECT_TRUE(store_->BeginChunk());
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->WriteAddHash(kAddChunk1, now, kHash2));
EXPECT_TRUE(store_->FinishChunk());
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk2));
store_->SetAddChunk(kAddChunk2);
EXPECT_TRUE(store_->BeginChunk());
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk2, kHash3.prefix));
EXPECT_TRUE(store_->WriteAddHash(kAddChunk2, now, kHash3));
EXPECT_TRUE(store_->FinishChunk());
EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
store_->SetSubChunk(kSubChunk1);
EXPECT_TRUE(store_->BeginChunk());
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash4.prefix));
EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash4));
EXPECT_TRUE(store_->FinishChunk());
EXPECT_FALSE(store_->CheckSubChunk(kSubChunk2));
store_->SetSubChunk(kSubChunk2);
EXPECT_TRUE(store_->BeginChunk());
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk2, kAddChunk4, kHash5.prefix));
EXPECT_TRUE(store_->WriteSubHash(kSubChunk2, kAddChunk4, kHash5));
EXPECT_TRUE(store_->FinishChunk());
store_->DeleteAddChunk(kAddChunk1);
store_->DeleteSubChunk(kSubChunk1);
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk2));
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
EXPECT_EQ(1U, prefixes_result.size());
EXPECT_EQ(kHash3.prefix, prefixes_result[0]);
EXPECT_EQ(1U, add_full_hashes_result.size());
EXPECT_EQ(kAddChunk2, add_full_hashes_result[0].chunk_id);
EXPECT_EQ(now.ToTimeT(), add_full_hashes_result[0].received);
EXPECT_TRUE(SBFullHashEqual(kHash3, add_full_hashes_result[0].full_hash));
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk2));
EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk2));
store_->DeleteAddChunk(kAddChunk2);
store_->DeleteSubChunk(kSubChunk2);
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk1));
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk2));
EXPECT_FALSE(store_->CheckSubChunk(kSubChunk1));
EXPECT_FALSE(store_->CheckSubChunk(kSubChunk2));
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
EXPECT_TRUE(prefixes_result.empty());
EXPECT_TRUE(add_full_hashes_result.empty());
}
}
TEST_F(SafeBrowsingStoreFileTest, Delete) {
EXPECT_FALSE(base::PathExists(filename_));
EXPECT_TRUE(store_->Delete());
PopulateStore(base::Time::Now());
EXPECT_TRUE(base::PathExists(filename_));
EXPECT_TRUE(store_->Delete());
EXPECT_FALSE(base::PathExists(filename_));
}
TEST_F(SafeBrowsingStoreFileTest, DeleteTemp) {
const base::FilePath temp_file =
SafeBrowsingStoreFile::TemporaryFileForFilename(filename_);
EXPECT_FALSE(base::PathExists(filename_));
EXPECT_FALSE(base::PathExists(temp_file));
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(base::PathExists(temp_file));
store_.reset(new SafeBrowsingStoreFile());
store_->Init(filename_, base::Closure());
EXPECT_FALSE(base::PathExists(filename_));
EXPECT_TRUE(base::PathExists(temp_file));
EXPECT_TRUE(store_->Delete());
EXPECT_FALSE(base::PathExists(filename_));
EXPECT_FALSE(base::PathExists(temp_file));
}
TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
PopulateStore(base::Time::Now());
{
std::vector<SBAddFullHash> pending_adds;
std::vector<SBPrefix> orig_prefixes;
std::vector<SBAddFullHash> orig_hashes;
safe_browsing::PrefixSetBuilder builder;
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->FinishUpdate(pending_adds, &builder, &orig_hashes));
builder.GetPrefixSet()->GetPrefixes(&orig_prefixes);
EXPECT_GT(orig_prefixes.size(), 0U);
EXPECT_GT(orig_hashes.size(), 0U);
EXPECT_FALSE(corruption_detected_);
}
base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
const long kOffset = 60;
EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
const uint32 kZero = 0;
uint32 previous = kZero;
EXPECT_EQ(fread(&previous, sizeof(previous), 1, file.get()), 1U);
EXPECT_NE(previous, kZero);
EXPECT_EQ(fseek(file.get(), kOffset, SEEK_SET), 0);
EXPECT_EQ(fwrite(&kZero, sizeof(kZero), 1, file.get()), 1U);
file.reset();
std::vector<SBAddFullHash> add_hashes;
corruption_detected_ = false;
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(store_->FinishUpdate(pending_adds, &builder, &add_hashes));
EXPECT_TRUE(corruption_detected_);
}
const long kAddChunkCountOffset = 2 * sizeof(int32);
const int32 kLargeCount = 1000 * 1000 * 1000;
file.reset(base::OpenFile(filename_, "rb+"));
EXPECT_EQ(fseek(file.get(), kAddChunkCountOffset, SEEK_SET), 0);
EXPECT_EQ(fwrite(&kLargeCount, sizeof(kLargeCount), 1, file.get()), 1U);
file.reset();
corruption_detected_ = false;
EXPECT_FALSE(store_->BeginUpdate());
EXPECT_TRUE(corruption_detected_);
}
TEST_F(SafeBrowsingStoreFileTest, CheckValidity) {
EXPECT_FALSE(base::PathExists(filename_));
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(corruption_detected_);
EXPECT_TRUE(store_->CheckValidity());
EXPECT_FALSE(corruption_detected_);
EXPECT_TRUE(store_->CancelUpdate());
EXPECT_FALSE(base::PathExists(filename_));
PopulateStore(base::Time::Now());
EXPECT_TRUE(base::PathExists(filename_));
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(corruption_detected_);
EXPECT_TRUE(store_->CheckValidity());
EXPECT_FALSE(corruption_detected_);
EXPECT_TRUE(store_->CancelUpdate());
}
TEST_F(SafeBrowsingStoreFileTest, CheckValidityHeader) {
PopulateStore(base::Time::Now());
EXPECT_TRUE(base::PathExists(filename_));
const size_t kOffset = 37;
{
base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_SET));
EXPECT_GE(fputs("hello", file.get()), 0);
}
ASSERT_FALSE(store_->BeginUpdate());
EXPECT_TRUE(corruption_detected_);
}
TEST_F(SafeBrowsingStoreFileTest, CheckValidityPayload) {
PopulateStore(base::Time::Now());
EXPECT_TRUE(base::PathExists(filename_));
const size_t kOffset = 137;
{
base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_SET));
EXPECT_GE(fputs("hello", file.get()), 0);
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(corruption_detected_);
EXPECT_FALSE(store_->CheckValidity());
EXPECT_TRUE(corruption_detected_);
EXPECT_TRUE(store_->CancelUpdate());
}
TEST_F(SafeBrowsingStoreFileTest, CheckValidityChecksum) {
PopulateStore(base::Time::Now());
EXPECT_TRUE(base::PathExists(filename_));
const int kOffset = -static_cast<int>(sizeof(base::MD5Digest));
{
base::ScopedFILE file(base::OpenFile(filename_, "rb+"));
EXPECT_EQ(0, fseek(file.get(), kOffset, SEEK_END));
EXPECT_GE(fputs("hello", file.get()), 0);
}
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_FALSE(corruption_detected_);
EXPECT_FALSE(store_->CheckValidity());
EXPECT_TRUE(corruption_detected_);
EXPECT_TRUE(store_->CancelUpdate());
}
TEST_F(SafeBrowsingStoreFileTest, GetAddPrefixesAndHashes) {
ASSERT_TRUE(store_->BeginUpdate());
const base::Time now = base::Time::Now();
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(kAddChunk1);
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash1.prefix));
EXPECT_TRUE(store_->WriteAddPrefix(kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->WriteAddHash(kAddChunk1, now, kHash2));
store_->SetSubChunk(kSubChunk1);
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk3, kHash3.prefix));
EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk3, kHash3));
EXPECT_TRUE(store_->FinishChunk());
EXPECT_FALSE(store_->CheckAddChunk(kSubChunk1));
EXPECT_FALSE(store_->CheckAddChunk(kAddChunk3));
EXPECT_FALSE(store_->CheckSubChunk(kAddChunk1));
std::vector<int> chunks;
store_->GetAddChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kAddChunk1, chunks[0]);
store_->GetSubChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kSubChunk1, chunks[0]);
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(std::vector<SBAddFullHash>(),
&builder,
&add_full_hashes_result));
SBAddPrefixes add_prefixes;
EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
ASSERT_EQ(2U, add_prefixes.size());
EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
std::vector<SBAddFullHash> add_hashes;
EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
ASSERT_EQ(1U, add_hashes.size());
EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
}
TEST_F(SafeBrowsingStoreFileTest, Resharding) {
const uint32 kTargetStride = 1 << 29;
const size_t kPrefixesPerChunk = 10000;
uint32 shard_stride = 0;
int chunk_id = 1;
do {
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->BeginChunk());
store_->SetAddChunk(chunk_id);
EXPECT_TRUE(store_->CheckAddChunk(chunk_id));
for (size_t i = 0; i < kPrefixesPerChunk; ++i) {
EXPECT_TRUE(store_->WriteAddPrefix(chunk_id, static_cast<SBPrefix>(i)));
}
EXPECT_TRUE(store_->FinishChunk());
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
SBAddPrefixes add_prefixes;
EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
ASSERT_EQ(chunk_id * kPrefixesPerChunk, add_prefixes.size());
const uint32 new_shard_stride = ReadStride();
EXPECT_TRUE((new_shard_stride == shard_stride) ||
((new_shard_stride << 1) == shard_stride));
shard_stride = new_shard_stride;
++chunk_id;
} while (!shard_stride || shard_stride > kTargetStride);
EXPECT_LT(chunk_id, 20);
while (--chunk_id) {
ASSERT_TRUE(store_->BeginUpdate());
EXPECT_TRUE(store_->CheckAddChunk(chunk_id));
EXPECT_FALSE(store_->CheckAddChunk(chunk_id + 1));
store_->DeleteAddChunk(chunk_id);
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
const uint32 new_shard_stride = ReadStride();
EXPECT_TRUE((new_shard_stride == shard_stride) ||
(new_shard_stride == (shard_stride << 1)));
shard_stride = new_shard_stride;
}
EXPECT_EQ(0u, shard_stride);
}
#if defined(ARCH_CPU_LITTLE_ENDIAN)
TEST_F(SafeBrowsingStoreFileTest, Version7) {
store_.reset();
const char kBasename[] = "FileStoreVersion7";
base::FilePath golden_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &golden_path));
golden_path = golden_path.AppendASCII("SafeBrowsing");
golden_path = golden_path.AppendASCII(kBasename);
ASSERT_TRUE(base::CopyFile(golden_path, filename_));
store_.reset(new SafeBrowsingStoreFile());
store_->Init(filename_,
base::Bind(&SafeBrowsingStoreFileTest::OnCorruptionDetected,
base::Unretained(this)));
SBAddPrefixes add_prefixes;
EXPECT_TRUE(store_->GetAddPrefixes(&add_prefixes));
ASSERT_EQ(2U, add_prefixes.size());
EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
EXPECT_EQ(kHash1.prefix, add_prefixes[0].prefix);
EXPECT_EQ(kAddChunk1, add_prefixes[1].chunk_id);
EXPECT_EQ(kHash2.prefix, add_prefixes[1].prefix);
std::vector<SBAddFullHash> add_hashes;
EXPECT_TRUE(store_->GetAddFullHashes(&add_hashes));
ASSERT_EQ(1U, add_hashes.size());
EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id);
EXPECT_TRUE(SBFullHashEqual(kHash2, add_hashes[0].full_hash));
EXPECT_TRUE(store_->BeginUpdate());
std::vector<int> chunks;
store_->GetAddChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kAddChunk1, chunks[0]);
store_->GetSubChunks(&chunks);
ASSERT_EQ(1U, chunks.size());
EXPECT_EQ(kSubChunk1, chunks[0]);
EXPECT_TRUE(store_->CheckAddChunk(kAddChunk1));
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
store_->SetSubChunk(kSubChunk2);
EXPECT_TRUE(store_->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store_->WriteSubPrefix(kSubChunk1, kAddChunk1, kHash2.prefix));
EXPECT_TRUE(store_->WriteSubHash(kSubChunk1, kAddChunk1, kHash2));
EXPECT_TRUE(store_->FinishChunk());
{
std::vector<SBAddFullHash> pending_adds;
safe_browsing::PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store_->FinishUpdate(pending_adds,
&builder,
&add_full_hashes_result));
std::vector<SBPrefix> prefixes_result;
builder.GetPrefixSet()->GetPrefixes(&prefixes_result);
ASSERT_EQ(1U, prefixes_result.size());
EXPECT_EQ(kHash1.prefix, prefixes_result[0]);
EXPECT_TRUE(add_full_hashes_result.empty());
}
}
#endif
}