Separate storage for protected preferences into Protected Preferences file.

Introduces ProtectedPrefStore which delegates to two different backing stores to handle unprotected and protected values.

NOTRY=True
BUG=349158

Review URL: https://codereview.chromium.org/205813002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260387 0039d316-1c4b-4281-b951-d872f2087c98
parent dc87ae44
......@@ -67,7 +67,9 @@ PrefService::~PrefService() {
}
void PrefService::InitFromStorage(bool async) {
if (!async) {
if (user_pref_store_->IsInitializationComplete()) {
read_error_callback_.Run(user_pref_store_->GetReadError());
} else if (!async) {
read_error_callback_.Run(user_pref_store_->ReadPrefs());
} else {
// Guarantee that initialization happens after this function returned.
......
......@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/prefs/persistent_pref_store.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/pref_store.h"
#include "base/strings/string_number_conversions.h"
......@@ -91,6 +92,42 @@ void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
user_prefs->ClearPref(prefs::kPreferenceResetTime);
}
void PrefHashFilter::MigrateValues(PersistentPrefStore* source,
PersistentPrefStore* destination) {
scoped_ptr<PrefHashStoreTransaction> transaction =
pref_hash_store_->BeginTransaction();
for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
it != tracked_paths_.end();
++it) {
const base::Value* source_value = NULL;
if (source->GetValue(it->first, &source_value) &&
!destination->GetValue(it->first, NULL)) {
base::DictionaryValue temp_dictionary;
// Copy the value from |source| into a suitable place for a
// TrackedPreference to act on it.
temp_dictionary.Set(it->first, source_value->DeepCopy());
// Check whether the value is correct according to our MAC. May remove the
// value from |temp_dictionary|.
it->second->EnforceAndReport(&temp_dictionary, transaction.get());
// Now take the value as it appears in |temp_dictionary| and put it in
// |destination|.
scoped_ptr<base::Value> checked_value;
if (temp_dictionary.Remove(it->first, &checked_value))
destination->SetValue(it->first, checked_value.release());
}
source->RemoveValue(it->first);
}
// Order these such that a crash at any point is still recoverable. We assume
// that they are configured such that the writes will occur on worker threads
// in the order that we asked for them.
destination->CommitPendingWrite();
transaction.reset();
// If we crash here, we will just delete the values from |source| in a future
// invocation of MigrateValues.
source->CommitPendingWrite();
}
void PrefHashFilter::Initialize(const PrefStore& pref_store) {
scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
pref_hash_store_->BeginTransaction());
......
......@@ -18,6 +18,7 @@
#include "chrome/browser/prefs/pref_hash_store.h"
#include "chrome/browser/prefs/tracked/tracked_preference.h"
class PersistentPrefStore;
class PrefService;
class PrefStore;
......@@ -83,6 +84,15 @@ class PrefHashFilter : public PrefFilter {
// |pref_store|.
void Initialize(const PrefStore& pref_store);
// Migrates protected values from |source| to |destination|. Values are
// migrated if they are protected according to this filter's configuration,
// the corresponding key has no value in |destination|, and the value in
// |source| is trusted according to this filter's PrefHashStore. Regardless of
// the state of |destination| or the trust status, the protected values will
// be removed from |source|.
void MigrateValues(PersistentPrefStore* source,
PersistentPrefStore* destination);
// PrefFilter implementation.
virtual void FilterOnLoad(base::DictionaryValue* pref_store_contents)
OVERRIDE;
......
......@@ -158,11 +158,24 @@ void ProfilePrefStoreManager::ResetAllPrefHashStores(PrefService* local_state) {
// static
base::Time ProfilePrefStoreManager::GetResetTime(PrefService* pref_service) {
// It's a bit of a coincidence that this (and ClearResetTime) work(s). The
// PrefHashFilter attached to the protected pref store will store the reset
// time directly in the protected pref store without going through the
// SegregatedPrefStore.
// PrefHashFilter::GetResetTime will read the value through the pref service,
// and thus through the SegregatedPrefStore. Even though it's not listed as
// "protected" it will be read from the protected store prefentially to the
// (NULL) value in the unprotected pref store.
return PrefHashFilter::GetResetTime(pref_service);
}
// static
void ProfilePrefStoreManager::ClearResetTime(PrefService* pref_service) {
// PrefHashFilter::ClearResetTime will clear the value through the pref
// service, and thus through the SegregatedPrefStore. Since it's not listed as
// "protected" it will be migrated from the protected store to the unprotected
// pref store before being deleted from the latter.
PrefHashFilter::ClearResetTime(pref_service);
}
......
// Copyright 2014 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/prefs/tracked/segregated_pref_store.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/values.h"
SegregatedPrefStore::AggregatingObserver::AggregatingObserver(
SegregatedPrefStore* outer)
: outer_(outer),
failed_sub_initializations_(0),
successful_sub_initializations_(0) {}
void SegregatedPrefStore::AggregatingObserver::OnPrefValueChanged(
const std::string& key) {
// There is no need to tell clients about changes if they have not yet been
// told about initialization.
if (failed_sub_initializations_ + successful_sub_initializations_ < 2)
return;
FOR_EACH_OBSERVER(
PrefStore::Observer, outer_->observers_, OnPrefValueChanged(key));
}
void SegregatedPrefStore::AggregatingObserver::OnInitializationCompleted(
bool succeeded) {
if (succeeded)
++successful_sub_initializations_;
else
++failed_sub_initializations_;
DCHECK_LE(failed_sub_initializations_ + successful_sub_initializations_, 2);
if (failed_sub_initializations_ + successful_sub_initializations_ == 2) {
if (!outer_->on_initialization_.is_null())
outer_->on_initialization_.Run();
if (successful_sub_initializations_ == 2 && outer_->read_error_delegate_) {
PersistentPrefStore::PrefReadError read_error = outer_->GetReadError();
if (read_error != PersistentPrefStore::PREF_READ_ERROR_NONE)
outer_->read_error_delegate_->OnError(read_error);
}
FOR_EACH_OBSERVER(
PrefStore::Observer,
outer_->observers_,
OnInitializationCompleted(successful_sub_initializations_ == 2));
}
}
SegregatedPrefStore::SegregatedPrefStore(
const scoped_refptr<PersistentPrefStore>& default_pref_store,
const scoped_refptr<PersistentPrefStore>& selected_pref_store,
const std::set<std::string>& selected_pref_names,
const base::Closure& on_initialization)
: default_pref_store_(default_pref_store),
selected_pref_store_(selected_pref_store),
selected_preference_names_(selected_pref_names),
on_initialization_(on_initialization),
aggregating_observer_(this) {
default_pref_store_->AddObserver(&aggregating_observer_);
selected_pref_store_->AddObserver(&aggregating_observer_);
}
void SegregatedPrefStore::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void SegregatedPrefStore::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool SegregatedPrefStore::HasObservers() const {
return observers_.might_have_observers();
}
bool SegregatedPrefStore::IsInitializationComplete() const {
return default_pref_store_->IsInitializationComplete() &&
selected_pref_store_->IsInitializationComplete();
}
bool SegregatedPrefStore::GetValue(const std::string& key,
const base::Value** result) const {
return StoreForKey(key)->GetValue(key, result);
}
void SegregatedPrefStore::SetValue(const std::string& key, base::Value* value) {
StoreForKey(key)->SetValue(key, value);
}
void SegregatedPrefStore::RemoveValue(const std::string& key) {
StoreForKey(key)->RemoveValue(key);
}
bool SegregatedPrefStore::GetMutableValue(const std::string& key,
base::Value** result) {
return StoreForKey(key)->GetMutableValue(key, result);
}
void SegregatedPrefStore::ReportValueChanged(const std::string& key) {
StoreForKey(key)->ReportValueChanged(key);
}
void SegregatedPrefStore::SetValueSilently(const std::string& key,
base::Value* value) {
StoreForKey(key)->SetValueSilently(key, value);
}
bool SegregatedPrefStore::ReadOnly() const {
return selected_pref_store_->ReadOnly() ||
default_pref_store_->ReadOnly();
}
PersistentPrefStore::PrefReadError SegregatedPrefStore::GetReadError() const {
PersistentPrefStore::PrefReadError read_error =
default_pref_store_->GetReadError();
return read_error != PersistentPrefStore::PREF_READ_ERROR_NONE
? read_error
: selected_pref_store_->GetReadError();
}
PersistentPrefStore::PrefReadError SegregatedPrefStore::ReadPrefs() {
PersistentPrefStore::PrefReadError unselected_read_error =
default_pref_store_->ReadPrefs();
PersistentPrefStore::PrefReadError selected_read_error =
selected_pref_store_->ReadPrefs();
return unselected_read_error != PersistentPrefStore::PREF_READ_ERROR_NONE
? unselected_read_error
: selected_read_error;
}
void SegregatedPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
read_error_delegate_.reset(error_delegate);
default_pref_store_->ReadPrefsAsync(NULL);
selected_pref_store_->ReadPrefsAsync(NULL);
}
void SegregatedPrefStore::CommitPendingWrite() {
default_pref_store_->CommitPendingWrite();
selected_pref_store_->CommitPendingWrite();
}
SegregatedPrefStore::~SegregatedPrefStore() {
default_pref_store_->RemoveObserver(&aggregating_observer_);
selected_pref_store_->RemoveObserver(&aggregating_observer_);
}
const PersistentPrefStore*
SegregatedPrefStore::StoreForKey(const std::string& key) const {
if (ContainsKey(selected_preference_names_, key) ||
selected_pref_store_->GetValue(key, NULL)) {
return selected_pref_store_.get();
}
return default_pref_store_.get();
}
PersistentPrefStore* SegregatedPrefStore::StoreForKey(const std::string& key) {
if (ContainsKey(selected_preference_names_, key))
return selected_pref_store_.get();
// Check if this unselected value was previously selected. If so, migrate it
// back to the unselected store.
// It's hard to do this in a single pass at startup because PrefStore does not
// permit us to enumerate its contents.
const base::Value* value = NULL;
if (selected_pref_store_->GetValue(key, &value)) {
scoped_ptr<base::Value> migrated_value(value->DeepCopy());
value = NULL;
default_pref_store_->SetValue(key, migrated_value.release());
default_pref_store_->CommitPendingWrite();
selected_pref_store_->RemoveValue(key);
selected_pref_store_->CommitPendingWrite();
}
return default_pref_store_.get();
}
// Copyright 2014 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.
#ifndef CHROME_BROWSER_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
#define CHROME_BROWSER_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
#include <set>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/prefs/persistent_pref_store.h"
// Provides a unified PersistentPrefStore implementation that splits its storage
// and retrieval between two underlying PersistentPrefStore instances: a set of
// preference names is used to partition the preferences.
class SegregatedPrefStore : public PersistentPrefStore {
public:
// Creates an instance that delegates to |selected_pref_store| for the
// preferences named in |selected_pref_names| and to |default_pref_store|
// for all others. If an unselected preference is present in
// |selected_pref_store| (i.e. because it was previously selected) it will
// be migrated back to |default_pref_store| upon access via a non-const
// method.
// |on_initialization| will be invoked when both stores have been initialized,
// before observers of the combined store are notified.
SegregatedPrefStore(
const scoped_refptr<PersistentPrefStore>& default_pref_store,
const scoped_refptr<PersistentPrefStore>& selected_pref_store,
const std::set<std::string>& selected_pref_names,
const base::Closure& on_initialization);
// PrefStore implementation
virtual void AddObserver(Observer* observer) OVERRIDE;
virtual void RemoveObserver(Observer* observer) OVERRIDE;
virtual bool HasObservers() const OVERRIDE;
virtual bool IsInitializationComplete() const OVERRIDE;
virtual bool GetValue(const std::string& key,
const base::Value** result) const OVERRIDE;
// WriteablePrefStore implementation
virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
virtual void RemoveValue(const std::string& key) OVERRIDE;
// PersistentPrefStore implementation
virtual bool GetMutableValue(const std::string& key,
base::Value** result) OVERRIDE;
virtual void ReportValueChanged(const std::string& key) OVERRIDE;
virtual void SetValueSilently(const std::string& key,
base::Value* value) OVERRIDE;
virtual bool ReadOnly() const OVERRIDE;
virtual PrefReadError GetReadError() const OVERRIDE;
virtual PrefReadError ReadPrefs() OVERRIDE;
virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE;
virtual void CommitPendingWrite() OVERRIDE;
private:
// Aggregates events from the underlying stores and synthesizes external
// events via |on_initialization|, |read_error_delegate_|, and |observers_|.
class AggregatingObserver : public PrefStore::Observer {
public:
explicit AggregatingObserver(SegregatedPrefStore* outer);
// PrefStore::Observer implementation
virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
virtual void OnInitializationCompleted(bool succeeded) OVERRIDE;
private:
SegregatedPrefStore* outer_;
int failed_sub_initializations_;
int successful_sub_initializations_;
DISALLOW_COPY_AND_ASSIGN(AggregatingObserver);
};
virtual ~SegregatedPrefStore();
// Returns |selected_pref_store| if |key| is selected or a value is present
// in |selected_pref_store|. This could happen if |key| was previously
// selected.
const PersistentPrefStore* StoreForKey(const std::string& key) const;
// Returns |selected_pref_store| if |key| is selected. If |key| is
// unselected but has a value in |selected_pref_store|, moves the value to
// |default_pref_store| before returning |default_pref_store|.
PersistentPrefStore* StoreForKey(const std::string& key);
scoped_refptr<PersistentPrefStore> default_pref_store_;
scoped_refptr<PersistentPrefStore> selected_pref_store_;
std::set<std::string> selected_preference_names_;
base::Closure on_initialization_;
scoped_ptr<PersistentPrefStore::ReadErrorDelegate> read_error_delegate_;
ObserverList<PrefStore::Observer, true> observers_;
AggregatingObserver aggregating_observer_;
DISALLOW_COPY_AND_ASSIGN(SegregatedPrefStore);
};
#endif // CHROME_BROWSER_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
// Copyright 2014 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/prefs/tracked/segregated_pref_store.h"
#include <set>
#include <string>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/persistent_pref_store.h"
#include "base/prefs/pref_store_observer_mock.h"
#include "base/prefs/testing_pref_store.h"
#include "base/values.h"
#include "chrome/browser/prefs/tracked/segregated_pref_store.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kSelectedPref[] = "selected_pref";
const char kUnselectedPref[] = "unselected_pref";
const char kValue1[] = "value1";
const char kValue2[] = "value2";
class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
public:
struct Data {
Data(bool invoked_in, PersistentPrefStore::PrefReadError read_error_in)
: invoked(invoked_in), read_error(read_error_in) {}
bool invoked;
PersistentPrefStore::PrefReadError read_error;
};
explicit MockReadErrorDelegate(Data* data) : data_(data) {
DCHECK(data_);
EXPECT_FALSE(data_->invoked);
}
// PersistentPrefStore::ReadErrorDelegate implementation
virtual void OnError(PersistentPrefStore::PrefReadError read_error) OVERRIDE {
EXPECT_FALSE(data_->invoked);
data_->invoked = true;
data_->read_error = read_error;
}
private:
Data* data_;
};
} // namespace
class SegregatedPrefStoreTest : public testing::Test {
public:
SegregatedPrefStoreTest()
: initialization_callback_invoked_(false),
read_error_delegate_data_(false,
PersistentPrefStore::PREF_READ_ERROR_NONE),
read_error_delegate_(
new MockReadErrorDelegate(&read_error_delegate_data_)) {}
virtual void SetUp() OVERRIDE {
selected_store_ = new TestingPrefStore;
default_store_ = new TestingPrefStore;
std::set<std::string> selected_pref_names;
selected_pref_names.insert(kSelectedPref);
segregated_store_ = new SegregatedPrefStore(
default_store_,
selected_store_,
selected_pref_names,
base::Bind(&SegregatedPrefStoreTest::InitializationCallback,
base::Unretained(this)));
segregated_store_->AddObserver(&observer_);
}
virtual void TearDown() OVERRIDE {
segregated_store_->RemoveObserver(&observer_);
}
protected:
scoped_ptr<PersistentPrefStore::ReadErrorDelegate> GetReadErrorDelegate() {
EXPECT_TRUE(read_error_delegate_);
return read_error_delegate_
.PassAs<PersistentPrefStore::ReadErrorDelegate>();
}
PrefStoreObserverMock observer_;
bool initialization_callback_invoked_;
scoped_refptr<TestingPrefStore> default_store_;
scoped_refptr<TestingPrefStore> selected_store_;
scoped_refptr<SegregatedPrefStore> segregated_store_;
MockReadErrorDelegate::Data read_error_delegate_data_;
private:
void InitializationCallback() {
EXPECT_FALSE(observer_.initialized);
EXPECT_FALSE(initialization_callback_invoked_);
initialization_callback_invoked_ = true;
}
scoped_ptr<MockReadErrorDelegate> read_error_delegate_;
};
TEST_F(SegregatedPrefStoreTest, StoreValues) {
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
segregated_store_->ReadPrefs());
// Properly stores new values.
segregated_store_->SetValue(kSelectedPref, new base::StringValue(kValue1));
segregated_store_->SetValue(kUnselectedPref, new base::StringValue(kValue2));
ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
ASSERT_FALSE(selected_store_->committed());
ASSERT_FALSE(default_store_->committed());
segregated_store_->CommitPendingWrite();
ASSERT_TRUE(selected_store_->committed());
ASSERT_TRUE(default_store_->committed());
}
TEST_F(SegregatedPrefStoreTest, ReadValues) {
selected_store_->SetValue(kSelectedPref, new base::StringValue(kValue1));
default_store_->SetValue(kUnselectedPref,
new base::StringValue(kValue2));
// Works properly with values that are already there.
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
segregated_store_->ReadPrefs());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
segregated_store_->GetReadError());
ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
}
TEST_F(SegregatedPrefStoreTest, PreviouslySelected) {
selected_store_->SetValue(kUnselectedPref, new base::StringValue(kValue1));
segregated_store_->ReadPrefs();
// It will read from the selected store.
ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
ASSERT_TRUE(selected_store_->GetValue(kUnselectedPref, NULL));
ASSERT_FALSE(default_store_->GetValue(kUnselectedPref, NULL));
// But when we update the value...
segregated_store_->SetValue(kUnselectedPref, new base::StringValue(kValue2));
// ...it will be migrated.
ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
}
TEST_F(SegregatedPrefStoreTest, Observer) {
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
segregated_store_->ReadPrefs());
EXPECT_TRUE(initialization_callback_invoked_);
EXPECT_TRUE(observer_.initialized);
EXPECT_TRUE(observer_.initialization_success);
EXPECT_TRUE(observer_.changed_keys.empty());
segregated_store_->SetValue(kSelectedPref, new base::StringValue(kValue1));
observer_.VerifyAndResetChangedKey(kSelectedPref);
segregated_store_->SetValue(kUnselectedPref, new base::StringValue(kValue2));
observer_.VerifyAndResetChangedKey(kUnselectedPref);
}
TEST_F(SegregatedPrefStoreTest, SelectedPrefReadError) {
selected_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->ReadPrefs());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->GetReadError());
}
TEST_F(SegregatedPrefStoreTest, UnselectedPrefReadError) {
default_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->ReadPrefs());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->GetReadError());
}
TEST_F(SegregatedPrefStoreTest, BothPrefReadError) {
default_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
selected_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->ReadPrefs());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->GetReadError());
}
TEST_F(SegregatedPrefStoreTest, BothPrefReadErrorAsync) {
default_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
selected_store_->set_read_error(
PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
selected_store_->SetBlockAsyncRead(true);
EXPECT_FALSE(read_error_delegate_data_.invoked);
segregated_store_->ReadPrefsAsync(GetReadErrorDelegate().release());
EXPECT_FALSE(read_error_delegate_data_.invoked);
selected_store_->SetBlockAsyncRead(false);
EXPECT_TRUE(read_error_delegate_data_.invoked);
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->GetReadError());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
segregated_store_->GetReadError());
}
TEST_F(SegregatedPrefStoreTest, IsInitializationComplete) {
EXPECT_FALSE(segregated_store_->IsInitializationComplete());
segregated_store_->ReadPrefs();
EXPECT_TRUE(segregated_store_->IsInitializationComplete());
}
TEST_F(SegregatedPrefStoreTest, IsInitializationCompleteAsync) {
selected_store_->SetBlockAsyncRead(true);
default_store_->SetBlockAsyncRead(true);
EXPECT_FALSE(segregated_store_->IsInitializationComplete());
segregated_store_->ReadPrefsAsync(NULL);
EXPECT_FALSE(segregated_store_->IsInitializationComplete());
selected_store_->SetBlockAsyncRead(false);
EXPECT_FALSE(segregated_store_->IsInitializationComplete());
default_store_->SetBlockAsyncRead(false);
EXPECT_TRUE(segregated_store_->IsInitializationComplete());
}
......@@ -1678,6 +1678,8 @@
'browser/prefs/tracked/pref_hash_calculator_helper_win.cc',
'browser/prefs/tracked/pref_service_hash_store_contents.cc',
'browser/prefs/tracked/pref_service_hash_store_contents.h',
'browser/prefs/tracked/segregated_pref_store.cc',
'browser/prefs/tracked/segregated_pref_store.h',
'browser/prefs/tracked/tracked_atomic_preference.cc',
'browser/prefs/tracked/tracked_atomic_preference.h',
'browser/prefs/tracked/tracked_preference.h',
......
......@@ -1166,6 +1166,7 @@
'browser/prefs/session_startup_pref_unittest.cc',
'browser/prefs/tracked/pref_hash_calculator_helper_win_unittest.cc',
'browser/prefs/tracked/pref_service_hash_store_contents_unittest.cc',
'browser/prefs/tracked/segregated_pref_store_unittest.cc',
'browser/prerender/prerender_history_unittest.cc',
'browser/prerender/prerender_tracker_unittest.cc',
'browser/prerender/prerender_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment