• 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 STORAGE_TEST_GROUP_ALL(name, test_class) \
10   EXTENSION_TEST_GROUP_ALL(ChromeStorage##name, test_class)
11 #define STORAGE_TEST_GROUP_MINIMAL(name, test_class) \
12   EXTENSION_TEST_GROUP_MINIMAL(ChromeStorage##name, test_class)
13 
14 namespace {
15 
16 const char kExtensionPath[] = "storage-extension";
17 const char kSuccessMessage[] = "success";
18 
19 // Base class for testing chrome.storage methods.
20 // See https://developer.chrome.com/extensions/storage
21 class StorageTestHandler : public ExtensionTestHandler {
22  public:
StorageTestHandler(RequestContextType request_context_type)23   explicit StorageTestHandler(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(&StorageTestHandler::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       TriggerStorageApiJSFunction();
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 storage API.
CreateManifest() const138   virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
139     ApiPermissionsList api_permissions;
140     api_permissions.push_back("storage");
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.storage.* JS that is executed in the extension browser
151   // when the triggerStorageApi() JS function is called.
152   virtual std::string GetStorageApiJS() const = 0;
153 
154   // Returns the JS that will be loaded in the extension browser. This
155   // implements the triggerStorageApi() JS function called from
156   // TriggerStorageApiJSFunction().
GetExtensionJS() const157   virtual std::string GetExtensionJS() const {
158     return "function triggerStorageApi() {" + GetStorageApiJS() + "}";
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(&StorageTestHandler::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 
TriggerStorageApiJSFunction()195   void TriggerStorageApiJSFunction() {
196     EXPECT_FALSE(got_trigger_api_function_);
197     got_trigger_api_function_.yes();
198 
199     extension_browser_->GetMainFrame()->ExecuteJavaScript(
200         "triggerStorageApi();", 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.storage.local.set(object items, function callback)
219 // and  for chrome.storage.local.get(string or array of string or object keys,
220 //                                   function callback)
221 class LocalStorageTestHandler : public StorageTestHandler {
222  public:
LocalStorageTestHandler(RequestContextType request_context_type)223   explicit LocalStorageTestHandler(RequestContextType request_context_type)
224       : StorageTestHandler(request_context_type) {}
225 
226  protected:
GetStorageApiJS() const227   std::string GetStorageApiJS() const override {
228     return "chrome.storage.local.set({\"local_key_1\": \"local_value_1\"}, "
229            "function() {"
230            "chrome.storage.local.get(\"local_key_1\", function (items) {"
231            "if(items[\"local_key_1\"] == \"local_value_1\") {" +
232            GetMessageJS(kSuccessMessage) +
233            "}});"
234            "});";
235   }
236 
237  private:
238   IMPLEMENT_REFCOUNTING(LocalStorageTestHandler);
239   DISALLOW_COPY_AND_ASSIGN(LocalStorageTestHandler);
240 };
241 }  // namespace
242 
243 STORAGE_TEST_GROUP_ALL(LocalStorage, LocalStorageTestHandler)
244 
245 namespace {
246 
247 // Test for chrome.storage.local.getBytesInUse(string or array of string keys,
248 //                                             function callback)
249 class LocalStorageGetBytesInUseTestHandler : public StorageTestHandler {
250  public:
LocalStorageGetBytesInUseTestHandler(RequestContextType request_context_type)251   explicit LocalStorageGetBytesInUseTestHandler(
252       RequestContextType request_context_type)
253       : StorageTestHandler(request_context_type) {}
254 
255  protected:
GetStorageApiJS() const256   std::string GetStorageApiJS() const override {
257     return "chrome.storage.local.set({\"local_key_2\": \"local_value_2\"}, "
258            "function() {"
259            "chrome.storage.local.getBytesInUse(\"local_key_2\", function "
260            "(bytesInUse) {"
261            "if (bytesInUse == 26) {" +
262            GetMessageJS(kSuccessMessage) +
263            "}});"
264            "});";
265   }
266 
267  private:
268   IMPLEMENT_REFCOUNTING(LocalStorageGetBytesInUseTestHandler);
269   DISALLOW_COPY_AND_ASSIGN(LocalStorageGetBytesInUseTestHandler);
270 };
271 }  // namespace
272 
273 STORAGE_TEST_GROUP_MINIMAL(LocalStorageGetBytesInUse,
274                            LocalStorageGetBytesInUseTestHandler)
275 
276 namespace {
277 
278 // Test for chrome.storage.local.remove(string or array of string keys, function
279 // callback)
280 class LocalStorageRemoveTestHandler : public StorageTestHandler {
281  public:
LocalStorageRemoveTestHandler(RequestContextType request_context_type)282   explicit LocalStorageRemoveTestHandler(
283       RequestContextType request_context_type)
284       : StorageTestHandler(request_context_type) {}
285 
286  protected:
GetStorageApiJS() const287   std::string GetStorageApiJS() const override {
288     return "chrome.storage.local.set({\"local_key_3\": \"local_value_3\"}, "
289            "function() {"
290            "chrome.storage.local.remove(\"local_key_3\", function () {"
291            "chrome.storage.local.get(\"local_key_3\", function(items) {"
292            "if (items[\"local_key_3\"] == undefined) {" +
293            GetMessageJS(kSuccessMessage) +
294            "}})})"
295            "});";
296   }
297 
298  private:
299   IMPLEMENT_REFCOUNTING(LocalStorageRemoveTestHandler);
300   DISALLOW_COPY_AND_ASSIGN(LocalStorageRemoveTestHandler);
301 };
302 }  // namespace
303 
304 STORAGE_TEST_GROUP_MINIMAL(LocalStorageRemove, LocalStorageRemoveTestHandler)
305 
306 namespace {
307 
308 // Test for chrome.storage.local.clear(function callback)
309 class LocalStorageClearTestHandler : public StorageTestHandler {
310  public:
LocalStorageClearTestHandler(RequestContextType request_context_type)311   explicit LocalStorageClearTestHandler(RequestContextType request_context_type)
312       : StorageTestHandler(request_context_type) {}
313 
314  protected:
GetStorageApiJS() const315   std::string GetStorageApiJS() const override {
316     return "var value1Cleared = false;"
317            "var value2Cleared = false;"
318            "function checkCleared() {"
319            "if (value1Cleared && value2Cleared) {" +
320            GetMessageJS(kSuccessMessage) +
321            "}}"
322            "chrome.storage.local.set({\"local_key_4\": \"local_value_4\","
323            "\"local_key_5\": \"local_value_5\"}, function() {"
324            "chrome.storage.local.clear(function () {"
325 
326            "chrome.storage.local.get(\"local_key_4\", function(items) {"
327            "if (items[\"local_key_4\"] == undefined) {"
328            "value1Cleared = true;"
329            "checkCleared();"
330            "}});"
331 
332            "chrome.storage.local.get(\"local_key_5\", function(items) {"
333            "if (items[\"local_key_5\"] == undefined) {"
334            "value2Cleared = true;"
335            "checkCleared();"
336            "}});"
337            "})});";
338   }
339 
340  private:
341   IMPLEMENT_REFCOUNTING(LocalStorageClearTestHandler);
342   DISALLOW_COPY_AND_ASSIGN(LocalStorageClearTestHandler);
343 };
344 }  // namespace
345 
346 STORAGE_TEST_GROUP_MINIMAL(LocalStorageClear, LocalStorageClearTestHandler)
347 
348 namespace {
349 
350 // Test for chrome.storage.sync.set(object items, function callback)
351 // and  for chrome.storage.sync.get(string or array of string or object keys,
352 //                                   function callback)
353 class SyncStorageTestHandler : public StorageTestHandler {
354  public:
SyncStorageTestHandler(RequestContextType request_context_type)355   explicit SyncStorageTestHandler(RequestContextType request_context_type)
356       : StorageTestHandler(request_context_type) {}
357 
358  protected:
GetStorageApiJS() const359   std::string GetStorageApiJS() const override {
360     return "chrome.storage.sync.set({\"sync_key_1\": \"sync_value_1\"}, "
361            "function() {"
362            "chrome.storage.sync.get(\"sync_key_1\", function (items) {"
363            "if (items[\"sync_key_1\"] == \"sync_value_1\") {" +
364            GetMessageJS(kSuccessMessage) +
365            "}});"
366            "});";
367   }
368 
369  private:
370   IMPLEMENT_REFCOUNTING(SyncStorageTestHandler);
371   DISALLOW_COPY_AND_ASSIGN(SyncStorageTestHandler);
372 };
373 }  // namespace
374 
375 STORAGE_TEST_GROUP_ALL(SyncStorage, SyncStorageTestHandler)
376 
377 namespace {
378 
379 // Test for chrome.storage.sync.getBytesInUse(string or array of string keys,
380 //                                             function callback)
381 class SyncStorageGetBytesInUseTestHandler : public StorageTestHandler {
382  public:
SyncStorageGetBytesInUseTestHandler(RequestContextType request_context_type)383   explicit SyncStorageGetBytesInUseTestHandler(
384       RequestContextType request_context_type)
385       : StorageTestHandler(request_context_type) {}
386 
387  protected:
GetStorageApiJS() const388   std::string GetStorageApiJS() const override {
389     return "chrome.storage.sync.set({\"sync_key_2\": \"sync_value_2\"}, "
390            "function() {"
391            "chrome.storage.sync.getBytesInUse(\"sync_key_2\", function "
392            "(bytesInUse) {"
393            "if (bytesInUse == 24) {" +
394            GetMessageJS(kSuccessMessage) +
395            "}});"
396            "});";
397   }
398 
399  private:
400   IMPLEMENT_REFCOUNTING(SyncStorageGetBytesInUseTestHandler);
401   DISALLOW_COPY_AND_ASSIGN(SyncStorageGetBytesInUseTestHandler);
402 };
403 }  // namespace
404 
405 STORAGE_TEST_GROUP_MINIMAL(SyncStorageGetBytesInUse,
406                            SyncStorageGetBytesInUseTestHandler)
407 
408 namespace {
409 
410 // Test for chrome.storage.sync.remove(string or array of string keys, function
411 // callback)
412 class SyncStorageRemoveTestHandler : public StorageTestHandler {
413  public:
SyncStorageRemoveTestHandler(RequestContextType request_context_type)414   explicit SyncStorageRemoveTestHandler(RequestContextType request_context_type)
415       : StorageTestHandler(request_context_type) {}
416 
417  protected:
GetStorageApiJS() const418   std::string GetStorageApiJS() const override {
419     return "chrome.storage.sync.set({\"sync_key_3\": \"sync_value_3\"}, "
420            "function() {"
421            "chrome.storage.sync.remove(\"sync_key_3\", function () {"
422            "chrome.storage.sync.get(\"sync_key_3\", function(items) {"
423            "if (items[\"sync_key_3\"] == undefined) {" +
424            GetMessageJS(kSuccessMessage) +
425            "}})})"
426            "});";
427   }
428 
429  private:
430   IMPLEMENT_REFCOUNTING(SyncStorageRemoveTestHandler);
431   DISALLOW_COPY_AND_ASSIGN(SyncStorageRemoveTestHandler);
432 };
433 }  // namespace
434 
435 STORAGE_TEST_GROUP_MINIMAL(SyncStorageRemove, SyncStorageRemoveTestHandler)
436 
437 namespace {
438 
439 // Test for chrome.storage.sync.clear(function callback)
440 class SyncStorageClearTestHandler : public StorageTestHandler {
441  public:
SyncStorageClearTestHandler(RequestContextType request_context_type)442   explicit SyncStorageClearTestHandler(RequestContextType request_context_type)
443       : StorageTestHandler(request_context_type) {}
444 
445  protected:
GetStorageApiJS() const446   std::string GetStorageApiJS() const override {
447     return "var value1Cleared = false;"
448            "var value2Cleared = false;"
449 
450            "function checkCleared() {"
451            "if (value1Cleared && value2Cleared) {" +
452            GetMessageJS(kSuccessMessage) +
453            "}}"
454 
455            "chrome.storage.sync.set({\"sync_key_4\": \"sync_value_4\","
456            "\"sync_key_5\": \"sync_value_5\"}, function() {"
457            "chrome.storage.sync.clear(function () {"
458 
459            "chrome.storage.sync.get(\"sync_key_4\", function(items) {"
460            "if (items[\"sync_key_4\"] == undefined) {"
461            "value1Cleared = true;"
462            "checkCleared();"
463            "}});"
464 
465            "chrome.storage.sync.get(\"sync_key_5\", function(items) {"
466            "if (items[\"sync_key_5\"] == undefined) {"
467            "value2Cleared = true;"
468            "checkCleared();"
469            "}});"
470 
471            "})});";
472   }
473 
474  private:
475   IMPLEMENT_REFCOUNTING(SyncStorageClearTestHandler);
476   DISALLOW_COPY_AND_ASSIGN(SyncStorageClearTestHandler);
477 };
478 }  // namespace
479 
480 STORAGE_TEST_GROUP_MINIMAL(SyncStorageClear, SyncStorageClearTestHandler)
481