• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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