Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(750)

Unified Diff: services/preferences/persistent_pref_store_impl_unittest.cc

Issue 2743563003: Pref service: add persistent pref store frontend and backend. (Closed)
Patch Set: rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « services/preferences/persistent_pref_store_impl.cc ('k') | services/preferences/public/cpp/BUILD.gn » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: services/preferences/persistent_pref_store_impl_unittest.cc
diff --git a/services/preferences/persistent_pref_store_impl_unittest.cc b/services/preferences/persistent_pref_store_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..806a3428e9b0d8b14c487b5b54fd6db8b71aee5b
--- /dev/null
+++ b/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -0,0 +1,459 @@
+// Copyright 2017 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 "services/preferences/persistent_pref_store_impl.h"
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/prefs/in_memory_pref_store.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/cpp/persistent_pref_store_client.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::WithoutArgs;
+
+namespace prefs {
+namespace {
+
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD1(OnInitializationCompleted, void(bool succeeded));
+};
+
+class PersistentPrefStoreMock : public InMemoryPrefStore {
+ public:
+ MOCK_METHOD0(CommitPendingWrite, void());
+ MOCK_METHOD0(SchedulePendingLossyWrites, void());
+ MOCK_METHOD0(ClearMutableValues, void());
+
+ private:
+ ~PersistentPrefStoreMock() override = default;
+};
+
+class PrefStoreConnectorMock : public mojom::PrefStoreConnector {
+ public:
+ MOCK_METHOD1(Connect, void(const ConnectCallback&));
+};
+
+class InitializationMockPersistentPrefStore : public InMemoryPrefStore {
+ public:
+ bool IsInitializationComplete() const override { return initialized_; }
+
+ void AddObserver(PrefStore::Observer* observer) override {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(PrefStore::Observer* observer) override {
+ observers_.RemoveObserver(observer);
+ }
+
+ void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {
+ DCHECK(!error_delegate);
+ }
+
+ PersistentPrefStore::PrefReadError GetReadError() const override {
+ return read_error_;
+ }
+ bool ReadOnly() const override { return read_only_; }
+
+ void Initialize(bool success,
+ PersistentPrefStore::PrefReadError error,
+ bool read_only) {
+ initialized_ = success;
+ read_error_ = error;
+ read_only_ = read_only;
+ for (auto& observer : observers_) {
+ observer.OnInitializationCompleted(initialized_);
+ }
+ }
+
+ private:
+ ~InitializationMockPersistentPrefStore() override = default;
+
+ PersistentPrefStore::PrefReadError read_error_;
+ bool read_only_ = false;
+ bool initialized_ = false;
+ base::ObserverList<PrefStore::Observer, true> observers_;
+};
+
+class PersistentPrefStoreImplTest : public testing::Test {
+ public:
+ PersistentPrefStoreImplTest() = default;
+
+ // testing::Test:
+ void TearDown() override {
+ pref_store_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ bindings_.CloseAllBindings();
+ backing_pref_store_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateImpl(scoped_refptr<PersistentPrefStore> backing_pref_store) {
+ backing_pref_store_ = base::MakeUnique<PersistentPrefStoreImpl>(
+ std::move(backing_pref_store), nullptr);
+ mojo::Binding<mojom::PersistentPrefStoreConnector> binding(
+ backing_pref_store_.get());
+ pref_store_ = CreateConnection();
+ }
+
+ mojom::PersistentPrefStoreConnectorPtr CreateConnector() {
+ return bindings_.CreateInterfacePtrAndBind(backing_pref_store_.get());
+ }
+
+ scoped_refptr<PersistentPrefStore> CreateConnection() {
+ return make_scoped_refptr(new PersistentPrefStoreClient(
+ bindings_.CreateInterfacePtrAndBind(backing_pref_store_.get())));
+ }
+
+ PersistentPrefStore* pref_store() { return pref_store_.get(); }
+
+ private:
+ base::MessageLoop message_loop_;
+
+ std::unique_ptr<PersistentPrefStoreImpl> backing_pref_store_;
+ mojo::BindingSet<mojom::PersistentPrefStoreConnector> bindings_;
+
+ scoped_refptr<PersistentPrefStore> pref_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImplTest);
+};
+
+TEST_F(PersistentPrefStoreImplTest, InitializationSuccess) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore);
+ CreateImpl(backing_pref_store);
+ backing_pref_store->Initialize(
+ true, PersistentPrefStore::PREF_READ_ERROR_NONE, false);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->GetReadError());
+ EXPECT_FALSE(pref_store()->ReadOnly());
+}
+
+TEST_F(PersistentPrefStoreImplTest, InitializationFailure) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore);
+ CreateImpl(backing_pref_store);
+ backing_pref_store->Initialize(
+ false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+ pref_store()->ReadPrefs());
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+ pref_store()->GetReadError());
+ EXPECT_TRUE(pref_store()->ReadOnly());
+}
+
+class TestReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+ TestReadErrorDelegate(PersistentPrefStore::PrefReadError* storage,
+ const base::Closure& quit)
+ : storage_(storage), quit_(quit) {
+ DCHECK(storage_);
+ DCHECK(quit_);
+ }
+
+ void OnError(PersistentPrefStore::PrefReadError error) override {
+ *storage_ = error;
+ quit_.Run();
+ }
+
+ private:
+ PersistentPrefStore::PrefReadError* const storage_;
+ const base::Closure quit_;
+};
+
+TEST_F(PersistentPrefStoreImplTest, InitializationFailure_AsyncRead) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore);
+ CreateImpl(backing_pref_store);
+ backing_pref_store->Initialize(
+ false, PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, true);
+ PersistentPrefStore::PrefReadError read_error =
+ PersistentPrefStore::PREF_READ_ERROR_NONE;
+ base::RunLoop run_loop;
+ pref_store()->ReadPrefsAsync(
+ new TestReadErrorDelegate(&read_error, run_loop.QuitClosure()));
+ run_loop.Run();
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, read_error);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE,
+ pref_store()->GetReadError());
+ EXPECT_TRUE(pref_store()->ReadOnly());
+}
+
+TEST_F(PersistentPrefStoreImplTest, DelayedInitializationSuccess) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore);
+
+ CreateImpl(backing_pref_store);
+ auto connector = CreateConnector();
+ base::RunLoop run_loop;
+ connector->Connect(base::Bind(
+ [](const base::Closure& quit,
+ PersistentPrefStore::PrefReadError read_error, bool read_only,
+ std::unique_ptr<base::DictionaryValue> local_prefs,
+ mojom::PersistentPrefStorePtr pref_store,
+ mojom::PrefStoreObserverRequest observer_request) {
+ quit.Run();
+ EXPECT_FALSE(read_only);
+ EXPECT_TRUE(local_prefs);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, read_error);
+ },
+ run_loop.QuitClosure()));
+ connector.FlushForTesting();
+ backing_pref_store->Initialize(
+ true, PersistentPrefStore::PREF_READ_ERROR_NONE, false);
+ run_loop.Run();
+}
+
+TEST_F(PersistentPrefStoreImplTest, DelayedInitializationFailure) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore);
+
+ CreateImpl(backing_pref_store);
+ auto connector = CreateConnector();
+ base::RunLoop run_loop;
+ connector->Connect(base::Bind(
+ [](const base::Closure& quit,
+ PersistentPrefStore::PrefReadError read_error, bool read_only,
+ std::unique_ptr<base::DictionaryValue> local_prefs,
+ mojom::PersistentPrefStorePtr pref_store,
+ mojom::PrefStoreObserverRequest observer_request) {
+ quit.Run();
+ EXPECT_TRUE(read_only);
+ EXPECT_FALSE(local_prefs);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
+ read_error);
+ },
+ run_loop.QuitClosure()));
+ connector.FlushForTesting();
+ backing_pref_store->Initialize(
+ false, PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED, true);
+ run_loop.Run();
+}
+
+constexpr char kKey[] = "path.to.key";
+
+TEST_F(PersistentPrefStoreImplTest, InitialValue) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, InitialValueWithoutPathExpansion) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, WriteObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ other_pref_store->ReadPrefs());
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value value("value");
+ pref_store()->SetValueSilently(kKey, value.CreateDeepCopy(), 0);
+
+ PrefStoreObserverMock observer;
+ other_pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(kKey))
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ other_pref_store->RemoveObserver(&observer);
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest,
+ WriteWithoutPathExpansionObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ other_pref_store->ReadPrefs());
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ pref_store()->SetValue(kKey, dict.CreateDeepCopy(), 0);
+
+ PrefStoreObserverMock observer;
+ other_pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(kKey))
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ other_pref_store->RemoveObserver(&observer);
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, RemoveObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ other_pref_store->ReadPrefs());
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+ pref_store()->RemoveValue(kKey, 0);
+
+ // This should be a no-op and shouldn't trigger a notification for the other
+ // client.
+ pref_store()->RemoveValue(kKey, 0);
+
+ PrefStoreObserverMock observer;
+ other_pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(kKey))
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ base::RunLoop().RunUntilIdle();
+ other_pref_store->RemoveObserver(&observer);
+
+ EXPECT_FALSE(other_pref_store->GetValue(kKey, &output));
+}
+
+TEST_F(PersistentPrefStoreImplTest,
+ RemoveWithoutPathExpansionObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ other_pref_store->ReadPrefs());
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+
+ base::Value* mutable_value = nullptr;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ ASSERT_TRUE(pref_store()->GetMutableValue(kKey, &mutable_value));
+ base::DictionaryValue* mutable_dict = nullptr;
+ ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict));
+ mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr);
+ pref_store()->ReportValueChanged(kKey, 0);
+
+ PrefStoreObserverMock observer;
+ other_pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(kKey))
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ other_pref_store->RemoveObserver(&observer);
+
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ const base::DictionaryValue* dict_value = nullptr;
+ ASSERT_TRUE(output->GetAsDictionary(&dict_value));
+ EXPECT_TRUE(dict_value->empty());
+}
+
+TEST_F(PersistentPrefStoreImplTest, CommitPendingWrite) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, CommitPendingWrite())
+ .Times(2)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ pref_store()->CommitPendingWrite();
+ run_loop.Run();
+}
+
+TEST_F(PersistentPrefStoreImplTest, SchedulePendingLossyWrites) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, SchedulePendingLossyWrites())
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ pref_store()->SchedulePendingLossyWrites();
+ run_loop.Run();
+}
+
+TEST_F(PersistentPrefStoreImplTest, ClearMutableValues) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->ReadPrefs());
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, ClearMutableValues())
+ .Times(1)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ pref_store()->ClearMutableValues();
+ run_loop.Run();
+}
+
+} // namespace
+} // namespace prefs
« no previous file with comments | « services/preferences/persistent_pref_store_impl.cc ('k') | services/preferences/public/cpp/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698