473 lines
16 KiB
C++
473 lines
16 KiB
C++
|
// 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_ = NULL;
|
||
|
|
||
|
// 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());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CefRequestHandler 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_ = NULL;
|
||
|
|
||
|
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);
|