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

Side by Side Diff: extensions/browser/api/lock_screen_data/item_storage_unittest.cc

Issue 2934293003: The chrome.lockScreen.data API implementation (Closed)
Patch Set: . Created 3 years, 5 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 unified diff | Download patch
OLDNEW
(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 "extensions/browser/api/lock_screen_data/item_storage.h"
6
7 #include <map>
8 #include <memory>
9 #include <queue>
10 #include <set>
11 #include <utility>
12 #include <vector>
13
14 #include "base/callback.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/run_loop.h"
21 #include "base/task_scheduler/post_task.h"
22 #include "base/time/time.h"
23 #include "chromeos/login/login_state.h"
24 #include "components/prefs/scoped_user_pref_update.h"
25 #include "components/prefs/testing_pref_service.h"
26 #include "components/sync_preferences/testing_pref_service_syncable.h"
27 #include "components/user_prefs/user_prefs.h"
28 #include "content/public/test/test_browser_context.h"
29 #include "content/public/test/test_browser_thread_bundle.h"
30 #include "extensions/browser/api/lock_screen_data/data_item.h"
31 #include "extensions/browser/api/lock_screen_data/operation_result.h"
32 #include "extensions/browser/event_router.h"
33 #include "extensions/browser/event_router_factory.h"
34 #include "extensions/browser/extension_registry.h"
35 #include "extensions/browser/extensions_test.h"
36 #include "extensions/browser/test_extensions_browser_client.h"
37 #include "extensions/common/api/lock_screen_data.h"
38 #include "extensions/common/extension_builder.h"
39 #include "extensions/common/value_builder.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41
42 namespace extensions {
43 namespace lock_screen_data {
44
45 namespace {
46
47 const char kTestUserIdHash[] = "user_id_hash";
48 const char kTestSymmetricKey[] = "fake_symmetric_key";
49
50 void RecordCreateResult(OperationResult* result_out,
51 const DataItem** item_out,
52 OperationResult result,
53 const DataItem* item) {
54 *result_out = result;
55 *item_out = item;
56 }
57
58 void RecordGetAllItemsResult(std::vector<std::string>* items_out,
59 const std::vector<const DataItem*>& items) {
60 items_out->clear();
61 for (const DataItem* item : items)
62 items_out->push_back(item->id());
63 }
64
65 void RecordWriteResult(OperationResult* result_out, OperationResult result) {
66 *result_out = result;
67 }
68
69 void RecordReadResult(OperationResult* result_out,
70 std::unique_ptr<std::vector<char>>* content_out,
71 OperationResult result,
72 std::unique_ptr<std::vector<char>> content) {
73 *result_out = result;
74 *content_out = std::move(content);
75 }
76
77 class TestEventRouter : public extensions::EventRouter {
78 public:
79 explicit TestEventRouter(content::BrowserContext* context)
80 : extensions::EventRouter(context, nullptr) {}
81 ~TestEventRouter() override = default;
82
83 bool ExtensionHasEventListener(const std::string& extension_id,
84 const std::string& event_name) const override {
85 return event_name ==
86 extensions::api::lock_screen_data::OnDataItemsAvailable::kEventName;
87 }
88
89 void BroadcastEvent(std::unique_ptr<extensions::Event> event) override {}
90
91 void DispatchEventToExtension(
92 const std::string& extension_id,
93 std::unique_ptr<extensions::Event> event) override {
94 if (event->event_name !=
95 extensions::api::lock_screen_data::OnDataItemsAvailable::kEventName) {
96 return;
97 }
98 ASSERT_TRUE(event->event_args);
99 const base::Value* arg_value = nullptr;
100 ASSERT_TRUE(event->event_args->Get(0, &arg_value));
101 ASSERT_TRUE(arg_value);
102
103 std::unique_ptr<extensions::api::lock_screen_data::DataItemsAvailableEvent>
104 event_args = extensions::api::lock_screen_data::
105 DataItemsAvailableEvent::FromValue(*arg_value);
106 ASSERT_TRUE(event_args);
107 was_locked_values_.push_back(event_args->was_locked);
108 }
109
110 const std::vector<bool>& was_locked_values() const {
111 return was_locked_values_;
112 }
113
114 void ClearWasLockedValues() { was_locked_values_.clear(); }
115
116 private:
117 std::vector<bool> was_locked_values_;
118
119 DISALLOW_COPY_AND_ASSIGN(TestEventRouter);
120 };
121
122 std::unique_ptr<KeyedService> TestEventRouterFactoryFunction(
123 content::BrowserContext* context) {
124 return base::MakeUnique<TestEventRouter>(context);
125 }
126
127 // Keeps track of all fake data items registered during a test.
128 class ItemRegistry {
129 public:
130 explicit ItemRegistry(const std::string& extension_id)
131 : extension_id_(extension_id) {}
132 ~ItemRegistry() = default;
133
134 // Adds a new item to set of registered items.
135 bool Add(const std::string& item_id) {
136 EXPECT_FALSE(items_.count(item_id));
137
138 if (!allow_new_)
139 return false;
140 items_.insert(item_id);
141 return true;
142 }
143
144 // Removes an item from the set of registered items.
145 void Remove(const std::string& item_id) {
146 ASSERT_TRUE(items_.count(item_id));
147 items_.erase(item_id);
148 }
149
150 void RemoveAll() { items_.clear(); }
151
152 // Gets the set of registered data items.
153 void HandleGetRequest(const DataItem::RegisteredValuesCallback& callback) {
154 if (!throttle_get_) {
155 RunCallback(callback);
156 return;
157 }
158
159 ASSERT_TRUE(pending_callback_.is_null());
160 pending_callback_ = callback;
161 }
162
163 // Completes a pending |HandleGetRequest| request.
164 void RunPendingCallback() {
165 ASSERT_FALSE(pending_callback_.is_null());
166 DataItem::RegisteredValuesCallback callback = pending_callback_;
167 pending_callback_.Reset();
168 RunCallback(callback);
169 }
170
171 bool HasPendingCallback() const { return !pending_callback_.is_null(); }
172
173 void set_allow_new(bool allow_new) { allow_new_ = allow_new; }
174 void set_fail(bool fail) { fail_ = fail; }
175 void set_throttle_get(bool throttle_get) { throttle_get_ = throttle_get; }
176
177 private:
178 void RunCallback(const DataItem::RegisteredValuesCallback& callback) {
179 callback.Run(fail_ ? OperationResult::kFailed : OperationResult::kSuccess,
180 ItemsToValue());
181 }
182
183 std::unique_ptr<base::DictionaryValue> ItemsToValue() {
184 if (fail_)
185 return nullptr;
186
187 std::unique_ptr<base::DictionaryValue> result =
188 base::MakeUnique<base::DictionaryValue>();
189
190 for (const std::string& item_id : items_)
191 result->Set(item_id, base::MakeUnique<base::DictionaryValue>());
192
193 return result;
194 }
195
196 const std::string extension_id_;
197 // Whether data item registration should succeed.
198 bool allow_new_ = true;
199 // Whether data item retrievals should fail.
200 bool fail_ = false;
201 // Whether the data item retrivals should be throttled. If set,
202 // |HandleGetRequest| callback will be saved to |pending_callback_| without
203 // returning. Test will have to invoke |RunPendingCallback| in order to
204 // complete the request.
205 bool throttle_get_ = false;
206
207 DataItem::RegisteredValuesCallback pending_callback_;
208 // Set of registered item ids.
209 std::set<std::string> items_;
210
211 DISALLOW_COPY_AND_ASSIGN(ItemRegistry);
212 };
213
214 // Keeps track of all operations requested from the test data item.
215 // The operations will remain in pending state until completed by calling
216 // CompleteNextOperation.
217 // This is owned by the test class, but data items created during the test have
218 // a reference to the object. More than one data item can have a reference to
219 // this - data items with the same ID will get the same operation queue.
220 class OperationQueue {
221 public:
222 enum class OperationType { kWrite, kRead, kDelete };
223
224 struct PendingOperation {
225 explicit PendingOperation(OperationType type) : type(type) {}
226
227 OperationType type;
228 // Set only for write - data to be written.
229 std::vector<char> data;
230
231 // Callback for write operation.
232 DataItem::WriteCallback write_callback;
233
234 // Callback for read operation.
235 DataItem::ReadCallback read_callback;
236
237 // Callback for delete operation.
238 DataItem::WriteCallback delete_callback;
239 };
240
241 OperationQueue(const std::string& id, ItemRegistry* item_registry)
242 : id_(id), item_registry_(item_registry) {}
243
244 ~OperationQueue() = default;
245
246 void Register(const DataItem::WriteCallback& callback) {
247 bool registered = item_registry_->Add(id_);
248 callback.Run(registered ? OperationResult::kSuccess
249 : OperationResult::kFailed);
250 }
251
252 void AddWrite(const std::vector<char>& data,
253 const DataItem::WriteCallback& callback) {
254 PendingOperation operation(OperationType::kWrite);
255 operation.data = data;
256 operation.write_callback = callback;
257
258 pending_operations_.emplace(std::move(operation));
259 }
260
261 void AddRead(const DataItem::ReadCallback& callback) {
262 PendingOperation operation(OperationType::kRead);
263 operation.read_callback = callback;
264
265 pending_operations_.emplace(std::move(operation));
266 }
267
268 void AddDelete(const DataItem::WriteCallback& callback) {
269 PendingOperation operation(OperationType::kDelete);
270 operation.delete_callback = callback;
271
272 pending_operations_.emplace(std::move(operation));
273 }
274
275 // Completes the next pendig operation.
276 // |expected_type| - the expected type of the next operation - this will fail
277 // if the operation does not match.
278 // |result| - the intended operation result.
279 void CompleteNextOperation(OperationType expected_type,
280 OperationResult result) {
281 ASSERT_FALSE(pending_operations_.empty());
282 ASSERT_FALSE(deleted_);
283
284 const PendingOperation& operation = pending_operations_.front();
285
286 ASSERT_EQ(expected_type, operation.type);
287
288 switch (expected_type) {
289 case OperationType::kWrite: {
290 if (result == OperationResult::kSuccess)
291 content_ = operation.data;
292 DataItem::WriteCallback callback = operation.write_callback;
293 pending_operations_.pop();
294 callback.Run(result);
295 break;
296 }
297 case OperationType::kDelete: {
298 if (result == OperationResult::kSuccess) {
299 deleted_ = true;
300 item_registry_->Remove(id_);
301 content_ = std::vector<char>();
302 }
303
304 DataItem::WriteCallback callback = operation.delete_callback;
305 pending_operations_.pop();
306 callback.Run(result);
307 break;
308 }
309 case OperationType::kRead: {
310 std::unique_ptr<std::vector<char>> result_data;
311 if (result == OperationResult::kSuccess) {
312 result_data = base::MakeUnique<std::vector<char>>(content_.begin(),
313 content_.end());
314 }
315
316 DataItem::ReadCallback callback = operation.read_callback;
317 pending_operations_.pop();
318 callback.Run(result, std::move(result_data));
319 break;
320 }
321 default:
322 ADD_FAILURE() << "Unexpected operation";
323 return;
324 }
325 }
326
327 bool HasPendingOperations() const { return !pending_operations_.empty(); }
328
329 bool deleted() const { return deleted_; }
330
331 const std::vector<char>& content() const { return content_; }
332
333 private:
334 std::string id_;
335 ItemRegistry* item_registry_;
336 std::queue<PendingOperation> pending_operations_;
337 std::vector<char> content_;
338 bool deleted_ = false;
339
340 DISALLOW_COPY_AND_ASSIGN(OperationQueue);
341 };
342
343 // Test data item - routes all requests to the OperationQueue provided through
344 // the ctor - the owning test is responsible for completing the started
345 // operations.
346 class TestDataItem : public DataItem {
347 public:
348 // |operations| - Operation queue used by this data item - not owned by this,
349 // and expected to outlive this object.
350 TestDataItem(const std::string& id,
351 const std::string& extension_id,
352 const std::string& crypto_key,
353 OperationQueue* operations)
354 : DataItem(id, extension_id, nullptr, nullptr, nullptr, crypto_key),
355 operations_(operations) {}
356
357 ~TestDataItem() override = default;
358
359 void Register(const WriteCallback& callback) override {
360 operations_->Register(callback);
361 }
362
363 void Write(const std::vector<char>& data,
364 const WriteCallback& callback) override {
365 operations_->AddWrite(data, callback);
366 }
367
368 void Read(const ReadCallback& callback) override {
369 operations_->AddRead(callback);
370 }
371
372 void Delete(const WriteCallback& callback) override {
373 operations_->AddDelete(callback);
374 }
375
376 private:
377 OperationQueue* operations_;
378
379 DISALLOW_COPY_AND_ASSIGN(TestDataItem);
380 };
381
382 class ItemStorageTest : public ExtensionsTest {
383 public:
384 ItemStorageTest()
385 : ExtensionsTest(base::MakeUnique<content::TestBrowserThreadBundle>()) {}
386 ~ItemStorageTest() override = default;
387
388 void SetUp() override {
389 ExtensionsTest::SetUp();
390
391 ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
392 ItemStorage::RegisterLocalState(local_state_.registry());
393 user_prefs::UserPrefs::Set(browser_context(), &testing_pref_service_);
394 extensions_browser_client()->set_lock_screen_context(&lock_screen_context_);
395
396 chromeos::LoginState::Initialize();
397 chromeos::LoginState::Get()->SetLoggedInStateAndPrimaryUser(
398 chromeos::LoginState::LOGGED_IN_ACTIVE,
399 chromeos::LoginState::LOGGED_IN_USER_REGULAR, kTestUserIdHash);
400
401 CreateTestExtension();
402 item_registry_ = base::MakeUnique<ItemRegistry>(extension()->id());
403
404 // Inject custom data item factory to be used with ItemStorage instances.
405 item_factory_ =
406 base::Bind(&ItemStorageTest::CreateItem, base::Unretained(this));
407 registered_items_getter_ = base::Bind(&ItemStorageTest::GetRegisteredItems,
408 base::Unretained(this));
409 item_store_deleter_ =
410 base::Bind(&ItemStorageTest::RemoveAllItems, base::Unretained(this));
411 ItemStorage::SetItemProvidersForTesting(
412 &registered_items_getter_, &item_factory_, &item_store_deleter_);
413
414 ResetItemStorage();
415 }
416
417 void TearDown() override {
418 item_storage_.reset();
419 operations_.clear();
420 item_registry_.reset();
421 ItemStorage::SetItemProvidersForTesting(nullptr, nullptr, nullptr);
422 chromeos::LoginState::Shutdown();
423 ExtensionsTest::TearDown();
424 }
425
426 OperationQueue* GetOperations(const std::string& id) {
427 return operations_[id].get();
428 }
429
430 void UnsetItemStorage() { item_storage_.reset(); }
431
432 void ResetItemStorage() {
433 item_storage_.reset();
434 item_storage_ =
435 base::MakeUnique<ItemStorage>(browser_context(), &local_state_,
436 kTestSymmetricKey, test_dir_.GetPath());
437 }
438
439 // Utility method for setting test item content.
440 bool SetItemContent(const std::string& id, const std::vector<char>& content) {
441 OperationQueue* item_operations = GetOperations(id);
442 if (!item_operations) {
443 ADD_FAILURE() << "No item operations";
444 return false;
445 }
446 OperationResult write_result = OperationResult::kFailed;
447 item_storage()->SetItemContent(
448 extension()->id(), id, content,
449 base::Bind(&RecordWriteResult, &write_result));
450 if (!item_operations->HasPendingOperations()) {
451 ADD_FAILURE() << "Write not registered";
452 return false;
453 }
454 item_operations->CompleteNextOperation(
455 OperationQueue::OperationType::kWrite, OperationResult::kSuccess);
456 EXPECT_EQ(OperationResult::kSuccess, write_result);
457 return write_result == OperationResult::kSuccess;
458 }
459
460 const DataItem* CreateNewItem() {
461 OperationResult create_result = OperationResult::kFailed;
462 const DataItem* item = nullptr;
463 item_storage()->CreateItem(
464 extension()->id(),
465 base::Bind(&RecordCreateResult, &create_result, &item));
466 EXPECT_EQ(OperationResult::kSuccess, create_result);
467
468 return item;
469 }
470
471 // Utility method for creating a new testing data item, and setting its
472 // content.
473 const DataItem* CreateItemWithContent(const std::vector<char>& content) {
474 const DataItem* item = CreateNewItem();
475 if (!item) {
476 ADD_FAILURE() << "Item creation failed";
477 return nullptr;
478 }
479
480 if (!SetItemContent(item->id(), content))
481 return nullptr;
482
483 return item;
484 }
485
486 void GetAllItems(std::vector<std::string>* all_items) {
487 item_storage()->GetAllForExtension(
488 extension()->id(), base::Bind(&RecordGetAllItemsResult, all_items));
489 }
490
491 // Finds an item with the ID |id| in list of items |items|.
492 const DataItem* FindItem(const std::string& id,
493 const std::vector<const DataItem*> items) {
494 for (const auto* item : items) {
495 if (item && item->id() == id)
496 return item;
497 }
498 return nullptr;
499 }
500
501 ItemStorage* item_storage() { return item_storage_.get(); }
502
503 content::BrowserContext* lock_screen_context() {
504 return &lock_screen_context_;
505 }
506
507 const Extension* extension() const { return extension_.get(); }
508
509 const base::FilePath& test_dir() const { return test_dir_.GetPath(); }
510
511 PrefService* local_state() { return &local_state_; }
512
513 ItemRegistry* item_registry() { return item_registry_.get(); }
514
515 private:
516 void CreateTestExtension() {
517 DictionaryBuilder app_builder;
518 app_builder.Set("background",
519 DictionaryBuilder()
520 .Set("scripts", ListBuilder().Append("script").Build())
521 .Build());
522 ListBuilder app_handlers_builder;
523 app_handlers_builder.Append(DictionaryBuilder()
524 .Set("action", "new_note")
525 .SetBoolean("enabled_on_lock_screen", true)
526 .Build());
527 extension_ =
528 ExtensionBuilder()
529 .SetManifest(
530 DictionaryBuilder()
531 .Set("name", "Test app")
532 .Set("version", "1.0")
533 .Set("manifest_version", 2)
534 .Set("app", app_builder.Build())
535 .Set("action_handlers", app_handlers_builder.Build())
536 .Set("permissions",
537 ListBuilder().Append("lockScreen").Build())
538 .Build())
539 .Build();
540 ExtensionRegistry::Get(browser_context())->AddEnabled(extension_);
541 }
542
543 // Callback for creating test data items - this is the callback passed to
544 // ItemStorage via SetItemFactoryForTesting.
545 std::unique_ptr<DataItem> CreateItem(const std::string& id,
546 const std::string& extension_id,
547 const std::string& crypto_key) {
548 EXPECT_EQ(extension()->id(), extension_id);
549 EXPECT_EQ(kTestSymmetricKey, crypto_key);
550
551 // If there is an operation queue for the item id, reuse it in order to
552 // retain state on ItemStorage restart.
553 OperationQueue* operation_queue = GetOperations(id);
554 if (!operation_queue) {
555 operations_[id] =
556 base::MakeUnique<OperationQueue>(id, item_registry_.get());
557 operation_queue = operations_[id].get();
558 }
559 return base::MakeUnique<TestDataItem>(id, extension_id, crypto_key,
560 operation_queue);
561 }
562
563 void GetRegisteredItems(const std::string& extension_id,
564 const DataItem::RegisteredValuesCallback& callback) {
565 if (extension()->id() != extension_id) {
566 callback.Run(OperationResult::kUnknownExtension, nullptr);
567 return;
568 }
569 item_registry_->HandleGetRequest(callback);
570 }
571
572 void RemoveAllItems(const std::string& extension_id,
573 const base::Closure& callback) {
574 ASSERT_EQ(extension()->id(), extension_id);
575 item_registry_->RemoveAll();
576 callback.Run();
577 }
578
579 std::unique_ptr<ItemStorage> item_storage_;
580
581 content::TestBrowserContext lock_screen_context_;
582 TestingPrefServiceSimple local_state_;
583
584 base::ScopedTempDir test_dir_;
585
586 sync_preferences::TestingPrefServiceSyncable testing_pref_service_;
587
588 ItemStorage::ItemFactoryCallback item_factory_;
589 ItemStorage::RegisteredItemsGetter registered_items_getter_;
590 ItemStorage::ItemStoreDeleter item_store_deleter_;
591
592 scoped_refptr<const Extension> extension_;
593
594 std::unique_ptr<ItemRegistry> item_registry_;
595 std::map<std::string, std::unique_ptr<OperationQueue>> operations_;
596
597 DISALLOW_COPY_AND_ASSIGN(ItemStorageTest);
598 };
599
600 } // namespace
601
602 TEST_F(ItemStorageTest, GetDependingOnSessionState) {
603 // Session state not initialized.
604 EXPECT_FALSE(ItemStorage::Get(browser_context()));
605 EXPECT_FALSE(ItemStorage::Get(lock_screen_context()));
606
607 // Locked session.
608 item_storage()->SetSessionLocked(true);
609 EXPECT_FALSE(ItemStorage::Get(browser_context()));
610 EXPECT_EQ(item_storage(), ItemStorage::Get(lock_screen_context()));
611
612 item_storage()->SetSessionLocked(false);
613
614 EXPECT_EQ(item_storage(), ItemStorage::Get(browser_context()));
615 EXPECT_FALSE(ItemStorage::Get(lock_screen_context()));
616 }
617
618 TEST_F(ItemStorageTest, SetAndGetContent) {
619 item_storage()->SetSessionLocked(true);
620
621 const DataItem* item = CreateNewItem();
622 ASSERT_TRUE(item);
623
624 std::vector<std::string> all_items;
625 GetAllItems(&all_items);
626 ASSERT_EQ(1u, all_items.size());
627 EXPECT_EQ(item->id(), all_items[0]);
628
629 OperationQueue* item_operations = GetOperations(item->id());
630 ASSERT_TRUE(item_operations);
631 EXPECT_FALSE(item_operations->HasPendingOperations());
632
633 std::vector<char> content = {'f', 'i', 'l', 'e'};
634 OperationResult write_result = OperationResult::kFailed;
635 item_storage()->SetItemContent(extension()->id(), item->id(), content,
636 base::Bind(&RecordWriteResult, &write_result));
637
638 item_operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
639 OperationResult::kSuccess);
640
641 EXPECT_EQ(OperationResult::kSuccess, write_result);
642 EXPECT_EQ(content, item_operations->content());
643
644 OperationResult read_result = OperationResult::kFailed;
645 std::unique_ptr<std::vector<char>> read_content;
646
647 item_storage()->GetItemContent(
648 extension()->id(), item->id(),
649 base::Bind(&RecordReadResult, &read_result, &read_content));
650
651 item_operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
652 OperationResult::kSuccess);
653 EXPECT_EQ(OperationResult::kSuccess, read_result);
654 EXPECT_EQ(content, *read_content);
655
656 OperationResult delete_result = OperationResult::kFailed;
657 item_storage()->DeleteItem(extension()->id(), item->id(),
658 base::Bind(&RecordWriteResult, &delete_result));
659
660 item_operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
661 OperationResult::kSuccess);
662 EXPECT_EQ(OperationResult::kSuccess, delete_result);
663 EXPECT_TRUE(item_operations->deleted());
664 }
665
666 TEST_F(ItemStorageTest, FailToInitializeData) {
667 item_storage()->SetSessionLocked(true);
668
669 const DataItem* item = CreateNewItem();
670 ASSERT_TRUE(item);
671 const std::string item_id = item->id();
672
673 ResetItemStorage();
674 item_registry()->set_fail(true);
675
676 OperationResult write_result = OperationResult::kFailed;
677 item_storage()->SetItemContent(extension()->id(), item_id, {'x'},
678 base::Bind(&RecordWriteResult, &write_result));
679 EXPECT_EQ(OperationResult::kNotFound, write_result);
680
681 OperationResult read_result = OperationResult::kFailed;
682 std::unique_ptr<std::vector<char>> read_content;
683 item_storage()->GetItemContent(
684 extension()->id(), item_id,
685 base::Bind(&RecordReadResult, &read_result, &read_content));
686 EXPECT_EQ(OperationResult::kNotFound, read_result);
687
688 OperationResult delete_result = OperationResult::kFailed;
689 item_storage()->DeleteItem(extension()->id(), "non_existen",
690 base::Bind(&RecordWriteResult, &delete_result));
691 EXPECT_EQ(OperationResult::kNotFound, delete_result);
692
693 OperationQueue* operations = GetOperations(item_id);
694 ASSERT_TRUE(operations);
695 EXPECT_FALSE(operations->HasPendingOperations());
696
697 item_registry()->set_fail(false);
698
699 const DataItem* new_item = CreateNewItem();
700 ASSERT_TRUE(new_item);
701
702 write_result = OperationResult::kFailed;
703 item_storage()->SetItemContent(extension()->id(), new_item->id(), {'y'},
704 base::Bind(&RecordWriteResult, &write_result));
705
706 OperationQueue* new_item_operations = GetOperations(new_item->id());
707 ASSERT_TRUE(new_item_operations);
708 new_item_operations->CompleteNextOperation(
709 OperationQueue::OperationType::kWrite, OperationResult::kSuccess);
710 EXPECT_EQ(OperationResult::kSuccess, write_result);
711
712 std::vector<std::string> items;
713 GetAllItems(&items);
714 ASSERT_EQ(1u, items.size());
715 EXPECT_EQ(new_item->id(), items[0]);
716 }
717
718 TEST_F(ItemStorageTest, RequestsDuringInitialLoad) {
719 item_storage()->SetSessionLocked(true);
720
721 const DataItem* item = CreateNewItem();
722 ASSERT_TRUE(item);
723 const std::string item_id = item->id();
724
725 item_registry()->set_throttle_get(true);
726 ResetItemStorage();
727
728 EXPECT_FALSE(item_registry()->HasPendingCallback());
729
730 OperationResult write_result = OperationResult::kFailed;
731 item_storage()->SetItemContent(extension()->id(), item_id, {'x'},
732 base::Bind(&RecordWriteResult, &write_result));
733
734 OperationResult read_result = OperationResult::kFailed;
735 std::unique_ptr<std::vector<char>> read_content;
736 item_storage()->GetItemContent(
737 extension()->id(), item_id,
738 base::Bind(&RecordReadResult, &read_result, &read_content));
739
740 std::vector<std::string> items;
741 item_storage()->GetAllForExtension(
742 extension()->id(), base::Bind(&RecordGetAllItemsResult, &items));
743 EXPECT_TRUE(items.empty());
744
745 OperationResult delete_result = OperationResult::kFailed;
746 item_storage()->DeleteItem(extension()->id(), item_id,
747 base::Bind(&RecordWriteResult, &delete_result));
748
749 OperationQueue* operations = GetOperations(item_id);
750 ASSERT_TRUE(operations);
751 EXPECT_FALSE(operations->HasPendingOperations());
752
753 OperationResult create_result = OperationResult::kFailed;
754 const DataItem* new_item = nullptr;
755 item_storage()->CreateItem(
756 extension()->id(),
757 base::Bind(&RecordCreateResult, &create_result, &new_item));
758 EXPECT_FALSE(new_item);
759
760 EXPECT_TRUE(item_registry()->HasPendingCallback());
761 item_registry()->RunPendingCallback();
762
763 EXPECT_TRUE(operations->HasPendingOperations());
764
765 operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
766 OperationResult::kSuccess);
767 operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
768 OperationResult::kSuccess);
769 operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
770 OperationResult::kSuccess);
771
772 EXPECT_EQ(OperationResult::kSuccess, write_result);
773 EXPECT_EQ(OperationResult::kSuccess, read_result);
774 ASSERT_TRUE(read_content);
775 EXPECT_EQ(std::vector<char>({'x'}), *read_content);
776 EXPECT_EQ(OperationResult::kSuccess, delete_result);
777 EXPECT_EQ(OperationResult::kSuccess, create_result);
778
779 EXPECT_TRUE(new_item);
780
781 ASSERT_EQ(1u, items.size());
782 EXPECT_EQ(item_id, items[0]);
783
784 GetAllItems(&items);
785 ASSERT_EQ(1u, items.size());
786 EXPECT_EQ(new_item->id(), items[0]);
787 }
788
789 TEST_F(ItemStorageTest, HandleNonExistent) {
790 item_storage()->SetSessionLocked(true);
791
792 const DataItem* item = CreateNewItem();
793 ASSERT_TRUE(item);
794
795 std::vector<char> content = {'x'};
796
797 OperationResult write_result = OperationResult::kFailed;
798 item_storage()->SetItemContent(extension()->id(), "non_existent", content,
799 base::Bind(&RecordWriteResult, &write_result));
800 EXPECT_EQ(OperationResult::kNotFound, write_result);
801
802 write_result = OperationResult::kFailed;
803 item_storage()->SetItemContent("non_existent", item->id(), content,
804 base::Bind(&RecordWriteResult, &write_result));
805 EXPECT_EQ(OperationResult::kNotFound, write_result);
806
807 OperationResult read_result = OperationResult::kFailed;
808 std::unique_ptr<std::vector<char>> read_content;
809 item_storage()->GetItemContent(
810 extension()->id(), "non_existent",
811 base::Bind(&RecordReadResult, &read_result, &read_content));
812 EXPECT_EQ(OperationResult::kNotFound, read_result);
813 read_result = OperationResult::kFailed;
814
815 item_storage()->GetItemContent(
816 "non_existent", item->id(),
817 base::Bind(&RecordReadResult, &read_result, &read_content));
818 EXPECT_EQ(OperationResult::kNotFound, read_result);
819
820 OperationResult delete_result = OperationResult::kFailed;
821 item_storage()->DeleteItem(extension()->id(), "non_existen",
822 base::Bind(&RecordWriteResult, &delete_result));
823 EXPECT_EQ(OperationResult::kNotFound, delete_result);
824
825 delete_result = OperationResult::kFailed;
826 item_storage()->DeleteItem("non_existent", item->id(),
827 base::Bind(&RecordWriteResult, &delete_result));
828 EXPECT_EQ(OperationResult::kNotFound, delete_result);
829 }
830
831 TEST_F(ItemStorageTest, HandleFailure) {
832 item_storage()->SetSessionLocked(true);
833
834 const DataItem* item = CreateItemWithContent({'x'});
835 ASSERT_TRUE(item);
836 OperationQueue* operations = GetOperations(item->id());
837 ASSERT_TRUE(operations);
838
839 OperationResult write_result = OperationResult::kFailed;
840 item_storage()->SetItemContent(extension()->id(), item->id(), {'x'},
841 base::Bind(&RecordWriteResult, &write_result));
842 operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
843 OperationResult::kInvalidKey);
844 EXPECT_EQ(OperationResult::kInvalidKey, write_result);
845
846 OperationResult read_result = OperationResult::kFailed;
847 std::unique_ptr<std::vector<char>> read_content;
848 item_storage()->GetItemContent(
849 extension()->id(), item->id(),
850 base::Bind(&RecordReadResult, &read_result, &read_content));
851 operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
852 OperationResult::kWrongKey);
853 EXPECT_EQ(OperationResult::kWrongKey, read_result);
854 EXPECT_FALSE(read_content);
855
856 EXPECT_FALSE(operations->HasPendingOperations());
857 }
858
859 TEST_F(ItemStorageTest, DataItemsAvailableEventOnUnlock) {
860 TestEventRouter* event_router = static_cast<TestEventRouter*>(
861 extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
862 browser_context(), &TestEventRouterFactoryFunction));
863 ASSERT_TRUE(event_router);
864
865 EXPECT_TRUE(event_router->was_locked_values().empty());
866
867 item_storage()->SetSessionLocked(true);
868 EXPECT_TRUE(event_router->was_locked_values().empty());
869
870 // No event since no data items associated with the app exist.
871 item_storage()->SetSessionLocked(false);
872 EXPECT_TRUE(event_router->was_locked_values().empty());
873
874 item_storage()->SetSessionLocked(true);
875 const DataItem* item = CreateItemWithContent({'f', 'i', 'l', 'e', '1'});
876 const std::string item_id = item->id();
877 EXPECT_TRUE(event_router->was_locked_values().empty());
878
879 // There's an available data item, so unlock should trigger the event.
880 item_storage()->SetSessionLocked(false);
881 EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
882 event_router->ClearWasLockedValues();
883
884 // Update the item content while the session is unlocked.
885 EXPECT_TRUE(SetItemContent(item_id, {'f', 'i', 'l', 'e', '2'}));
886
887 item_storage()->SetSessionLocked(true);
888
889 // Data item is still around - notify the app it's available.
890 item_storage()->SetSessionLocked(false);
891 EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
892 event_router->ClearWasLockedValues();
893
894 item_storage()->SetSessionLocked(true);
895
896 EXPECT_TRUE(SetItemContent(item_id, {'f', 'i', 'l', 'e', '3'}));
897
898 item_storage()->SetSessionLocked(false);
899 EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
900 event_router->ClearWasLockedValues();
901
902 // When the item is deleted, the data item avilable event should stop firing.
903 OperationResult delete_result;
904 item_storage()->DeleteItem(extension()->id(), item_id,
905 base::Bind(&RecordWriteResult, &delete_result));
906 OperationQueue* operations = GetOperations(item_id);
907 ASSERT_TRUE(operations);
908 operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
909 OperationResult::kSuccess);
910 item_storage()->SetSessionLocked(false);
911 item_storage()->SetSessionLocked(true);
912
913 EXPECT_TRUE(event_router->was_locked_values().empty());
914 }
915
916 TEST_F(ItemStorageTest, NoDataItemsAvailableEventAfterFailedCreation) {
917 TestEventRouter* event_router = static_cast<TestEventRouter*>(
918 extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
919 browser_context(), &TestEventRouterFactoryFunction));
920 ASSERT_TRUE(event_router);
921
922 item_storage()->SetSessionLocked(true);
923
924 item_registry()->set_allow_new(false);
925
926 OperationResult create_result = OperationResult::kFailed;
927 const DataItem* item = nullptr;
928 item_storage()->CreateItem(
929 extension()->id(),
930 base::Bind(&RecordCreateResult, &create_result, &item));
931 EXPECT_EQ(OperationResult::kFailed, create_result);
932
933 item_storage()->SetSessionLocked(false);
934 item_storage()->SetSessionLocked(true);
935 EXPECT_TRUE(event_router->was_locked_values().empty());
936 }
937
938 TEST_F(ItemStorageTest, DataItemsAvailableEventOnRestart) {
939 TestEventRouter* event_router = static_cast<TestEventRouter*>(
940 extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
941 browser_context(), &TestEventRouterFactoryFunction));
942 ASSERT_TRUE(event_router);
943
944 EXPECT_TRUE(event_router->was_locked_values().empty());
945
946 item_storage()->SetSessionLocked(true);
947 EXPECT_TRUE(event_router->was_locked_values().empty());
948
949 const DataItem* item = CreateItemWithContent({'f', 'i', 'l', 'e', '1'});
950 EXPECT_TRUE(event_router->was_locked_values().empty());
951 const std::string item_id = item->id();
952
953 ResetItemStorage();
954
955 EXPECT_TRUE(event_router->was_locked_values().empty());
956 item_storage()->SetSessionLocked(false);
957
958 EXPECT_EQ(std::vector<bool>({false}), event_router->was_locked_values());
959 event_router->ClearWasLockedValues();
960
961 // The event should be dispatched on next unlock event, as long as a valid
962 // item exists.
963 ResetItemStorage();
964 item_storage()->SetSessionLocked(false);
965
966 EXPECT_EQ(std::vector<bool>({false}), event_router->was_locked_values());
967 event_router->ClearWasLockedValues();
968
969 ResetItemStorage();
970
971 OperationResult delete_result = OperationResult::kFailed;
972 item_storage()->DeleteItem(extension()->id(), item_id,
973 base::Bind(&RecordWriteResult, &delete_result));
974 OperationQueue* operations = GetOperations(item_id);
975 ASSERT_TRUE(operations);
976 operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
977 OperationResult::kSuccess);
978
979 item_storage()->SetSessionLocked(false);
980 EXPECT_TRUE(event_router->was_locked_values().empty());
981 }
982
983 TEST_F(ItemStorageTest, ClearDataOnUninstall) {
984 const DataItem* item = CreateItemWithContent({'x'});
985 ASSERT_TRUE(item);
986
987 ExtensionRegistry::Get(browser_context())->RemoveEnabled(extension()->id());
988 ExtensionRegistry::Get(browser_context())
989 ->TriggerOnUninstalled(extension(), UNINSTALL_REASON_FOR_TESTING);
990 ExtensionRegistry::Get(browser_context())->AddEnabled(extension());
991
992 std::vector<std::string> items;
993 GetAllItems(&items);
994 EXPECT_TRUE(items.empty());
995 }
996
997 TEST_F(ItemStorageTest, ClearOnUninstallWhileItemStorageNotSet) {
998 TestEventRouter* event_router = static_cast<TestEventRouter*>(
999 extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
1000 browser_context(), &TestEventRouterFactoryFunction));
1001 ASSERT_TRUE(event_router);
1002
1003 const DataItem* item = CreateItemWithContent({'x'});
1004 ASSERT_TRUE(item);
1005
1006 UnsetItemStorage();
1007
1008 ExtensionRegistry::Get(browser_context())->RemoveEnabled(extension()->id());
1009 ExtensionRegistry::Get(browser_context())
1010 ->TriggerOnUninstalled(extension(), UNINSTALL_REASON_FOR_TESTING);
1011
1012 ResetItemStorage();
1013 ExtensionRegistry::Get(browser_context())->AddEnabled(extension());
1014 item_storage()->SetSessionLocked(false);
1015
1016 std::vector<std::string> items;
1017 GetAllItems(&items);
1018 EXPECT_TRUE(items.empty());
1019
1020 EXPECT_TRUE(event_router->was_locked_values().empty());
1021 }
1022
1023 } // namespace lock_screen_data
1024 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698