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/extension_util.h" 9 10 namespace { 11 12 const char kExtensionPath[] = "view-extension"; 13 14 // Test extension load/unload. 15 class ViewLoadUnloadTestHandler : public ExtensionTestHandler { 16 public: ViewLoadUnloadTestHandler(RequestContextType request_context_type)17 explicit ViewLoadUnloadTestHandler(RequestContextType request_context_type) 18 : ExtensionTestHandler(request_context_type) { 19 // Only creating the extension browser. 20 set_create_main_browser(false); 21 } 22 23 // CefExtensionHandler methods: OnExtensionLoaded(CefRefPtr<CefExtension> extension)24 void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override { 25 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 26 EXPECT_TRUE(extension); 27 EXPECT_TRUE(extension->IsLoaded()); 28 EXPECT_TRUE(extension->GetLoaderContext()); 29 EXPECT_TRUE( 30 loader_request_context()->IsSame(extension->GetLoaderContext())); 31 VerifyExtension(extension); 32 33 EXPECT_FALSE(got_loaded_); 34 got_loaded_.yes(); 35 36 EXPECT_FALSE(extension_); 37 extension_ = extension; 38 39 CreateBrowserForExtension(); 40 } 41 OnExtensionUnloaded(CefRefPtr<CefExtension> extension)42 void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override { 43 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 44 EXPECT_TRUE(extension); 45 EXPECT_FALSE(extension->IsLoaded()); 46 EXPECT_FALSE(extension->GetLoaderContext()); 47 48 EXPECT_FALSE(got_unloaded_); 49 got_unloaded_.yes(); 50 51 EXPECT_TRUE(extension_); 52 EXPECT_TRUE(extension_->IsSame(extension)); 53 54 // The extension should no longer be registered with the context. 55 if (loader_request_context()) 56 VerifyExtensionInContext(extension, loader_request_context(), false, 57 true); 58 if (request_context() && !request_context_same_loader()) 59 VerifyExtensionInContext(extension, request_context(), false, false); 60 61 extension_ = nullptr; 62 63 // Execute asynchronously so call stacks have a chance to unwind. 64 // Will close the browser windows. 65 CefPostTask(TID_UI, 66 base::BindOnce(&ViewLoadUnloadTestHandler::DestroyTest, this)); 67 } 68 69 // CefLoadHandler methods: OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)70 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, 71 bool isLoading, 72 bool canGoBack, 73 bool canGoForward) override { 74 EXPECT_FALSE(browser->GetHost()->IsBackgroundHost()); 75 76 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 77 EXPECT_TRUE(extension); 78 EXPECT_TRUE(extension_->IsSame(extension)); 79 80 if (isLoading) { 81 EXPECT_FALSE(extension_browser_); 82 extension_browser_ = browser; 83 } else { 84 EXPECT_TRUE(browser->IsSame(extension_browser_)); 85 86 const std::string& url = browser->GetMainFrame()->GetURL(); 87 EXPECT_STREQ(extension_url_.c_str(), url.c_str()); 88 89 EXPECT_FALSE(got_load_done_); 90 got_load_done_.yes(); 91 92 TriggerDestroyTestIfDone(); 93 } 94 } 95 96 // CefResourceRequestHandler methods: GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)97 CefRefPtr<CefResourceHandler> GetResourceHandler( 98 CefRefPtr<CefBrowser> browser, 99 CefRefPtr<CefFrame> frame, 100 CefRefPtr<CefRequest> request) override { 101 EXPECT_FALSE(browser->GetHost()->IsBackgroundHost()); 102 EXPECT_TRUE(browser->IsSame(extension_browser_)); 103 104 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 105 EXPECT_TRUE(extension); 106 EXPECT_TRUE(extension_->IsSame(extension)); 107 108 const std::string& url = request->GetURL(); 109 EXPECT_STREQ(extension_url_.c_str(), url.c_str()); 110 111 EXPECT_FALSE(got_url_request_); 112 got_url_request_.yes(); 113 114 // Handle the resource request. 115 return RoutingTestHandler::GetResourceHandler(browser, frame, request); 116 } 117 118 protected: OnLoadExtensions()119 void OnLoadExtensions() override { 120 LoadExtension(kExtensionPath, CreateManifest()); 121 } 122 OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)123 bool OnMessage(CefRefPtr<CefBrowser> browser, 124 const std::string& message) override { 125 EXPECT_FALSE(browser->GetHost()->IsBackgroundHost()); 126 EXPECT_STREQ("extension_onload", message.c_str()); 127 128 CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); 129 EXPECT_TRUE(extension); 130 EXPECT_TRUE(extension_->IsSame(extension)); 131 132 EXPECT_TRUE(browser->IsSame(extension_browser_)); 133 134 EXPECT_FALSE(got_body_onload_); 135 got_body_onload_.yes(); 136 137 TriggerDestroyTestIfDone(); 138 return true; 139 } 140 OnDestroyTest()141 void OnDestroyTest() override { 142 extension_browser_ = nullptr; 143 144 EXPECT_TRUE(got_loaded_); 145 EXPECT_TRUE(got_url_request_); 146 EXPECT_TRUE(got_body_onload_); 147 EXPECT_TRUE(got_load_done_); 148 EXPECT_TRUE(got_unloaded_); 149 } 150 151 // Create the default manifest. CreateManifest() const152 CefRefPtr<CefDictionaryValue> CreateManifest() const { 153 return CreateDefaultManifest(ApiPermissionsList()); 154 } 155 156 // Verify |extension| contents. VerifyExtension(CefRefPtr<CefExtension> extension) const157 void VerifyExtension(CefRefPtr<CefExtension> extension) const { 158 EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(), 159 client::extension_util::GetInternalExtensionResourcePath( 160 extension->GetPath()) 161 .c_str()); 162 163 CefRefPtr<CefDictionaryValue> expected_manifest = CreateManifest(); 164 TestDictionaryEqual(expected_manifest, extension->GetManifest()); 165 166 VerifyExtensionInContext(extension, loader_request_context(), true, true); 167 if (!request_context_same_loader()) 168 VerifyExtensionInContext(extension, request_context(), true, false); 169 } 170 CreateBrowserForExtension()171 void CreateBrowserForExtension() { 172 const std::string& identifier = extension_->GetIdentifier(); 173 EXPECT_FALSE(identifier.empty()); 174 const std::string& origin = 175 client::extension_util::GetExtensionOrigin(identifier); 176 EXPECT_FALSE(origin.empty()); 177 178 // Add extension resources. 179 extension_url_ = origin + "extension.html"; 180 AddResource(extension_url_, 181 "<html><body onLoad=" + GetMessageJS("extension_onload") + 182 ">Extension</body></html>", 183 "text/html"); 184 185 // Create a browser to host the extension. 186 CreateBrowser(extension_url_, request_context()); 187 } 188 TriggerDestroyTestIfDone()189 void TriggerDestroyTestIfDone() { 190 if (got_body_onload_ && got_load_done_) { 191 TriggerDestroyTest(); 192 } 193 } 194 TriggerDestroyTest()195 virtual void TriggerDestroyTest() { 196 // Execute asynchronously so call stacks have a chance to unwind. 197 CefPostTask(TID_UI, 198 base::BindOnce(&ViewLoadUnloadTestHandler::UnloadExtension, 199 this, extension_)); 200 } 201 202 CefRefPtr<CefExtension> extension_; 203 std::string extension_url_; 204 CefRefPtr<CefBrowser> extension_browser_; 205 206 TrackCallback got_loaded_; 207 TrackCallback got_url_request_; 208 TrackCallback got_body_onload_; 209 TrackCallback got_load_done_; 210 TrackCallback got_unloaded_; 211 212 IMPLEMENT_REFCOUNTING(ViewLoadUnloadTestHandler); 213 DISALLOW_COPY_AND_ASSIGN(ViewLoadUnloadTestHandler); 214 }; 215 216 } // namespace 217 218 EXTENSION_TEST_GROUP_ALL(ViewLoadUnload, ViewLoadUnloadTestHandler) 219 220 namespace { 221 222 // Same as above but without the unload. Only do this with a custom context to 223 // avoid poluting the global context. 224 class ViewLoadNoUnloadTestHandler : public ViewLoadUnloadTestHandler { 225 public: ViewLoadNoUnloadTestHandler(RequestContextType request_context_type)226 explicit ViewLoadNoUnloadTestHandler(RequestContextType request_context_type) 227 : ViewLoadUnloadTestHandler(request_context_type) {} 228 229 protected: TriggerDestroyTest()230 void TriggerDestroyTest() override { 231 // Release everything that references the request context. This should 232 // trigger unload of the extension. 233 CloseBrowser(extension_browser_, false); 234 extension_browser_ = nullptr; 235 ReleaseRequestContexts(); 236 } 237 }; 238 239 } // namespace 240 241 EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(ViewLoadNoUnload, 242 ViewLoadNoUnloadTestHandler) 243