diff options
author | erikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-17 20:57:14 +0000 |
---|---|---|
committer | erikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-17 20:57:14 +0000 |
commit | 25fd1b2ecec6dbbdf281e954b991644f155e9a35 (patch) | |
tree | d5d368234e4fbf7494512f70478c162c4de9c987 /chrome | |
parent | 4154786bb3f8655d0a9cb6dee37df90ff735c8e7 (diff) | |
download | chromium_src-25fd1b2ecec6dbbdf281e954b991644f155e9a35.zip chromium_src-25fd1b2ecec6dbbdf281e954b991644f155e9a35.tar.gz chromium_src-25fd1b2ecec6dbbdf281e954b991644f155e9a35.tar.bz2 |
An initial pass at structure to do end-to-end extension API tests. I'll work on actually fleshing out some tests in the next CL.
Review URL: http://codereview.chromium.org/171032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23577 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/extension_apitest.cc | 74 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_apitest.h | 47 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_bookmarks_apitest.cc | 10 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_browsertest.h | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_dispatcher.cc | 15 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_test_api.cc | 29 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_test_api.h | 24 | ||||
-rw-r--r-- | chrome/chrome.gyp | 9 | ||||
-rw-r--r-- | chrome/common/common_resources.grd | 2 | ||||
-rwxr-xr-x | chrome/common/extensions/api/extension_api.json | 21 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 5 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/bookmarks/manifest.json | 7 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/bookmarks/test.html | 1 | ||||
-rwxr-xr-x | chrome/test/data/extensions/api_test/bookmarks/test.js | 76 |
14 files changed, 319 insertions, 9 deletions
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc new file mode 100644 index 0000000..3c45524 --- /dev/null +++ b/chrome/browser/extensions/extension_apitest.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_apitest.h" + +#include "chrome/browser/browser.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/test/ui_test_utils.h" + +namespace { +static const int kTimeoutMs = 60 * 1000; // 1 minute +}; + +// Load an extension and wait for it to notify of PASSED or FAILED. +bool ExtensionApiTest::RunExtensionTest(const char* extension_name) { + bool result; + completed_ = false; + { + NotificationRegistrar registrar; + registrar.Add(this, NotificationType::EXTENSION_TEST_PASSED, + NotificationService::AllSources()); + registrar.Add(this, NotificationType::EXTENSION_TEST_FAILED, + NotificationService::AllSources()); + result = LoadExtension(test_data_dir_.AppendASCII(extension_name)); + + // If the test runs quickly, we may get the notification while waiting + // for the Load to finish. + if (completed_) { + result = passed_; + } else { + result = WaitForPassFail(); + } + } + return result; +} + +bool ExtensionApiTest::WaitForPassFail() { + completed_ = false; + passed_ = false; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, new MessageLoop::QuitTask, kTimeoutMs); + ui_test_utils::RunMessageLoop(); + return passed_; +} + +void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) { + ExtensionBrowserTest::SetUpCommandLine(command_line); + test_data_dir_ = test_data_dir_.AppendASCII("api_test"); +} + +void ExtensionApiTest::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::EXTENSION_TEST_PASSED: + std::cout << "Got EXTENSION_TEST_PASSED notification.\n"; + completed_ = true; + passed_ = true; + MessageLoopForUI::current()->Quit(); + break; + + case NotificationType::EXTENSION_TEST_FAILED: + std::cout << "Got EXTENSION_TEST_FAILED notification.\n"; + completed_ = true; + passed_ = false; + message_ = *(Details<std::string>(details).ptr()); + MessageLoopForUI::current()->Quit(); + break; + + default: + ExtensionBrowserTest::Observe(type, source, details); + } +} diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h new file mode 100644 index 0000000..9e1885b --- /dev/null +++ b/chrome/browser/extensions/extension_apitest.h @@ -0,0 +1,47 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_ + +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/common/notification_service.h" + +// The general flow of these API tests should work like this: +// (1) Setup initial browser state (e.g. create some bookmarks for the +// bookmark test) +// (2) Call ASSERT_TRUE(RunExtensionTest(name)); +// (3) In your extension code, run your test and call chrome.test.pass or +// chrome.test.fail +// (4) Verify expected browser state. +// TODO(erikkay): There should also be a way to drive events in these tests. + +class ExtensionApiTest : public ExtensionBrowserTest { + protected: + // Load |extension_name| and wait for pass / fail notification. + // |extension_name| is a directory in "test/data/extensions/api_test". + bool RunExtensionTest(const char* extension_name); + + // Reset |completed_| and wait for a new pass / fail notification. + bool WaitForPassFail(); + + // All extensions tested by ExtensionApiTest are in the "api_test" dir. + virtual void SetUpCommandLine(CommandLine* command_line); + + // NotificationObserver + void ExtensionApiTest::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Did the extension side of the unit test complete? + bool completed_; + + // Did the extension side of the unit test pass? + bool passed_; + + // If it failed, what was the error message? + std::string message_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_ diff --git a/chrome/browser/extensions/extension_bookmarks_apitest.cc b/chrome/browser/extensions/extension_bookmarks_apitest.cc new file mode 100644 index 0000000..ba24900 --- /dev/null +++ b/chrome/browser/extensions/extension_bookmarks_apitest.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_apitest.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Bookmarks) { + // TODO(erikkay) no initial state for this test. + ASSERT_TRUE(RunExtensionTest("bookmarks")) << message_; +} diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h index 7ef797c..98fb948 100644 --- a/chrome/browser/extensions/extension_browsertest.h +++ b/chrome/browser/extensions/extension_browsertest.h @@ -32,14 +32,16 @@ class ExtensionBrowserTest // Wait for the number of visible page actions to change to |count|. bool WaitForPageActionVisibilityChangeTo(int count); + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + bool loaded_; bool installed_; FilePath test_data_dir_; private: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); bool WaitForExtensionHostsToLoad(); }; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index e2fa753..5a3bb34 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -16,6 +16,7 @@ #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" +#include "chrome/browser/extensions/extension_test_api.h" #include "chrome/browser/extensions/extension_toolstrip_api.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" @@ -67,9 +68,10 @@ FactoryRegistry* FactoryRegistry::instance() { void FactoryRegistry::ResetFunctions() { // Register all functions here. - namespace tabs = extension_tabs_module_constants; - namespace page_actions = extension_page_actions_module_constants; namespace bookmarks = extension_bookmarks_module_constants; + namespace page_actions = extension_page_actions_module_constants; + namespace tabs = extension_tabs_module_constants; + namespace test = extension_test_api_functions; namespace toolstrip = extension_toolstrip_api_functions; // Windows @@ -139,6 +141,12 @@ void FactoryRegistry::ResetFunctions() { &NewExtensionFunction<ToolstripExpandFunction>; factories_[toolstrip::kCollapseFunction] = &NewExtensionFunction<ToolstripCollapseFunction>; + + // Test. + factories_[test::kPassFunction] = + &NewExtensionFunction<ExtensionTestPassFunction>; + factories_[test::kFailFunction] = + &NewExtensionFunction<ExtensionTestFailFunction>; } void FactoryRegistry::GetAllNames(std::vector<std::string>* names) { @@ -253,7 +261,8 @@ void ExtensionFunctionDispatcher::SendResponse(ExtensionFunction* function, } void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) { - LOG(ERROR) << "bad extension message " << // TODO(erikkay) name? + LOG(ERROR) << "bad extension message " << + api->name() << " : terminating renderer."; if (RenderProcessHost::run_renderer_in_process()) { // In single process mode it is better if we don't suicide but just crash. diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc new file mode 100644 index 0000000..a381286 --- /dev/null +++ b/chrome/browser/extensions/extension_test_api.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_test_api.h" +#include "chrome/common/notification_service.h" + +namespace extension_test_api_functions { +const char kPassFunction[] = "test.pass"; +const char kFailFunction[] = "test.fail"; +}; // namespace extension_test_api_functions + +bool ExtensionTestPassFunction::RunImpl() { + NotificationService::current()->Notify( + NotificationType::EXTENSION_TEST_PASSED, + Source<Profile>(dispatcher()->profile()), + NotificationService::NoDetails()); + return true; +} + +bool ExtensionTestFailFunction::RunImpl() { + std::string message; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&message)); + NotificationService::current()->Notify( + NotificationType::EXTENSION_TEST_FAILED, + Source<Profile>(dispatcher()->profile()), + Details<std::string>(&message)); + return true; +} diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h new file mode 100644 index 0000000..ce7cb9e --- /dev/null +++ b/chrome/browser/extensions/extension_test_api.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_ + +#include "chrome/browser/extensions/extension_function.h" + +// Function names. +namespace extension_test_api_functions { + extern const char kPassFunction[]; + extern const char kFailFunction[]; +}; // namespace extension_test_api_functions + +class ExtensionTestPassFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; + +class ExtensionTestFailFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_ diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 34d2c93..5ebd804 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -47,11 +47,14 @@ 'browser/ssl/ssl_browser_tests.cc', ], 'browser_tests_sources_win_specific': [ - 'browser/extensions/extension_shelf_model_unittest.cc', - 'browser/extensions/extension_startup_unittest.cc', + 'browser/extensions/extension_apitest.cc', + 'browser/extensions/extension_apitest.h', + 'browser/extensions/extension_bookmarks_apitest.cc', 'browser/extensions/extension_browsertest.cc', 'browser/extensions/extension_browsertest.h', 'browser/extensions/extension_browsertests_misc.cc', + 'browser/extensions/extension_shelf_model_unittest.cc', + 'browser/extensions/extension_startup_unittest.cc', 'browser/views/browser_views_accessibility_browsertest.cc', 'browser/views/find_bar_win_browsertest.cc', # TODO(jam): http://crbug.com/15101 These tests fail on Linux and Mac. @@ -1054,6 +1057,8 @@ 'browser/extensions/extension_tabs_module.h', 'browser/extensions/extension_tabs_module_constants.cc', 'browser/extensions/extension_tabs_module_constants.h', + 'browser/extensions/extension_test_api.cc', + 'browser/extensions/extension_test_api.h', 'browser/extensions/extension_toolstrip_api.cc', 'browser/extensions/extension_toolstrip_api.h', 'browser/extensions/extension_updater.cc', diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd index e8510c5..457cd27 100644 --- a/chrome/common/common_resources.grd +++ b/chrome/common/common_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. aa1 --> +without changes to the corresponding grd file. --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/common_resources.h" type="rc_header"> diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 2225236..e5989bc 100755 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -849,5 +849,26 @@ } ], "events": [] + }, + { + "namespace": "test", + "types": [], + "functions": [ + { + "name": "fail", + "type": "function", + "description": "Notify the browser process that test code running in the extension failed. This is only used for internal unit testing.", + "parameters": [ + {"type": "string", "name": "message"} + ] + }, + { + "name": "pass", + "type": "function", + "description": "Notify the browser process that test code running in the extension passed. This is only used for internal unit testing.", + "parameters": [] + } + ], + "events": [] } ] diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 8ba2d84..ed37cc6 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -642,6 +642,11 @@ class NotificationType { // Sent when a background page is ready so other components can load. EXTENSION_BACKGROUND_PAGE_READY, + // Sent by an extension to notify the browser about the results of a unit + // test. + EXTENSION_TEST_PASSED, + EXTENSION_TEST_FAILED, + // Debugging --------------------------------------------------------------- // Count (must be last) ---------------------------------------------------- diff --git a/chrome/test/data/extensions/api_test/bookmarks/manifest.json b/chrome/test/data/extensions/api_test/bookmarks/manifest.json new file mode 100644 index 0000000..0ed2a60 --- /dev/null +++ b/chrome/test/data/extensions/api_test/bookmarks/manifest.json @@ -0,0 +1,7 @@ +{
+ "name": "chrome.bookmarks",
+ "version": "0.1",
+ "description": "end-to-end browser test for chrome.bookmarks API",
+ "background_page": "test.html",
+ "permissions": ["bookmarks"]
+}
diff --git a/chrome/test/data/extensions/api_test/bookmarks/test.html b/chrome/test/data/extensions/api_test/bookmarks/test.html new file mode 100644 index 0000000..3e7b4a4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/bookmarks/test.html @@ -0,0 +1 @@ +<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/bookmarks/test.js b/chrome/test/data/extensions/api_test/bookmarks/test.js new file mode 100755 index 0000000..13de9b5 --- /dev/null +++ b/chrome/test/data/extensions/api_test/bookmarks/test.js @@ -0,0 +1,76 @@ +var completed = false;
+
+function complete() {
+ completed = true;
+ // a bit of a hack just to try to get the script to stop running at this point
+ throw "completed";
+}
+
+function fail(message) {
+ if (completed) throw "completed";
+
+ console.log("FAIL: " + message);
+ chrome.test.fail(message);
+ complete();
+}
+
+function succeed() {
+ if (completed) throw "completed";
+
+ chrome.test.pass();
+ complete();
+}
+
+window.onerror = function(message, url, code) {
+ if (completed) return;
+
+ fail(message);
+};
+
+function expectTrue(test, message) {
+ if (!test) {
+ fail(message);
+ }
+}
+
+var expected = [
+ {"children": [
+ {"children": [], "id": "1", "parentId": "0", "title":"Bookmarks bar"},
+ {"children": [], "id": "2", "parentId": "0", "title":"Other bookmarks"}
+ ],
+ "id": "0", "title": ""
+ }
+];
+
+function compareTrees(left, right) {
+ console.log("compare");
+ console.log(JSON.stringify(right));
+ console.log(JSON.stringify(left));
+ // TODO(erikkay): do some comparison of dateAdded
+ if (left == null && right == null) {
+ console.log("both left and right are NULL");
+ return true;
+ }
+ if (left == null || right == null)
+ return false;
+ if (left.length < right.length)
+ return false;
+ for (var i = 0; i < left.length; i++) {
+ if (left[i].id != right[i].id)
+ return false;
+ console.log(left[i].title + " ? " + right[i].title);
+ if (left[i].title != right[i].title)
+ return false;
+ if (!compareTrees(left[i].children, right[i].children))
+ return false;
+ }
+ return true;
+}
+
+chrome.bookmarks.getTree(function(results) {
+ expectTrue(compareTrees(results, expected),
+ "getTree() result doesn't match expected");
+ expected = results;
+ console.log("done");
+ succeed();
+});
|