| // Copyright (c) 2017 The Chromium Embedded Framework 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 "tests/ceftests/extensions/extension_test_handler.h" |
| #include "tests/ceftests/test_util.h" |
| #include "tests/shared/browser/extension_util.h" |
| |
| #define STORAGE_TEST_GROUP_ALL(name, test_class) \ |
| EXTENSION_TEST_GROUP_ALL(ChromeStorage##name, test_class) |
| #define STORAGE_TEST_GROUP_MINIMAL(name, test_class) \ |
| EXTENSION_TEST_GROUP_MINIMAL(ChromeStorage##name, test_class) |
| |
| namespace { |
| |
| const char kExtensionPath[] = "storage-extension"; |
| const char kSuccessMessage[] = "success"; |
| |
| // Base class for testing chrome.storage methods. |
| // See https://developer.chrome.com/extensions/storage |
| class StorageTestHandler : public ExtensionTestHandler { |
| public: |
| explicit StorageTestHandler(RequestContextType request_context_type) |
| : ExtensionTestHandler(request_context_type) { |
| // Only creating the extension browser. |
| set_create_main_browser(false); |
| } |
| |
| // CefExtensionHandler methods: |
| void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| EXPECT_FALSE(got_loaded_); |
| got_loaded_.yes(); |
| |
| // Verify |extension| contents. |
| EXPECT_FALSE(extension->GetIdentifier().empty()); |
| EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(), |
| client::extension_util::GetInternalExtensionResourcePath( |
| extension->GetPath()) |
| .c_str()); |
| TestDictionaryEqual(CreateManifest(), extension->GetManifest()); |
| |
| EXPECT_FALSE(extension_); |
| extension_ = extension; |
| |
| CreateBrowserForExtension(); |
| } |
| |
| void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| EXPECT_TRUE(extension_); |
| EXPECT_TRUE(extension_->IsSame(extension)); |
| EXPECT_FALSE(got_unloaded_); |
| got_unloaded_.yes(); |
| extension_ = nullptr; |
| |
| // Execute asynchronously so call stacks have a chance to unwind. |
| // Will close the browser windows. |
| CefPostTask(TID_UI, base::Bind(&StorageTestHandler::DestroyTest, this)); |
| } |
| |
| // CefLoadHandler methods: |
| void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, |
| bool isLoading, |
| bool canGoBack, |
| bool canGoForward) override { |
| CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); |
| EXPECT_TRUE(extension); |
| EXPECT_TRUE(extension_->IsSame(extension)); |
| |
| if (isLoading) { |
| EXPECT_FALSE(extension_browser_); |
| extension_browser_ = browser; |
| } else { |
| EXPECT_TRUE(browser->IsSame(extension_browser_)); |
| |
| const std::string& url = browser->GetMainFrame()->GetURL(); |
| EXPECT_STREQ(extension_url_.c_str(), url.c_str()); |
| } |
| } |
| |
| // CefResourceRequestHandler methods: |
| CefRefPtr<CefResourceHandler> GetResourceHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| EXPECT_TRUE(browser->IsSame(extension_browser_)); |
| |
| CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); |
| EXPECT_TRUE(extension); |
| EXPECT_TRUE(extension_->IsSame(extension)); |
| |
| const std::string& url = request->GetURL(); |
| EXPECT_STREQ(extension_url_.c_str(), url.c_str()); |
| |
| EXPECT_FALSE(got_url_request_); |
| got_url_request_.yes(); |
| |
| // Handle the resource request. |
| return RoutingTestHandler::GetResourceHandler(browser, frame, request); |
| } |
| |
| protected: |
| void OnLoadExtensions() override { |
| LoadExtension(kExtensionPath, CreateManifest()); |
| } |
| |
| bool OnMessage(CefRefPtr<CefBrowser> browser, |
| const std::string& message) override { |
| if (message == "extension_onload") { |
| // From body onLoad in the extension browser. |
| EXPECT_TRUE(browser->IsSame(extension_browser_)); |
| EXPECT_FALSE(got_body_onload_); |
| got_body_onload_.yes(); |
| TriggerStorageApiJSFunction(); |
| return true; |
| } |
| EXPECT_TRUE(browser->IsSame(extension_browser_)); |
| EXPECT_FALSE(got_success_message_); |
| got_success_message_.yes(); |
| EXPECT_STREQ(kSuccessMessage, message.c_str()); |
| TriggerDestroyTest(); |
| return true; |
| } |
| |
| void OnDestroyTest() override { |
| extension_browser_ = nullptr; |
| |
| EXPECT_TRUE(got_loaded_); |
| EXPECT_TRUE(got_url_request_); |
| EXPECT_TRUE(got_body_onload_); |
| EXPECT_TRUE(got_trigger_api_function_); |
| EXPECT_TRUE(got_success_message_); |
| EXPECT_TRUE(got_unloaded_); |
| } |
| |
| // Create a manifest that grants access to the storage API. |
| virtual CefRefPtr<CefDictionaryValue> CreateManifest() const { |
| ApiPermissionsList api_permissions; |
| api_permissions.push_back("storage"); |
| return CreateDefaultManifest(api_permissions); |
| } |
| |
| // Add resources in the extension browser. |
| virtual void OnAddExtensionResources(const std::string& origin) { |
| extension_url_ = origin + "extension.html"; |
| AddResource(extension_url_, GetExtensionHTML(), "text/html"); |
| } |
| |
| // Returns the chrome.storage.* JS that is executed in the extension browser |
| // when the triggerStorageApi() JS function is called. |
| virtual std::string GetStorageApiJS() const = 0; |
| |
| // Returns the JS that will be loaded in the extension browser. This |
| // implements the triggerStorageApi() JS function called from |
| // TriggerStorageApiJSFunction(). |
| virtual std::string GetExtensionJS() const { |
| return "function triggerStorageApi() {" + GetStorageApiJS() + "}"; |
| } |
| |
| // Returns the HTML that will be loaded in the extension browser. |
| virtual std::string GetExtensionHTML() const { |
| return "<html><head><script>" + GetExtensionJS() + |
| "</script></head><body onLoad=" + GetMessageJS("extension_onload") + |
| ">Extension</body></html>"; |
| } |
| |
| virtual void TriggerDestroyTest() { |
| // Execute asynchronously so call stacks have a chance to unwind. |
| CefPostTask(TID_UI, base::Bind(&StorageTestHandler::UnloadExtension, this, |
| extension_)); |
| } |
| |
| CefRefPtr<CefExtension> extension() const { return extension_; } |
| std::string extension_url() const { return extension_url_; } |
| CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; } |
| |
| bool got_success_message() const { return got_success_message_; } |
| |
| private: |
| void CreateBrowserForExtension() { |
| const std::string& identifier = extension_->GetIdentifier(); |
| EXPECT_FALSE(identifier.empty()); |
| const std::string& origin = |
| client::extension_util::GetExtensionOrigin(identifier); |
| EXPECT_FALSE(origin.empty()); |
| |
| // Add extension resources. |
| OnAddExtensionResources(origin); |
| |
| // Create a browser to host the extension. |
| CreateBrowser(extension_url_, request_context()); |
| } |
| |
| void TriggerStorageApiJSFunction() { |
| EXPECT_FALSE(got_trigger_api_function_); |
| got_trigger_api_function_.yes(); |
| |
| extension_browser_->GetMainFrame()->ExecuteJavaScript( |
| "triggerStorageApi();", extension_url_, 0); |
| } |
| |
| CefRefPtr<CefExtension> extension_; |
| std::string extension_url_; |
| CefRefPtr<CefBrowser> extension_browser_; |
| |
| TrackCallback got_loaded_; |
| TrackCallback got_url_request_; |
| TrackCallback got_body_onload_; |
| TrackCallback got_trigger_api_function_; |
| TrackCallback got_success_message_; |
| TrackCallback got_unloaded_; |
| }; |
| } // namespace |
| |
| namespace { |
| |
| // Test for chrome.storage.local.set(object items, function callback) |
| // and for chrome.storage.local.get(string or array of string or object keys, |
| // function callback) |
| class LocalStorageTestHandler : public StorageTestHandler { |
| public: |
| explicit LocalStorageTestHandler(RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.local.set({\"local_key_1\": \"local_value_1\"}, " |
| "function() {" |
| "chrome.storage.local.get(\"local_key_1\", function (items) {" |
| "if(items[\"local_key_1\"] == \"local_value_1\") {" + |
| GetMessageJS(kSuccessMessage) + |
| "}});" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(LocalStorageTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(LocalStorageTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_ALL(LocalStorage, LocalStorageTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.local.getBytesInUse(string or array of string keys, |
| // function callback) |
| class LocalStorageGetBytesInUseTestHandler : public StorageTestHandler { |
| public: |
| explicit LocalStorageGetBytesInUseTestHandler( |
| RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.local.set({\"local_key_2\": \"local_value_2\"}, " |
| "function() {" |
| "chrome.storage.local.getBytesInUse(\"local_key_2\", function " |
| "(bytesInUse) {" |
| "if (bytesInUse == 26) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}});" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(LocalStorageGetBytesInUseTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(LocalStorageGetBytesInUseTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(LocalStorageGetBytesInUse, |
| LocalStorageGetBytesInUseTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.local.remove(string or array of string keys, function |
| // callback) |
| class LocalStorageRemoveTestHandler : public StorageTestHandler { |
| public: |
| explicit LocalStorageRemoveTestHandler( |
| RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.local.set({\"local_key_3\": \"local_value_3\"}, " |
| "function() {" |
| "chrome.storage.local.remove(\"local_key_3\", function () {" |
| "chrome.storage.local.get(\"local_key_3\", function(items) {" |
| "if (items[\"local_key_3\"] == undefined) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}})})" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(LocalStorageRemoveTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(LocalStorageRemoveTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(LocalStorageRemove, LocalStorageRemoveTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.local.clear(function callback) |
| class LocalStorageClearTestHandler : public StorageTestHandler { |
| public: |
| explicit LocalStorageClearTestHandler(RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "var value1Cleared = false;" |
| "var value2Cleared = false;" |
| "function checkCleared() {" |
| "if (value1Cleared && value2Cleared) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}}" |
| "chrome.storage.local.set({\"local_key_4\": \"local_value_4\"," |
| "\"local_key_5\": \"local_value_5\"}, function() {" |
| "chrome.storage.local.clear(function () {" |
| |
| "chrome.storage.local.get(\"local_key_4\", function(items) {" |
| "if (items[\"local_key_4\"] == undefined) {" |
| "value1Cleared = true;" |
| "checkCleared();" |
| "}});" |
| |
| "chrome.storage.local.get(\"local_key_5\", function(items) {" |
| "if (items[\"local_key_5\"] == undefined) {" |
| "value2Cleared = true;" |
| "checkCleared();" |
| "}});" |
| "})});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(LocalStorageClearTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(LocalStorageClearTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(LocalStorageClear, LocalStorageClearTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.sync.set(object items, function callback) |
| // and for chrome.storage.sync.get(string or array of string or object keys, |
| // function callback) |
| class SyncStorageTestHandler : public StorageTestHandler { |
| public: |
| explicit SyncStorageTestHandler(RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.sync.set({\"sync_key_1\": \"sync_value_1\"}, " |
| "function() {" |
| "chrome.storage.sync.get(\"sync_key_1\", function (items) {" |
| "if (items[\"sync_key_1\"] == \"sync_value_1\") {" + |
| GetMessageJS(kSuccessMessage) + |
| "}});" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(SyncStorageTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(SyncStorageTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_ALL(SyncStorage, SyncStorageTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.sync.getBytesInUse(string or array of string keys, |
| // function callback) |
| class SyncStorageGetBytesInUseTestHandler : public StorageTestHandler { |
| public: |
| explicit SyncStorageGetBytesInUseTestHandler( |
| RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.sync.set({\"sync_key_2\": \"sync_value_2\"}, " |
| "function() {" |
| "chrome.storage.sync.getBytesInUse(\"sync_key_2\", function " |
| "(bytesInUse) {" |
| "if (bytesInUse == 24) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}});" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(SyncStorageGetBytesInUseTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(SyncStorageGetBytesInUseTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(SyncStorageGetBytesInUse, |
| SyncStorageGetBytesInUseTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.sync.remove(string or array of string keys, function |
| // callback) |
| class SyncStorageRemoveTestHandler : public StorageTestHandler { |
| public: |
| explicit SyncStorageRemoveTestHandler(RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "chrome.storage.sync.set({\"sync_key_3\": \"sync_value_3\"}, " |
| "function() {" |
| "chrome.storage.sync.remove(\"sync_key_3\", function () {" |
| "chrome.storage.sync.get(\"sync_key_3\", function(items) {" |
| "if (items[\"sync_key_3\"] == undefined) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}})})" |
| "});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(SyncStorageRemoveTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(SyncStorageRemoveTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(SyncStorageRemove, SyncStorageRemoveTestHandler) |
| |
| namespace { |
| |
| // Test for chrome.storage.sync.clear(function callback) |
| class SyncStorageClearTestHandler : public StorageTestHandler { |
| public: |
| explicit SyncStorageClearTestHandler(RequestContextType request_context_type) |
| : StorageTestHandler(request_context_type) {} |
| |
| protected: |
| std::string GetStorageApiJS() const override { |
| return "var value1Cleared = false;" |
| "var value2Cleared = false;" |
| |
| "function checkCleared() {" |
| "if (value1Cleared && value2Cleared) {" + |
| GetMessageJS(kSuccessMessage) + |
| "}}" |
| |
| "chrome.storage.sync.set({\"sync_key_4\": \"sync_value_4\"," |
| "\"sync_key_5\": \"sync_value_5\"}, function() {" |
| "chrome.storage.sync.clear(function () {" |
| |
| "chrome.storage.sync.get(\"sync_key_4\", function(items) {" |
| "if (items[\"sync_key_4\"] == undefined) {" |
| "value1Cleared = true;" |
| "checkCleared();" |
| "}});" |
| |
| "chrome.storage.sync.get(\"sync_key_5\", function(items) {" |
| "if (items[\"sync_key_5\"] == undefined) {" |
| "value2Cleared = true;" |
| "checkCleared();" |
| "}});" |
| |
| "})});"; |
| } |
| |
| private: |
| IMPLEMENT_REFCOUNTING(SyncStorageClearTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(SyncStorageClearTestHandler); |
| }; |
| } // namespace |
| |
| STORAGE_TEST_GROUP_MINIMAL(SyncStorageClear, SyncStorageClearTestHandler) |