OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "services/preferences/user_prefs.h" |
| 6 |
| 7 #include "base/macros.h" |
| 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/run_loop.h" |
| 11 #include "base/values.h" |
| 12 #include "components/prefs/in_memory_pref_store.h" |
| 13 #include "mojo/public/cpp/bindings/binding_set.h" |
| 14 #include "services/preferences/public/cpp/persistent_pref_store_client.h" |
| 15 #include "services/preferences/public/cpp/pref_store_client.h" |
| 16 #include "services/preferences/public/interfaces/preferences.mojom.h" |
| 17 #include "testing/gmock/include/gmock/gmock.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 |
| 20 using testing::Invoke; |
| 21 using testing::WithoutArgs; |
| 22 |
| 23 namespace prefs { |
| 24 namespace { |
| 25 |
| 26 class PrefStoreObserverMock : public PrefStore::Observer { |
| 27 public: |
| 28 MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); |
| 29 MOCK_METHOD1(OnInitializationCompleted, void(bool succeeded)); |
| 30 }; |
| 31 |
| 32 class PersistentPrefStoreMock : public InMemoryPrefStore { |
| 33 public: |
| 34 MOCK_METHOD0(CommitPendingWrite, void()); |
| 35 MOCK_METHOD0(SchedulePendingLossyWrites, void()); |
| 36 MOCK_METHOD0(ClearMutableValues, void()); |
| 37 |
| 38 private: |
| 39 ~PersistentPrefStoreMock() override = default; |
| 40 }; |
| 41 |
| 42 class PrefStoreConnectorMock : public mojom::PrefStoreConnector { |
| 43 public: |
| 44 MOCK_METHOD1(Connect, void(const ConnectCallback&)); |
| 45 }; |
| 46 |
| 47 class InitializationMockPersistentPrefStore : public InMemoryPrefStore { |
| 48 public: |
| 49 bool IsInitializationComplete() const override { return initialized_; } |
| 50 |
| 51 void AddObserver(PrefStore::Observer* observer) override { |
| 52 observers_.AddObserver(observer); |
| 53 } |
| 54 |
| 55 void RemoveObserver(PrefStore::Observer* observer) override { |
| 56 observers_.RemoveObserver(observer); |
| 57 } |
| 58 |
| 59 void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override { |
| 60 DCHECK(!error_delegate); |
| 61 } |
| 62 |
| 63 PersistentPrefStore::PrefReadError GetReadError() const override { |
| 64 return read_error_; |
| 65 } |
| 66 bool ReadOnly() const override { return read_only_; } |
| 67 |
| 68 void Initialize(bool success, |
| 69 PersistentPrefStore::PrefReadError error, |
| 70 bool read_only) { |
| 71 initialized_ = success; |
| 72 read_error_ = error; |
| 73 read_only_ = read_only; |
| 74 for (auto& observer : observers_) { |
| 75 observer.OnInitializationCompleted(initialized_); |
| 76 } |
| 77 } |
| 78 |
| 79 private: |
| 80 ~InitializationMockPersistentPrefStore() override = default; |
| 81 |
| 82 PersistentPrefStore::PrefReadError read_error_; |
| 83 bool read_only_ = false; |
| 84 bool initialized_ = false; |
| 85 base::ObserverList<PrefStore::Observer, true> observers_; |
| 86 }; |
| 87 |
| 88 class UserPrefsTest : public testing::Test { |
| 89 public: |
| 90 UserPrefsTest() = default; |
| 91 |
| 92 // testing::Test: |
| 93 void TearDown() override { |
| 94 pref_store_ = nullptr; |
| 95 base::RunLoop().RunUntilIdle(); |
| 96 bindings_.CloseAllBindings(); |
| 97 user_prefs_.reset(); |
| 98 base::RunLoop().RunUntilIdle(); |
| 99 } |
| 100 |
| 101 void CreateUserPrefs(scoped_refptr<PersistentPrefStore> backing_pref_store) { |
| 102 user_prefs_ = |
| 103 base::MakeUnique<UserPrefs>(std::move(backing_pref_store), nullptr); |
| 104 mojo::Binding<mojom::PersistentPrefStoreConnector> binding( |
| 105 user_prefs_.get()); |
| 106 pref_store_ = CreateConnection(); |
| 107 } |
| 108 |
| 109 mojom::PersistentPrefStoreConnectorPtr CreateConnector() { |
| 110 return bindings_.CreateInterfacePtrAndBind(user_prefs_.get()); |
| 111 } |
| 112 |
| 113 scoped_refptr<PersistentPrefStore> CreateConnection() { |
| 114 return make_scoped_refptr(new PersistentPrefStoreClient( |
| 115 bindings_.CreateInterfacePtrAndBind(user_prefs_.get()))); |
| 116 } |
| 117 |
| 118 PersistentPrefStore* pref_store() { return pref_store_.get(); } |
| 119 |
| 120 private: |
| 121 base::MessageLoop message_loop_; |
| 122 |
| 123 std::unique_ptr<UserPrefs> user_prefs_; |
| 124 mojo::BindingSet<mojom::PersistentPrefStoreConnector> bindings_; |
| 125 |
| 126 scoped_refptr<PersistentPrefStore> pref_store_; |
| 127 |
| 128 DISALLOW_COPY_AND_ASSIGN(UserPrefsTest); |
| 129 }; |
| 130 |
| 131 TEST_F(UserPrefsTest, InitializationSuccess) { |
| 132 auto backing_pref_store = |
| 133 make_scoped_refptr(new InitializationMockPersistentPrefStore); |
| 134 CreateUserPrefs(backing_pref_store); |
| 135 backing_pref_store->Initialize( |
| 136 true, PersistentPrefStore::PREF_READ_ERROR_NONE, false); |
| 137 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 138 pref_store()->ReadPrefs()); |
| 139 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 140 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 141 pref_store()->GetReadError()); |
| 142 EXPECT_FALSE(pref_store()->ReadOnly()); |
| 143 } |
| 144 |
| 145 TEST_F(UserPrefsTest, InitializationFailure) { |
| 146 auto backing_pref_store = |
| 147 make_scoped_refptr(new InitializationMockPersistentPrefStore); |
| 148 CreateUserPrefs(backing_pref_store); |
| 149 backing_pref_store->Initialize( |
| 150 false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true); |
| 151 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, |
| 152 pref_store()->ReadPrefs()); |
| 153 EXPECT_FALSE(pref_store()->IsInitializationComplete()); |
| 154 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, |
| 155 pref_store()->GetReadError()); |
| 156 EXPECT_TRUE(pref_store()->ReadOnly()); |
| 157 } |
| 158 |
| 159 class TestReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate { |
| 160 public: |
| 161 TestReadErrorDelegate(PersistentPrefStore::PrefReadError* storage, |
| 162 const base::Closure& quit) |
| 163 : storage_(storage), quit_(quit) { |
| 164 DCHECK(storage_); |
| 165 DCHECK(quit_); |
| 166 } |
| 167 |
| 168 void OnError(PersistentPrefStore::PrefReadError error) override { |
| 169 *storage_ = error; |
| 170 quit_.Run(); |
| 171 } |
| 172 |
| 173 private: |
| 174 PersistentPrefStore::PrefReadError* const storage_; |
| 175 const base::Closure quit_; |
| 176 }; |
| 177 |
| 178 TEST_F(UserPrefsTest, InitializationFailure_AsyncRead) { |
| 179 auto backing_pref_store = |
| 180 make_scoped_refptr(new InitializationMockPersistentPrefStore); |
| 181 CreateUserPrefs(backing_pref_store); |
| 182 backing_pref_store->Initialize( |
| 183 false, PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, true); |
| 184 PersistentPrefStore::PrefReadError read_error = |
| 185 PersistentPrefStore::PREF_READ_ERROR_NONE; |
| 186 base::RunLoop run_loop; |
| 187 pref_store()->ReadPrefsAsync( |
| 188 new TestReadErrorDelegate(&read_error, run_loop.QuitClosure())); |
| 189 run_loop.Run(); |
| 190 EXPECT_FALSE(pref_store()->IsInitializationComplete()); |
| 191 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, read_error); |
| 192 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, |
| 193 pref_store()->GetReadError()); |
| 194 EXPECT_TRUE(pref_store()->ReadOnly()); |
| 195 } |
| 196 |
| 197 TEST_F(UserPrefsTest, DelayedInitializationSuccess) { |
| 198 auto backing_pref_store = |
| 199 make_scoped_refptr(new InitializationMockPersistentPrefStore); |
| 200 |
| 201 CreateUserPrefs(backing_pref_store); |
| 202 auto connector = CreateConnector(); |
| 203 base::RunLoop run_loop; |
| 204 connector->Connect(base::Bind( |
| 205 [](const base::Closure& quit, |
| 206 PersistentPrefStore::PrefReadError read_error, bool read_only, |
| 207 std::unique_ptr<base::DictionaryValue> local_prefs, |
| 208 mojom::PersistentPrefStorePtr pref_store, |
| 209 mojom::PrefStoreObserverRequest observer_request) { |
| 210 quit.Run(); |
| 211 EXPECT_FALSE(read_only); |
| 212 EXPECT_TRUE(local_prefs); |
| 213 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, read_error); |
| 214 }, |
| 215 run_loop.QuitClosure())); |
| 216 connector.FlushForTesting(); |
| 217 backing_pref_store->Initialize( |
| 218 true, PersistentPrefStore::PREF_READ_ERROR_NONE, false); |
| 219 run_loop.Run(); |
| 220 } |
| 221 |
| 222 TEST_F(UserPrefsTest, DelayedInitializationFailure) { |
| 223 auto backing_pref_store = |
| 224 make_scoped_refptr(new InitializationMockPersistentPrefStore); |
| 225 |
| 226 CreateUserPrefs(backing_pref_store); |
| 227 auto connector = CreateConnector(); |
| 228 base::RunLoop run_loop; |
| 229 connector->Connect(base::Bind( |
| 230 [](const base::Closure& quit, |
| 231 PersistentPrefStore::PrefReadError read_error, bool read_only, |
| 232 std::unique_ptr<base::DictionaryValue> local_prefs, |
| 233 mojom::PersistentPrefStorePtr pref_store, |
| 234 mojom::PrefStoreObserverRequest observer_request) { |
| 235 quit.Run(); |
| 236 EXPECT_TRUE(read_only); |
| 237 EXPECT_FALSE(local_prefs); |
| 238 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED, |
| 239 read_error); |
| 240 }, |
| 241 run_loop.QuitClosure())); |
| 242 connector.FlushForTesting(); |
| 243 backing_pref_store->Initialize( |
| 244 false, PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED, true); |
| 245 run_loop.Run(); |
| 246 } |
| 247 |
| 248 constexpr char kKey[] = "path.to.key"; |
| 249 |
| 250 TEST_F(UserPrefsTest, InitialValue) { |
| 251 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 252 const base::Value value("value"); |
| 253 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); |
| 254 CreateUserPrefs(backing_pref_store); |
| 255 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 256 pref_store()->ReadPrefs()); |
| 257 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 258 const base::Value* output = nullptr; |
| 259 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); |
| 260 EXPECT_TRUE(value.Equals(output)); |
| 261 } |
| 262 |
| 263 TEST_F(UserPrefsTest, InitialValueWithoutPathExpansion) { |
| 264 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 265 base::DictionaryValue dict; |
| 266 dict.SetStringWithoutPathExpansion(kKey, "value"); |
| 267 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0); |
| 268 CreateUserPrefs(backing_pref_store); |
| 269 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 270 pref_store()->ReadPrefs()); |
| 271 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 272 const base::Value* output = nullptr; |
| 273 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); |
| 274 EXPECT_TRUE(dict.Equals(output)); |
| 275 } |
| 276 |
| 277 TEST_F(UserPrefsTest, WriteObservedByOtherClient) { |
| 278 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 279 CreateUserPrefs(backing_pref_store); |
| 280 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 281 pref_store()->ReadPrefs()); |
| 282 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 283 |
| 284 auto other_pref_store = CreateConnection(); |
| 285 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 286 other_pref_store->ReadPrefs()); |
| 287 EXPECT_TRUE(other_pref_store->IsInitializationComplete()); |
| 288 |
| 289 const base::Value value("value"); |
| 290 pref_store()->SetValueSilently(kKey, value.CreateDeepCopy(), 0); |
| 291 |
| 292 PrefStoreObserverMock observer; |
| 293 other_pref_store->AddObserver(&observer); |
| 294 base::RunLoop run_loop; |
| 295 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) |
| 296 .Times(1) |
| 297 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 298 run_loop.Run(); |
| 299 other_pref_store->RemoveObserver(&observer); |
| 300 |
| 301 const base::Value* output = nullptr; |
| 302 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output)); |
| 303 EXPECT_TRUE(value.Equals(output)); |
| 304 } |
| 305 |
| 306 TEST_F(UserPrefsTest, WriteWithoutPathExpansionObservedByOtherClient) { |
| 307 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 308 CreateUserPrefs(backing_pref_store); |
| 309 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 310 pref_store()->ReadPrefs()); |
| 311 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 312 |
| 313 auto other_pref_store = CreateConnection(); |
| 314 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 315 other_pref_store->ReadPrefs()); |
| 316 EXPECT_TRUE(other_pref_store->IsInitializationComplete()); |
| 317 |
| 318 base::DictionaryValue dict; |
| 319 dict.SetStringWithoutPathExpansion(kKey, "value"); |
| 320 pref_store()->SetValue(kKey, dict.CreateDeepCopy(), 0); |
| 321 |
| 322 PrefStoreObserverMock observer; |
| 323 other_pref_store->AddObserver(&observer); |
| 324 base::RunLoop run_loop; |
| 325 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) |
| 326 .Times(1) |
| 327 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 328 run_loop.Run(); |
| 329 other_pref_store->RemoveObserver(&observer); |
| 330 |
| 331 const base::Value* output = nullptr; |
| 332 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output)); |
| 333 EXPECT_TRUE(dict.Equals(output)); |
| 334 } |
| 335 |
| 336 TEST_F(UserPrefsTest, RemoveObservedByOtherClient) { |
| 337 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 338 const base::Value value("value"); |
| 339 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); |
| 340 CreateUserPrefs(backing_pref_store); |
| 341 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 342 pref_store()->ReadPrefs()); |
| 343 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 344 |
| 345 auto other_pref_store = CreateConnection(); |
| 346 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 347 other_pref_store->ReadPrefs()); |
| 348 EXPECT_TRUE(other_pref_store->IsInitializationComplete()); |
| 349 |
| 350 const base::Value* output = nullptr; |
| 351 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output)); |
| 352 EXPECT_TRUE(value.Equals(output)); |
| 353 pref_store()->RemoveValue(kKey, 0); |
| 354 |
| 355 // This should be a no-op and shouldn't trigger a notification for the other |
| 356 // client. |
| 357 pref_store()->RemoveValue(kKey, 0); |
| 358 |
| 359 PrefStoreObserverMock observer; |
| 360 other_pref_store->AddObserver(&observer); |
| 361 base::RunLoop run_loop; |
| 362 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) |
| 363 .Times(1) |
| 364 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 365 run_loop.Run(); |
| 366 base::RunLoop().RunUntilIdle(); |
| 367 other_pref_store->RemoveObserver(&observer); |
| 368 |
| 369 EXPECT_FALSE(other_pref_store->GetValue(kKey, &output)); |
| 370 } |
| 371 |
| 372 TEST_F(UserPrefsTest, RemoveWithoutPathExpansionObservedByOtherClient) { |
| 373 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore()); |
| 374 base::DictionaryValue dict; |
| 375 dict.SetStringWithoutPathExpansion(kKey, "value"); |
| 376 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0); |
| 377 CreateUserPrefs(backing_pref_store); |
| 378 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 379 pref_store()->ReadPrefs()); |
| 380 EXPECT_TRUE(pref_store()->IsInitializationComplete()); |
| 381 |
| 382 auto other_pref_store = CreateConnection(); |
| 383 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 384 other_pref_store->ReadPrefs()); |
| 385 EXPECT_TRUE(other_pref_store->IsInitializationComplete()); |
| 386 |
| 387 const base::Value* output = nullptr; |
| 388 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output)); |
| 389 EXPECT_TRUE(dict.Equals(output)); |
| 390 |
| 391 base::Value* mutable_value = nullptr; |
| 392 dict.SetStringWithoutPathExpansion(kKey, "value"); |
| 393 ASSERT_TRUE(pref_store()->GetMutableValue(kKey, &mutable_value)); |
| 394 base::DictionaryValue* mutable_dict = nullptr; |
| 395 ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict)); |
| 396 mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr); |
| 397 pref_store()->ReportValueChanged(kKey, 0); |
| 398 |
| 399 PrefStoreObserverMock observer; |
| 400 other_pref_store->AddObserver(&observer); |
| 401 base::RunLoop run_loop; |
| 402 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) |
| 403 .Times(1) |
| 404 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 405 run_loop.Run(); |
| 406 other_pref_store->RemoveObserver(&observer); |
| 407 |
| 408 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output)); |
| 409 const base::DictionaryValue* dict_value = nullptr; |
| 410 ASSERT_TRUE(output->GetAsDictionary(&dict_value)); |
| 411 EXPECT_TRUE(dict_value->empty()); |
| 412 } |
| 413 |
| 414 TEST_F(UserPrefsTest, CommitPendingWrite) { |
| 415 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock); |
| 416 CreateUserPrefs(backing_store); |
| 417 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 418 pref_store()->ReadPrefs()); |
| 419 base::RunLoop run_loop; |
| 420 EXPECT_CALL(*backing_store, CommitPendingWrite()) |
| 421 .Times(2) |
| 422 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 423 pref_store()->CommitPendingWrite(); |
| 424 run_loop.Run(); |
| 425 } |
| 426 |
| 427 TEST_F(UserPrefsTest, SchedulePendingLossyWrites) { |
| 428 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock); |
| 429 CreateUserPrefs(backing_store); |
| 430 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 431 pref_store()->ReadPrefs()); |
| 432 base::RunLoop run_loop; |
| 433 EXPECT_CALL(*backing_store, SchedulePendingLossyWrites()) |
| 434 .Times(1) |
| 435 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 436 EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1); |
| 437 pref_store()->SchedulePendingLossyWrites(); |
| 438 run_loop.Run(); |
| 439 } |
| 440 |
| 441 TEST_F(UserPrefsTest, ClearMutableValues) { |
| 442 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock); |
| 443 CreateUserPrefs(backing_store); |
| 444 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
| 445 pref_store()->ReadPrefs()); |
| 446 base::RunLoop run_loop; |
| 447 EXPECT_CALL(*backing_store, ClearMutableValues()) |
| 448 .Times(1) |
| 449 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); |
| 450 EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1); |
| 451 pref_store()->ClearMutableValues(); |
| 452 run_loop.Run(); |
| 453 } |
| 454 |
| 455 } // namespace |
| 456 } // namespace prefs |
OLD | NEW |