• 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 #include "tests/ceftests/test_util.h"
7 #include "tests/shared/browser/extension_util.h"
8 
9 #define ALARMS_TEST_GROUP_ALL(name, test_class) \
10   EXTENSION_TEST_GROUP_ALL(ChromeAlarms##name, test_class)
11 #define ALARMS_TEST_GROUP_MINIMAL(name, test_class) \
12   EXTENSION_TEST_GROUP_MINIMAL(ChromeAlarms##name, test_class)
13 
14 namespace {
15 
16 const char kExtensionPath[] = "alarms-extension";
17 const char kSuccessMessage[] = "success";
18 
19 // Base class for testing chrome.alarms methods.
20 // See https://developer.chrome.com/extensions/alarms
21 class AlarmsTestHandler : public ExtensionTestHandler {
22  public:
AlarmsTestHandler(RequestContextType request_context_type)23   explicit AlarmsTestHandler(RequestContextType request_context_type)
24       : ExtensionTestHandler(request_context_type) {
25     // Only creating the extension browser.
26     set_create_main_browser(false);
27   }
28 
29   // CefExtensionHandler methods:
OnExtensionLoaded(CefRefPtr<CefExtension> extension)30   void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
31     EXPECT_TRUE(CefCurrentlyOn(TID_UI));
32     EXPECT_FALSE(got_loaded_);
33     got_loaded_.yes();
34 
35     // Verify |extension| contents.
36     EXPECT_FALSE(extension->GetIdentifier().empty());
37     EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
38                  client::extension_util::GetInternalExtensionResourcePath(
39                      extension->GetPath())
40                      .c_str());
41     TestDictionaryEqual(CreateManifest(), extension->GetManifest());
42 
43     EXPECT_FALSE(extension_);
44     extension_ = extension;
45 
46     CreateBrowserForExtension();
47   }
48 
OnExtensionUnloaded(CefRefPtr<CefExtension> extension)49   void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
50     EXPECT_TRUE(CefCurrentlyOn(TID_UI));
51     EXPECT_TRUE(extension_);
52     EXPECT_TRUE(extension_->IsSame(extension));
53     EXPECT_FALSE(got_unloaded_);
54     got_unloaded_.yes();
55     extension_ = nullptr;
56 
57     // Execute asynchronously so call stacks have a chance to unwind.
58     // Will close the browser windows.
59     CefPostTask(TID_UI, base::BindOnce(&AlarmsTestHandler::DestroyTest, this));
60   }
61 
62   // CefLoadHandler methods:
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)63   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
64                             bool isLoading,
65                             bool canGoBack,
66                             bool canGoForward) override {
67     CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
68     EXPECT_TRUE(extension);
69     EXPECT_TRUE(extension_->IsSame(extension));
70 
71     if (isLoading) {
72       EXPECT_FALSE(extension_browser_);
73       extension_browser_ = browser;
74     } else {
75       EXPECT_TRUE(browser->IsSame(extension_browser_));
76 
77       const std::string& url = browser->GetMainFrame()->GetURL();
78       EXPECT_STREQ(extension_url_.c_str(), url.c_str());
79     }
80   }
81 
82   // CefResourceRequestHandler methods:
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)83   CefRefPtr<CefResourceHandler> GetResourceHandler(
84       CefRefPtr<CefBrowser> browser,
85       CefRefPtr<CefFrame> frame,
86       CefRefPtr<CefRequest> request) override {
87     EXPECT_TRUE(browser->IsSame(extension_browser_));
88 
89     CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
90     EXPECT_TRUE(extension);
91     EXPECT_TRUE(extension_->IsSame(extension));
92 
93     const std::string& url = request->GetURL();
94     EXPECT_STREQ(extension_url_.c_str(), url.c_str());
95 
96     EXPECT_FALSE(got_url_request_);
97     got_url_request_.yes();
98 
99     // Handle the resource request.
100     return RoutingTestHandler::GetResourceHandler(browser, frame, request);
101   }
102 
103  protected:
OnLoadExtensions()104   void OnLoadExtensions() override {
105     LoadExtension(kExtensionPath, CreateManifest());
106   }
107 
OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)108   bool OnMessage(CefRefPtr<CefBrowser> browser,
109                  const std::string& message) override {
110     if (message == "extension_onload") {
111       // From body onLoad in the extension browser.
112       EXPECT_TRUE(browser->IsSame(extension_browser_));
113       EXPECT_FALSE(got_body_onload_);
114       got_body_onload_.yes();
115       TriggerAlarmsApiJSFunction();
116       return true;
117     }
118     EXPECT_TRUE(browser->IsSame(extension_browser_));
119     EXPECT_FALSE(got_success_message_);
120     got_success_message_.yes();
121     EXPECT_STREQ(kSuccessMessage, message.c_str());
122     TriggerDestroyTest();
123     return true;
124   }
125 
OnDestroyTest()126   void OnDestroyTest() override {
127     extension_browser_ = nullptr;
128 
129     EXPECT_TRUE(got_loaded_);
130     EXPECT_TRUE(got_url_request_);
131     EXPECT_TRUE(got_body_onload_);
132     EXPECT_TRUE(got_trigger_api_function_);
133     EXPECT_TRUE(got_success_message_);
134     EXPECT_TRUE(got_unloaded_);
135   }
136 
137   // Create a manifest that grants access to the alarms API.
CreateManifest() const138   virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
139     ApiPermissionsList api_permissions;
140     api_permissions.push_back("alarms");
141     return CreateDefaultManifest(api_permissions);
142   }
143 
144   // Add resources in the extension browser.
OnAddExtensionResources(const std::string & origin)145   virtual void OnAddExtensionResources(const std::string& origin) {
146     extension_url_ = origin + "extension.html";
147     AddResource(extension_url_, GetExtensionHTML(), "text/html");
148   }
149 
150   // Returns the chrome.alarms.* JS that is executed in the extension browser
151   // when the triggerAlarmsApi() JS function is called.
152   virtual std::string GetAlarmsApiJS() const = 0;
153 
154   // Returns the JS that will be loaded in the extension browser. This
155   // implements the triggerAlarmsApi() JS function called from
156   // TriggerAlarmsApiJSFunction().
GetExtensionJS() const157   virtual std::string GetExtensionJS() const {
158     return "function triggerAlarmsApi() {" + GetAlarmsApiJS() + "}";
159   }
160 
161   // Returns the HTML that will be loaded in the extension browser.
GetExtensionHTML() const162   virtual std::string GetExtensionHTML() const {
163     return "<html><head><script>" + GetExtensionJS() +
164            "</script></head><body onLoad=" + GetMessageJS("extension_onload") +
165            ">Extension</body></html>";
166   }
167 
TriggerDestroyTest()168   virtual void TriggerDestroyTest() {
169     // Execute asynchronously so call stacks have a chance to unwind.
170     CefPostTask(TID_UI, base::BindOnce(&AlarmsTestHandler::UnloadExtension,
171                                        this, extension_));
172   }
173 
extension() const174   CefRefPtr<CefExtension> extension() const { return extension_; }
extension_url() const175   std::string extension_url() const { return extension_url_; }
extension_browser() const176   CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; }
177 
got_success_message() const178   bool got_success_message() const { return got_success_message_; }
179 
180  private:
CreateBrowserForExtension()181   void CreateBrowserForExtension() {
182     const std::string& identifier = extension_->GetIdentifier();
183     EXPECT_FALSE(identifier.empty());
184     const std::string& origin =
185         client::extension_util::GetExtensionOrigin(identifier);
186     EXPECT_FALSE(origin.empty());
187 
188     // Add extension resources.
189     OnAddExtensionResources(origin);
190 
191     // Create a browser to host the extension.
192     CreateBrowser(extension_url_, request_context());
193   }
194 
TriggerAlarmsApiJSFunction()195   void TriggerAlarmsApiJSFunction() {
196     EXPECT_FALSE(got_trigger_api_function_);
197     got_trigger_api_function_.yes();
198 
199     extension_browser_->GetMainFrame()->ExecuteJavaScript("triggerAlarmsApi();",
200                                                           extension_url_, 0);
201   }
202 
203   CefRefPtr<CefExtension> extension_;
204   std::string extension_url_;
205   CefRefPtr<CefBrowser> extension_browser_;
206 
207   TrackCallback got_loaded_;
208   TrackCallback got_url_request_;
209   TrackCallback got_body_onload_;
210   TrackCallback got_trigger_api_function_;
211   TrackCallback got_success_message_;
212   TrackCallback got_unloaded_;
213 };
214 }  // namespace
215 
216 namespace {
217 
218 // Test for chrome.alarms.create(string name, object alarmInfo)
219 // and chrome.alarms.onAlarm.addListener(function callback)
220 class CreateAlarmTestHandler : public AlarmsTestHandler {
221  public:
CreateAlarmTestHandler(RequestContextType request_context_type)222   explicit CreateAlarmTestHandler(RequestContextType request_context_type)
223       : AlarmsTestHandler(request_context_type) {}
224 
225  protected:
GetAlarmsApiJS() const226   std::string GetAlarmsApiJS() const override {
227     return "chrome.alarms.onAlarm.addListener(function (alarm) {" +
228            GetMessageJS(kSuccessMessage) +
229            "});"
230            "chrome.alarms.create(\"test\", {delayInMinutes:0.01})";
231   }
232 
233  private:
234   IMPLEMENT_REFCOUNTING(CreateAlarmTestHandler);
235   DISALLOW_COPY_AND_ASSIGN(CreateAlarmTestHandler);
236 };
237 }  // namespace
238 
239 ALARMS_TEST_GROUP_ALL(CreateAlarm, CreateAlarmTestHandler)
240 
241 namespace {
242 
243 // Test for chrome.alarms.get(string name, function callback)
244 class GetAlarmTestHandler : public AlarmsTestHandler {
245  public:
GetAlarmTestHandler(RequestContextType request_context_type)246   explicit GetAlarmTestHandler(RequestContextType request_context_type)
247       : AlarmsTestHandler(request_context_type) {}
248 
249  protected:
GetAlarmsApiJS() const250   std::string GetAlarmsApiJS() const override {
251     return "chrome.alarms.create(\"test\", {delayInMinutes:1});"
252            "setTimeout(function() {"
253            "chrome.alarms.get(\"test\", function (alarm) {" +
254            GetMessageJS(kSuccessMessage) + "})}, 100)";
255   }
256 
257  private:
258   IMPLEMENT_REFCOUNTING(GetAlarmTestHandler);
259   DISALLOW_COPY_AND_ASSIGN(GetAlarmTestHandler);
260 };
261 }  // namespace
262 
263 ALARMS_TEST_GROUP_MINIMAL(GetAlarm, GetAlarmTestHandler)
264 
265 namespace {
266 
267 // Test for chrome.alarms.getAll(function callback)
268 class GetAllAlarmsTestHandler : public AlarmsTestHandler {
269  public:
GetAllAlarmsTestHandler(RequestContextType request_context_type)270   explicit GetAllAlarmsTestHandler(RequestContextType request_context_type)
271       : AlarmsTestHandler(request_context_type) {}
272 
273  protected:
GetAlarmsApiJS() const274   std::string GetAlarmsApiJS() const override {
275     return "chrome.alarms.create(\"alarm1\", {delayInMinutes:1});"
276            "chrome.alarms.create(\"alarm2\", {delayInMinutes:1});"
277            "setTimeout(function() {"
278            "chrome.alarms.getAll(function (alarms) {"
279            "if (alarms.length == 2) {" +
280            GetMessageJS(kSuccessMessage) + "}})}, 100)";
281   }
282 
283  private:
284   IMPLEMENT_REFCOUNTING(GetAllAlarmsTestHandler);
285   DISALLOW_COPY_AND_ASSIGN(GetAllAlarmsTestHandler);
286 };
287 }  // namespace
288 
289 ALARMS_TEST_GROUP_MINIMAL(GetAllAlarms, GetAllAlarmsTestHandler)
290 
291 namespace {
292 
293 // Test for chrome.alarms.clear(string name, function callback)
294 class ClearAlarmTestHandler : public AlarmsTestHandler {
295  public:
ClearAlarmTestHandler(RequestContextType request_context_type)296   explicit ClearAlarmTestHandler(RequestContextType request_context_type)
297       : AlarmsTestHandler(request_context_type) {}
298 
299  protected:
GetAlarmsApiJS() const300   std::string GetAlarmsApiJS() const override {
301     return "chrome.alarms.create(\"test\", {delayInMinutes:1});"
302            "setTimeout(function() {"
303            "chrome.alarms.clear(\"test\", function (wasCleared) {"
304            "if (wasCleared) {" +
305            GetMessageJS(kSuccessMessage) + "}})}, 100)";
306   }
307 
308  private:
309   IMPLEMENT_REFCOUNTING(ClearAlarmTestHandler);
310   DISALLOW_COPY_AND_ASSIGN(ClearAlarmTestHandler);
311 };
312 }  // namespace
313 
314 ALARMS_TEST_GROUP_MINIMAL(ClearAlarm, ClearAlarmTestHandler)
315 
316 namespace {
317 
318 // Test for chrome.alarms.clearAll(function callback)
319 class ClearAllAlarmsTestHandler : public AlarmsTestHandler {
320  public:
ClearAllAlarmsTestHandler(RequestContextType request_context_type)321   explicit ClearAllAlarmsTestHandler(RequestContextType request_context_type)
322       : AlarmsTestHandler(request_context_type) {}
323 
324  protected:
GetAlarmsApiJS() const325   std::string GetAlarmsApiJS() const override {
326     return "chrome.alarms.create(\"alarm1\", {delayInMinutes:1});"
327            "chrome.alarms.create(\"alarm2\", {delayInMinutes:1});"
328            "setTimeout(function() {"
329            "chrome.alarms.clearAll(function (wasCleared) {"
330            "if (wasCleared) {" +
331            GetMessageJS(kSuccessMessage) + "}})}, 100)";
332   }
333 
334  private:
335   IMPLEMENT_REFCOUNTING(ClearAllAlarmsTestHandler);
336   DISALLOW_COPY_AND_ASSIGN(ClearAllAlarmsTestHandler);
337 };
338 }  // namespace
339 
340 ALARMS_TEST_GROUP_MINIMAL(ClearAllAlarms, ClearAllAlarmsTestHandler)
341