1 // Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #include "tests/ceftests/extensions/extension_test_handler.h" 6 7 #include "tests/ceftests/test_util.h" 8 #include "tests/shared/browser/client_app_browser.h" 9 #include "tests/shared/browser/extension_util.h" 10 11 using client::ClientAppBrowser; 12 13 namespace { 14 15 const char kExtensionPath[] = "background-extension"; 16 const char kBackgroundScript[] = "background.js"; 17 // HTML file created internally to load the background script. 18 const char kGeneratedBackgroundPage[] = "_generated_background_page.html"; 19 20 // Test load/unload of an extension with a background script. 21 class BackgroundLoadUnloadTestHandler : public ExtensionTestHandler { 22 public: BackgroundLoadUnloadTestHandler(RequestContextType request_context_type)23 explicit BackgroundLoadUnloadTestHandler( 24 RequestContextType request_context_type) 25 : ExtensionTestHandler(request_context_type) { 26 // Only creating the extension browser. 27 set_create_main_browser(false); 28 } 29 30 // CefExtensionHandler methods: OnExtensionLoaded(CefRefPtr<CefExtension> extension)31 void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override { 32 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 33 EXPECT_TRUE(extension); 34 EXPECT_TRUE(extension->IsLoaded()); 35 EXPECT_TRUE(extension->GetLoaderContext()); 36 EXPECT_TRUE( 37 loader_request_context()->IsSame(extension->GetLoaderContext())); 38 VerifyExtension(extension); 39 40 EXPECT_FALSE(got_loaded_); 41 got_loaded_.yes(); 42 43 EXPECT_FALSE(extension_); 44 extension_ = extension; 45 46 background_page_url_ = GetExtensionURL(extension, kGeneratedBackgroundPage); 47 48 // Add extension resources. 49 script_url_ = GetExtensionURL(extension, kBackgroundScript); 50 AddResource(script_url_, GetMessageJS("extension_onload"), 51 "text/javascript"); 52 } 53 OnExtensionUnloaded(CefRefPtr<CefExtension> extension)54 void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override { 55 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 56 EXPECT_TRUE(extension); 57 EXPECT_FALSE(extension->IsLoaded()); 58 EXPECT_FALSE(extension->GetLoaderContext()); 59 60 EXPECT_FALSE(got_unloaded_); 61 got_unloaded_.yes(); 62 63 EXPECT_TRUE(extension_); 64 EXPECT_TRUE(extension_->IsSame(extension)); 65 66 // The extension should no longer be registered with the context. 67 if (loader_request_context()) 68 VerifyExtensionInContext(extension, loader_request_context(), false, 69 true); 70 if (request_context() && !request_context_same_loader()) 71 VerifyExtensionInContext(extension, request_context(), false, false); 72 73 extension_ = nullptr; 74 75 // Execute asynchronously so call stacks have a chance to unwind. 76 // Will close the browser windows. 77 CefPostTask( 78 TID_UI, 79 base::BindOnce(&BackgroundLoadUnloadTestHandler::DestroyTest, this)); 80 } 81 OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension,const CefString & url,CefRefPtr<CefClient> & client,CefBrowserSettings & settings)82 bool OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension, 83 const CefString& url, 84 CefRefPtr<CefClient>& client, 85 CefBrowserSettings& settings) override { 86 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 87 EXPECT_TRUE(extension); 88 EXPECT_TRUE(extension->IsLoaded()); 89 EXPECT_TRUE(extension->GetLoaderContext()); 90 EXPECT_TRUE( 91 loader_request_context()->IsSame(extension->GetLoaderContext())); 92 VerifyExtension(extension); 93 94 const std::string& background_page_url = 95 GetExtensionURL(extension, kGeneratedBackgroundPage); 96 EXPECT_STREQ(background_page_url.c_str(), url.ToString().c_str()); 97 98 EXPECT_FALSE(client); 99 client = this; 100 101 // Allow the browser creation. 102 return false; 103 } 104 105 // CefLoadHandler methods: OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)106 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, 107 bool isLoading, 108 bool canGoBack, 109 bool canGoForward) override { 110 EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); 111 112 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 113 EXPECT_TRUE(extension); 114 EXPECT_TRUE(extension_->IsSame(extension)); 115 116 if (isLoading) { 117 EXPECT_FALSE(extension_browser_); 118 extension_browser_ = browser; 119 } else { 120 EXPECT_TRUE(browser->IsSame(extension_browser_)); 121 122 const std::string& url = browser->GetMainFrame()->GetURL(); 123 EXPECT_STREQ(background_page_url_.c_str(), url.c_str()); 124 125 EXPECT_FALSE(got_load_done_); 126 got_load_done_.yes(); 127 128 TriggerDestroyTestIfDone(); 129 } 130 } 131 132 // CefResourceRequestHandler methods: GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)133 CefRefPtr<CefResourceHandler> GetResourceHandler( 134 CefRefPtr<CefBrowser> browser, 135 CefRefPtr<CefFrame> frame, 136 CefRefPtr<CefRequest> request) override { 137 EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); 138 EXPECT_TRUE(browser->IsSame(extension_browser_)); 139 140 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 141 EXPECT_TRUE(extension); 142 EXPECT_TRUE(extension_->IsSame(extension)); 143 144 const std::string& url = request->GetURL(); 145 if (url == background_page_url_) { 146 EXPECT_FALSE(got_background_page_url_request_); 147 got_background_page_url_request_.yes(); 148 } else if (url == script_url_) { 149 EXPECT_FALSE(got_script_url_request_); 150 got_script_url_request_.yes(); 151 } else { 152 EXPECT_TRUE(false); // Not reached. 153 } 154 155 // Handle the resource request. 156 return RoutingTestHandler::GetResourceHandler(browser, frame, request); 157 } 158 extension() const159 CefRefPtr<CefExtension> extension() const { return extension_; } 160 161 // Verify |extension| contents. VerifyExtension(CefRefPtr<CefExtension> extension) const162 void VerifyExtension(CefRefPtr<CefExtension> extension) const { 163 EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(), 164 client::extension_util::GetInternalExtensionResourcePath( 165 extension->GetPath()) 166 .c_str()); 167 168 CefRefPtr<CefDictionaryValue> expected_manifest = CreateManifest(); 169 TestDictionaryEqual(expected_manifest, extension->GetManifest()); 170 171 VerifyExtensionInContext(extension, loader_request_context(), true, true); 172 if (!request_context_same_loader()) 173 VerifyExtensionInContext(extension, request_context(), true, false); 174 } 175 GetExtensionURL(CefRefPtr<CefExtension> extension,const std::string & resource_path) const176 std::string GetExtensionURL(CefRefPtr<CefExtension> extension, 177 const std::string& resource_path) const { 178 const std::string& identifier = extension->GetIdentifier(); 179 const std::string& origin = 180 client::extension_util::GetExtensionOrigin(identifier); 181 EXPECT_FALSE(origin.empty()); 182 return origin + resource_path; 183 } 184 185 protected: OnLoadExtensions()186 void OnLoadExtensions() override { 187 LoadExtension(kExtensionPath, CreateManifest()); 188 } 189 OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)190 bool OnMessage(CefRefPtr<CefBrowser> browser, 191 const std::string& message) override { 192 EXPECT_STREQ("extension_onload", message.c_str()); 193 EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); 194 195 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 196 EXPECT_TRUE(extension); 197 EXPECT_TRUE(extension_->IsSame(extension)); 198 199 EXPECT_TRUE(browser->IsSame(extension_browser_)); 200 EXPECT_TRUE(browser->GetHost()->IsBackgroundHost()); 201 202 EXPECT_FALSE(got_body_onload_); 203 got_body_onload_.yes(); 204 205 TriggerDestroyTestIfDone(); 206 return true; 207 } 208 OnDestroyTest()209 void OnDestroyTest() override { 210 extension_browser_ = nullptr; 211 212 EXPECT_TRUE(got_loaded_); 213 EXPECT_TRUE(got_background_page_url_request_); 214 EXPECT_TRUE(got_script_url_request_); 215 EXPECT_TRUE(got_body_onload_); 216 EXPECT_TRUE(got_load_done_); 217 EXPECT_TRUE(got_unloaded_); 218 } 219 220 // Create a manifest with background script. CreateManifest() const221 CefRefPtr<CefDictionaryValue> CreateManifest() const { 222 CefRefPtr<CefDictionaryValue> manifest = 223 CreateDefaultManifest(ApiPermissionsList()); 224 225 CefRefPtr<CefDictionaryValue> background = CefDictionaryValue::Create(); 226 CefRefPtr<CefListValue> scripts = CefListValue::Create(); 227 scripts->SetString(0, kBackgroundScript); 228 background->SetList("scripts", scripts); 229 manifest->SetDictionary("background", background); 230 231 return manifest; 232 } 233 TriggerDestroyTestIfDone()234 void TriggerDestroyTestIfDone() { 235 if (got_body_onload_ && got_load_done_) { 236 TriggerDestroyTest(); 237 } 238 } 239 TriggerDestroyTest()240 virtual void TriggerDestroyTest() { 241 // Execute asynchronously so call stacks have a chance to unwind. 242 CefPostTask(TID_UI, base::BindOnce( 243 &BackgroundLoadUnloadTestHandler::UnloadExtension, 244 this, extension_)); 245 } 246 247 CefRefPtr<CefExtension> extension_; 248 std::string script_url_; 249 std::string background_page_url_; 250 CefRefPtr<CefBrowser> extension_browser_; 251 252 TrackCallback got_loaded_; 253 TrackCallback got_background_page_url_request_; 254 TrackCallback got_script_url_request_; 255 TrackCallback got_body_onload_; 256 TrackCallback got_load_done_; 257 TrackCallback got_unloaded_; 258 259 IMPLEMENT_REFCOUNTING(BackgroundLoadUnloadTestHandler); 260 DISALLOW_COPY_AND_ASSIGN(BackgroundLoadUnloadTestHandler); 261 }; 262 263 } // namespace 264 265 EXTENSION_TEST_GROUP_ALL(BackgroundLoadUnload, BackgroundLoadUnloadTestHandler) 266 267 namespace { 268 269 // Same as above but without the unload. Only do this with a custom context to 270 // avoid poluting the global context. 271 class BackgroundLoadNoUnloadTestHandler 272 : public BackgroundLoadUnloadTestHandler { 273 public: BackgroundLoadNoUnloadTestHandler(RequestContextType request_context_type)274 explicit BackgroundLoadNoUnloadTestHandler( 275 RequestContextType request_context_type) 276 : BackgroundLoadUnloadTestHandler(request_context_type) {} 277 278 protected: TriggerDestroyTest()279 void TriggerDestroyTest() override { 280 // Release everything that references the request context. This should 281 // trigger unload of the extension. 282 CloseBrowser(extension_browser_, false); 283 extension_browser_ = nullptr; 284 ReleaseRequestContexts(); 285 } 286 }; 287 288 } // namespace 289 290 EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(BackgroundLoadNoUnload, 291 BackgroundLoadNoUnloadTestHandler) 292