blob: 02cd335ad5c4272b87e93f151f3512955778aa55 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/incident_reporting/state_store.h"
#include <stdint.h>
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_file_value_serializer.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_simple_task_runner.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/safe_browsing/incident_reporting/incident.h"
#include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/sync_preferences/pref_service_syncable_factory.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/quota_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
#include "base/test/test_reg_util_win.h"
#endif
namespace safe_browsing {
#if defined(OS_WIN)
// A base test fixture that redirects HKCU for testing the platform state store
// backed by the Windows registry to prevent interference with existing Chrome
// installs or other tests.
class PlatformStateStoreTestBase : public ::testing::Test {
protected:
PlatformStateStoreTestBase() {}
void SetUp() override {
::testing::Test::SetUp();
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
}
private:
registry_util::RegistryOverrideManager registry_override_manager_;
DISALLOW_COPY_AND_ASSIGN(PlatformStateStoreTestBase);
};
#else // OS_WIN
using PlatformStateStoreTestBase = ::testing::Test;
#endif // !OS_WIN
// A test fixture with a testing profile that writes its user prefs to a json
// file.
class StateStoreTest : public PlatformStateStoreTestBase {
protected:
struct TestData {
IncidentType type;
const char* key;
uint32_t digest;
};
StateStoreTest()
: profile_(nullptr),
task_runner_(new base::TestSimpleTaskRunner()),
profile_manager_(TestingBrowserProcess::GetGlobal()) {}
void SetUp() override {
PlatformStateStoreTestBase::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(profile_manager_.SetUp());
CreateProfile();
}
void DeleteProfile() {
if (profile_) {
profile_ = nullptr;
profile_manager_.DeleteTestingProfile(kProfileName_);
}
}
// Commits a pending write (which posts a task to task_runner_) and waits for
// it to finish.
void CommitWrite() {
ASSERT_NE(nullptr, profile_);
profile_->GetPrefs()->CommitPendingWrite();
task_runner_->RunUntilIdle();
}
// Removes the safebrowsing.incidents_sent preference from the profile's pref
// store.
void TrimPref() {
ASSERT_EQ(nullptr, profile_);
std::unique_ptr<base::Value> prefs(JSONFileValueDeserializer(GetPrefsPath())
.Deserialize(nullptr, nullptr));
ASSERT_NE(nullptr, prefs.get());
base::DictionaryValue* dict = nullptr;
ASSERT_TRUE(prefs->GetAsDictionary(&dict));
ASSERT_TRUE(dict->Remove(prefs::kSafeBrowsingIncidentsSent, nullptr));
ASSERT_TRUE(JSONFileValueSerializer(GetPrefsPath()).Serialize(*dict));
}
void CreateProfile() {
ASSERT_EQ(nullptr, profile_);
// Create the testing profile with a file-backed user pref store.
sync_preferences::PrefServiceSyncableFactory factory;
factory.SetUserPrefsFile(GetPrefsPath(), task_runner_.get());
user_prefs::PrefRegistrySyncable* pref_registry =
new user_prefs::PrefRegistrySyncable();
RegisterUserProfilePrefs(pref_registry);
profile_ = profile_manager_.CreateTestingProfile(
kProfileName_, factory.CreateSyncable(pref_registry),
base::UTF8ToUTF16(kProfileName_), 0, std::string(),
TestingProfile::TestingFactories(),
/*override_new_profile=*/base::Optional<bool>(false));
}
static const char kProfileName_[];
static const TestData kTestData_[];
content::BrowserTaskEnvironment task_environment_;
TestingProfile* profile_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
private:
base::FilePath GetPrefsPath() {
return temp_dir_.GetPath().AppendASCII("prefs");
}
extensions::QuotaService::ScopedDisablePurgeForTesting
disable_purge_for_testing_;
base::ScopedTempDir temp_dir_;
TestingProfileManager profile_manager_;
DISALLOW_COPY_AND_ASSIGN(StateStoreTest);
};
// static
const char StateStoreTest::kProfileName_[] = "test_profile";
const StateStoreTest::TestData StateStoreTest::kTestData_[] = {
{IncidentType::TRACKED_PREFERENCE, "tp_one", 1},
{IncidentType::TRACKED_PREFERENCE, "tp_two", 2},
{IncidentType::TRACKED_PREFERENCE, "tp_three", 3},
{IncidentType::BINARY_INTEGRITY, "bi", 0},
};
TEST_F(StateStoreTest, MarkAsAndHasBeenReported) {
StateStore state_store(profile_);
for (const auto& data : kTestData_)
ASSERT_FALSE(state_store.HasBeenReported(data.type, data.key, data.digest));
{
StateStore::Transaction transaction(&state_store);
for (const auto& data : kTestData_) {
transaction.MarkAsReported(data.type, data.key, data.digest);
ASSERT_TRUE(
state_store.HasBeenReported(data.type, data.key, data.digest));
}
}
for (const auto& data : kTestData_)
ASSERT_TRUE(state_store.HasBeenReported(data.type, data.key, data.digest));
}
TEST_F(StateStoreTest, ClearForType) {
StateStore state_store(profile_);
{
StateStore::Transaction transaction(&state_store);
for (const auto& data : kTestData_)
transaction.MarkAsReported(data.type, data.key, data.digest);
}
for (const auto& data : kTestData_)
ASSERT_TRUE(state_store.HasBeenReported(data.type, data.key, data.digest));
const IncidentType removed_type = IncidentType::TRACKED_PREFERENCE;
StateStore::Transaction(&state_store).ClearForType(removed_type);
for (const auto& data : kTestData_) {
if (data.type == removed_type) {
ASSERT_FALSE(
state_store.HasBeenReported(data.type, data.key, data.digest));
} else {
ASSERT_TRUE(
state_store.HasBeenReported(data.type, data.key, data.digest));
}
}
}
TEST_F(StateStoreTest, ClearAll) {
StateStore state_store(profile_);
// Write some state to the store.
{
StateStore::Transaction transaction(&state_store);
for (const auto& data : kTestData_)
transaction.MarkAsReported(data.type, data.key, data.digest);
}
StateStore::Transaction(&state_store).ClearAll();
for (const auto& data : kTestData_) {
ASSERT_FALSE(state_store.HasBeenReported(data.type, data.key, data.digest));
}
// Write prefs out to the JsonPrefStore.
CommitWrite();
// Delete the profile.
DeleteProfile();
// Recreate the profile.
CreateProfile();
StateStore store_2(profile_);
for (const auto& data : kTestData_) {
// Verify that the state did not survive through the Platform State Store.
ASSERT_FALSE(store_2.HasBeenReported(data.type, data.key, data.digest));
}
}
TEST_F(StateStoreTest, Persistence) {
// Write some state to the store.
{
StateStore state_store(profile_);
StateStore::Transaction transaction(&state_store);
for (const auto& data : kTestData_)
transaction.MarkAsReported(data.type, data.key, data.digest);
}
// Run tasks to write prefs out to the JsonPrefStore.
CommitWrite();
// Delete the profile.
DeleteProfile();
// Recreate the profile.
CreateProfile();
// Verify that the state survived.
StateStore state_store(profile_);
for (const auto& data : kTestData_)
ASSERT_TRUE(state_store.HasBeenReported(data.type, data.key, data.digest));
}
TEST_F(StateStoreTest, PersistenceWithStoreDelete) {
// Write some state to the store.
{
StateStore state_store(profile_);
StateStore::Transaction transaction(&state_store);
for (const auto& data : kTestData_)
transaction.MarkAsReported(data.type, data.key, data.digest);
}
// Write prefs out to the JsonPrefStore.
CommitWrite();
// Delete the profile.
DeleteProfile();
// Delete the state pref.
TrimPref();
// Recreate the profile.
CreateProfile();
StateStore state_store(profile_);
for (const auto& data : kTestData_) {
#if defined(USE_PLATFORM_STATE_STORE)
// Verify that the state survived.
ASSERT_TRUE(state_store.HasBeenReported(data.type, data.key, data.digest));
#else
// Verify that the state did not survive.
ASSERT_FALSE(state_store.HasBeenReported(data.type, data.key, data.digest));
#endif
}
}
} // namespace safe_browsing