| // 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/client_app_browser.h" |
| #include "tests/shared/browser/extension_util.h" |
| |
| using client::ClientAppBrowser; |
| |
| namespace { |
| |
| const char kExtensionPath[] = "background-extension"; |
| const char kBackgroundScript[] = "background.js"; |
| // HTML file created internally to load the background script. |
| const char kGeneratedBackgroundPage[] = "_generated_background_page.html"; |
| |
| // Test load/unload of an extension with a background script. |
| class BackgroundLoadUnloadTestHandler : public ExtensionTestHandler { |
| public: |
| explicit BackgroundLoadUnloadTestHandler( |
| 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_TRUE(extension); |
| EXPECT_TRUE(extension->IsLoaded()); |
| EXPECT_TRUE(extension->GetLoaderContext()); |
| EXPECT_TRUE( |
| loader_request_context()->IsSame(extension->GetLoaderContext())); |
| VerifyExtension(extension); |
| |
| EXPECT_FALSE(got_loaded_); |
| got_loaded_.yes(); |
| |
| EXPECT_FALSE(extension_); |
| extension_ = extension; |
| |
| background_page_url_ = GetExtensionURL(extension, kGeneratedBackgroundPage); |
| |
| // Add extension resources. |
| script_url_ = GetExtensionURL(extension, kBackgroundScript); |
| AddResource(script_url_, GetMessageJS("extension_onload"), |
| "text/javascript"); |
| } |
| |
| void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| EXPECT_TRUE(extension); |
| EXPECT_FALSE(extension->IsLoaded()); |
| EXPECT_FALSE(extension->GetLoaderContext()); |
| |
| EXPECT_FALSE(got_unloaded_); |
| got_unloaded_.yes(); |
| |
| EXPECT_TRUE(extension_); |
| EXPECT_TRUE(extension_->IsSame(extension)); |
| |
| // The extension should no longer be registered with the context. |
| if (loader_request_context()) |
| VerifyExtensionInContext(extension, loader_request_context(), false, |
| true); |
| if (request_context() && !request_context_same_loader()) |
| VerifyExtensionInContext(extension, request_context(), false, false); |
| |
| extension_ = nullptr; |
| |
| // Execute asynchronously so call stacks have a chance to unwind. |
| // Will close the browser windows. |
| CefPostTask( |
| TID_UI, |
| base::Bind(&BackgroundLoadUnloadTestHandler::DestroyTest, this)); |
| } |
| |
| bool OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension, |
| const CefString& url, |
| CefRefPtr<CefClient>& client, |
| CefBrowserSettings& settings) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| EXPECT_TRUE(extension); |
| EXPECT_TRUE(extension->IsLoaded()); |
| EXPECT_TRUE(extension->GetLoaderContext()); |
| EXPECT_TRUE( |
| loader_request_context()->IsSame(extension->GetLoaderContext())); |
| VerifyExtension(extension); |
| |
| const std::string& background_page_url = |
| GetExtensionURL(extension, kGeneratedBackgroundPage); |
| EXPECT_STREQ(background_page_url.c_str(), url.ToString().c_str()); |
| |
| EXPECT_FALSE(client); |
| client = this; |
| |
| // Allow the browser creation. |
| return false; |
| } |
| |
| // CefLoadHandler methods: |
| void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, |
| bool isLoading, |
| bool canGoBack, |
| bool canGoForward) override { |
| EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); |
| |
| 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(background_page_url_.c_str(), url.c_str()); |
| |
| EXPECT_FALSE(got_load_done_); |
| got_load_done_.yes(); |
| |
| TriggerDestroyTestIfDone(); |
| } |
| } |
| |
| // CefResourceRequestHandler methods: |
| CefRefPtr<CefResourceHandler> GetResourceHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); |
| 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(); |
| if (url == background_page_url_) { |
| EXPECT_FALSE(got_background_page_url_request_); |
| got_background_page_url_request_.yes(); |
| } else if (url == script_url_) { |
| EXPECT_FALSE(got_script_url_request_); |
| got_script_url_request_.yes(); |
| } else { |
| EXPECT_TRUE(false); // Not reached. |
| } |
| |
| // Handle the resource request. |
| return RoutingTestHandler::GetResourceHandler(browser, frame, request); |
| } |
| |
| CefRefPtr<CefExtension> extension() const { return extension_; } |
| |
| // Verify |extension| contents. |
| void VerifyExtension(CefRefPtr<CefExtension> extension) const { |
| EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(), |
| client::extension_util::GetInternalExtensionResourcePath( |
| extension->GetPath()) |
| .c_str()); |
| |
| CefRefPtr<CefDictionaryValue> expected_manifest = CreateManifest(); |
| TestDictionaryEqual(expected_manifest, extension->GetManifest()); |
| |
| VerifyExtensionInContext(extension, loader_request_context(), true, true); |
| if (!request_context_same_loader()) |
| VerifyExtensionInContext(extension, request_context(), true, false); |
| } |
| |
| std::string GetExtensionURL(CefRefPtr<CefExtension> extension, |
| const std::string& resource_path) const { |
| const std::string& identifier = extension->GetIdentifier(); |
| const std::string& origin = |
| client::extension_util::GetExtensionOrigin(identifier); |
| EXPECT_FALSE(origin.empty()); |
| return origin + resource_path; |
| } |
| |
| protected: |
| void OnLoadExtensions() override { |
| LoadExtension(kExtensionPath, CreateManifest()); |
| } |
| |
| bool OnMessage(CefRefPtr<CefBrowser> browser, |
| const std::string& message) override { |
| EXPECT_STREQ("extension_onload", message.c_str()); |
| EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); |
| |
| CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); |
| EXPECT_TRUE(extension); |
| EXPECT_TRUE(extension_->IsSame(extension)); |
| |
| EXPECT_TRUE(browser->IsSame(extension_browser_)); |
| EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); |
| |
| EXPECT_FALSE(got_body_onload_); |
| got_body_onload_.yes(); |
| |
| TriggerDestroyTestIfDone(); |
| return true; |
| } |
| |
| void OnDestroyTest() override { |
| extension_browser_ = nullptr; |
| |
| EXPECT_TRUE(got_loaded_); |
| EXPECT_TRUE(got_background_page_url_request_); |
| EXPECT_TRUE(got_script_url_request_); |
| EXPECT_TRUE(got_body_onload_); |
| EXPECT_TRUE(got_load_done_); |
| EXPECT_TRUE(got_unloaded_); |
| } |
| |
| // Create a manifest with background script. |
| CefRefPtr<CefDictionaryValue> CreateManifest() const { |
| CefRefPtr<CefDictionaryValue> manifest = |
| CreateDefaultManifest(ApiPermissionsList()); |
| |
| CefRefPtr<CefDictionaryValue> background = CefDictionaryValue::Create(); |
| CefRefPtr<CefListValue> scripts = CefListValue::Create(); |
| scripts->SetString(0, kBackgroundScript); |
| background->SetList("scripts", scripts); |
| manifest->SetDictionary("background", background); |
| |
| return manifest; |
| } |
| |
| void TriggerDestroyTestIfDone() { |
| if (got_body_onload_ && got_load_done_) { |
| TriggerDestroyTest(); |
| } |
| } |
| |
| virtual void TriggerDestroyTest() { |
| // Execute asynchronously so call stacks have a chance to unwind. |
| CefPostTask(TID_UI, |
| base::Bind(&BackgroundLoadUnloadTestHandler::UnloadExtension, |
| this, extension_)); |
| } |
| |
| CefRefPtr<CefExtension> extension_; |
| std::string script_url_; |
| std::string background_page_url_; |
| CefRefPtr<CefBrowser> extension_browser_; |
| |
| TrackCallback got_loaded_; |
| TrackCallback got_background_page_url_request_; |
| TrackCallback got_script_url_request_; |
| TrackCallback got_body_onload_; |
| TrackCallback got_load_done_; |
| TrackCallback got_unloaded_; |
| |
| IMPLEMENT_REFCOUNTING(BackgroundLoadUnloadTestHandler); |
| DISALLOW_COPY_AND_ASSIGN(BackgroundLoadUnloadTestHandler); |
| }; |
| |
| } // namespace |
| |
| EXTENSION_TEST_GROUP_ALL(BackgroundLoadUnload, BackgroundLoadUnloadTestHandler) |
| |
| namespace { |
| |
| // Same as above but without the unload. Only do this with a custom context to |
| // avoid poluting the global context. |
| class BackgroundLoadNoUnloadTestHandler |
| : public BackgroundLoadUnloadTestHandler { |
| public: |
| explicit BackgroundLoadNoUnloadTestHandler( |
| RequestContextType request_context_type) |
| : BackgroundLoadUnloadTestHandler(request_context_type) {} |
| |
| protected: |
| void TriggerDestroyTest() override { |
| // Release everything that references the request context. This should |
| // trigger unload of the extension. |
| CloseBrowser(extension_browser_, false); |
| extension_browser_ = nullptr; |
| ReleaseRequestContexts(); |
| } |
| }; |
| |
| } // namespace |
| |
| EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(BackgroundLoadNoUnload, |
| BackgroundLoadNoUnloadTestHandler) |