blob: f71d6d8d59dce5ad5fc42b0ee6f345e1cdaaa1d7 [file] [log] [blame]
// 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)