diff options
author | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-04 16:59:11 +0000 |
---|---|---|
committer | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-04 16:59:11 +0000 |
commit | ff8ac0fae66f4fed1dc936560bfe668eb612cb9e (patch) | |
tree | 0e16cc556ae27ce8d63e92b48e48e24dc2b1ee80 | |
parent | f94f03235d9b3f79e809fe352aac4e16598816dd (diff) | |
download | chromium_src-ff8ac0fae66f4fed1dc936560bfe668eb612cb9e.zip chromium_src-ff8ac0fae66f4fed1dc936560bfe668eb612cb9e.tar.gz chromium_src-ff8ac0fae66f4fed1dc936560bfe668eb612cb9e.tar.bz2 |
Add browser test framework for net-internals, along with
tests for the test and prerender tabs, and removing
cookies and login info.
BUG=89057
TEST=NetInternalsTest.*
Review URL: http://codereview.chromium.org/7553009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95430 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/prerender/prerender_browsertest.cc | 5 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/browser_bridge.js | 28 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/test_view.html | 2 | ||||
-rw-r--r-- | chrome/browser/ui/webui/net_internals_ui_browsertest.cc | 240 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 3 | ||||
-rw-r--r-- | chrome/common/url_constants.cc | 2 | ||||
-rw-r--r-- | chrome/common/url_constants.h | 2 | ||||
-rw-r--r-- | chrome/test/base/ui_test_utils.cc | 26 | ||||
-rw-r--r-- | chrome/test/base/ui_test_utils.h | 19 | ||||
-rw-r--r-- | chrome/test/data/webui/net_internals/log_view_painter.js | 82 | ||||
-rw-r--r-- | chrome/test/data/webui/net_internals/net_internals_test.js | 280 | ||||
-rw-r--r-- | chrome/test/data/webui/net_internals/prerender_view.js | 158 | ||||
-rw-r--r-- | chrome/test/data/webui/net_internals/test_view.js | 134 | ||||
-rw-r--r-- | chrome/test/data/webui/test_api.js | 29 |
14 files changed, 981 insertions, 29 deletions
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc index 2ea4ab0..cb117e5 100644 --- a/chrome/browser/prerender/prerender_browsertest.cc +++ b/chrome/browser/prerender/prerender_browsertest.cc @@ -1552,10 +1552,11 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderFavicon) { IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderUnload) { set_loader_path("files/prerender/prerender_loader_with_unload.html"); PrerenderTestURL("files/prerender/prerender_page.html", FINAL_STATUS_USED, 1); + string16 expected_title = ASCIIToUTF16("Unloaded"); ui_test_utils::TitleWatcher title_watcher(browser()->GetSelectedTabContents(), - ASCIIToUTF16("Unloaded")); + expected_title); NavigateToDestURL(); - EXPECT_TRUE(title_watcher.Wait()); + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); } // Checks that when the history is cleared, prerendering is cancelled and diff --git a/chrome/browser/resources/net_internals/browser_bridge.js b/chrome/browser/resources/net_internals/browser_bridge.js index 4616400..024f34b 100644 --- a/chrome/browser/resources/net_internals/browser_bridge.js +++ b/chrome/browser/resources/net_internals/browser_bridge.js @@ -69,6 +69,9 @@ var BrowserBridge = (function() { // and no messages will be sent to the browser, either. Intended for use // when viewing log files. this.disabled_ = false; + + // Interval id returned by window.setInterval for polling timer. + this.pollIntervalId_ = null; } cr.addSingletonGetter(BrowserBridge); @@ -96,12 +99,26 @@ var BrowserBridge = (function() { sendReady: function() { this.send('notifyReady'); + this.setPollInterval(POLL_INTERVAL_MS); + }, - // Some of the data we are interested is not currently exposed as a - // stream, so we will poll the browser to find out when it changes and - // then notify the observers. - window.setInterval(this.checkForUpdatedInfo.bind(this, false), - POLL_INTERVAL_MS); + /** + * Some of the data we are interested is not currently exposed as a + * stream. This starts polling those with active observers (visible + * views) every |intervalMs|. Subsequent calls override previous calls + * to this function. If |intervalMs| is 0, stops polling. + */ + setPollInterval: function(intervalMs) { + if (this.pollIntervalId_ !== null) { + window.clearInterval(this.pollIntervalId_); + this.pollIntervalId_ = null; + } + + if (intervalMs > 0) { + this.pollIntervalId_ = + window.setInterval(this.checkForUpdatedInfo.bind(this, false), + intervalMs); + } }, sendGetProxySettings: function() { @@ -312,6 +329,7 @@ var BrowserBridge = (function() { */ disable: function() { this.disabled_ = true; + this.setPollInterval(0); }, /** diff --git a/chrome/browser/resources/net_internals/test_view.html b/chrome/browser/resources/net_internals/test_view.html index bade39a..9f184a6 100644 --- a/chrome/browser/resources/net_internals/test_view.html +++ b/chrome/browser/resources/net_internals/test_view.html @@ -4,7 +4,7 @@ tests for why it failed.</p> <form id=test-view-connection-tests-form> URL: <input type=text id=test-view-url-input /> - <input type=submit value="Start tests" /> + <input id=test-view-connection-tests-submit type=submit value="Start tests" /> </form> <div id=test-view-summary></div> </div> diff --git a/chrome/browser/ui/webui/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals_ui_browsertest.cc new file mode 100644 index 0000000..e4f16bc --- /dev/null +++ b/chrome/browser/ui/webui/net_internals_ui_browsertest.cc @@ -0,0 +1,240 @@ +// Copyright (c) 2011 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 "base/command_line.h" +#include "base/file_path.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/webui/web_ui_browsertest.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/base/ui_test_utils.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const string16 kPassTitle = ASCIIToUTF16("Test Passed"); +const string16 kFailTitle = ASCIIToUTF16("Test Failed"); + +// Each test involves calls a single Javascript function and then waits for the +// title to be changed to "Test Passed" or "Test Failed" when done. +class NetInternalsTest : public WebUIBrowserTest { + public: + NetInternalsTest(); + virtual ~NetInternalsTest(); + + // InProcessBrowserTest overrides. + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; + virtual void SetUpInProcessBrowserTestFixture() OVERRIDE; + virtual void SetUpOnMainThread() OVERRIDE; + + // Runs the specified Javascript test function with the specified arguments + // and waits for the title to change to "Test Passed" or "Test Failed". + void RunTestAndWaitForTitle(const std::string& function_name, + const ListValue& function_arguments); + + // Same as above, with constant number of arguments for easy use. Will also + // free arguments. + void RunTestAndWaitForTitle(const std::string& function_name); + void RunTestAndWaitForTitle(const std::string& function_name, Value* arg); + void RunTestAndWaitForTitle(const std::string& function_name, + Value* arg1, Value* arg2); + void RunTestAndWaitForTitle(const std::string& function_name, + Value* arg1, Value* arg2, Value* arg3); + + void set_expected_title_(const string16& value) { expected_title_ = value; } + + private: + // The expected title at the end of the test. Defaults to kPassTitle. + string16 expected_title_; + + DISALLOW_COPY_AND_ASSIGN(NetInternalsTest); +}; + +NetInternalsTest::NetInternalsTest() : expected_title_(kPassTitle) { +} + +NetInternalsTest::~NetInternalsTest() { +} + +void NetInternalsTest::SetUpCommandLine(CommandLine* command_line) { + WebUIBrowserTest::SetUpCommandLine(command_line); + // Needed to test the prerender view. + command_line->AppendSwitchASCII(switches::kPrerender, + switches::kPrerenderSwitchValueEnabled); +} + +void NetInternalsTest::SetUpInProcessBrowserTestFixture() { + // Adds libraries needed for testing, so much be first. + WebUIBrowserTest::SetUpInProcessBrowserTestFixture(); + + // Framework for net-internals tests. + AddLibrary(FilePath(FILE_PATH_LITERAL( + "net_internals/net_internals_test.js"))); + + // Add Javascript files needed for individual tests. + AddLibrary(FilePath(FILE_PATH_LITERAL("net_internals/log_view_painter.js"))); + AddLibrary(FilePath(FILE_PATH_LITERAL("net_internals/prerender_view.js"))); + AddLibrary(FilePath(FILE_PATH_LITERAL("net_internals/test_view.js"))); +} + +void NetInternalsTest::SetUpOnMainThread() { + // Navigate to chrome://net-internals. + ui_test_utils::NavigateToURL(browser(), + GURL(chrome::kChromeUINetInternalsURL)); +} + +void NetInternalsTest::RunTestAndWaitForTitle( + const std::string& function_name, + const ListValue& function_arguments) { + ui_test_utils::TitleWatcher title_watcher(browser()->GetTabContentsAt(0), + kPassTitle); + title_watcher.AlsoWaitForTitle(kFailTitle); + + ConstValueVector arguments; + StringValue function_name_arg(function_name); + arguments.push_back(&function_name_arg); + arguments.push_back(&function_arguments); + + ASSERT_TRUE(RunJavascriptFunction("netInternalsTest.runTest", arguments)); + ASSERT_EQ(expected_title_, title_watcher.WaitAndGetTitle()); +} + +void NetInternalsTest::RunTestAndWaitForTitle( + const std::string& function_name) { + ListValue test_arguments; + RunTestAndWaitForTitle(function_name, test_arguments); +} + +void NetInternalsTest::RunTestAndWaitForTitle(const std::string& function_name, + Value* arg) { + ListValue test_arguments; + test_arguments.Append(arg); + RunTestAndWaitForTitle(function_name, test_arguments); +} + +void NetInternalsTest::RunTestAndWaitForTitle(const std::string& function_name, + Value* arg1, Value* arg2) { + ListValue test_arguments; + test_arguments.Append(arg1); + test_arguments.Append(arg2); + RunTestAndWaitForTitle(function_name, test_arguments); +} + +void NetInternalsTest::RunTestAndWaitForTitle(const std::string& function_name, + Value* arg1, Value* arg2, + Value* arg3) { + ListValue test_arguments; + test_arguments.Append(arg1); + test_arguments.Append(arg2); + test_arguments.Append(arg3); + RunTestAndWaitForTitle(function_name, test_arguments); +} + +//////////////////////////////////////////////////////////////////////////////// +// framework.js +//////////////////////////////////////////////////////////////////////////////// + +// Checks testDone. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsDone) { + RunTestAndWaitForTitle("NetInternalsDone"); +} + +// Checks a failed expect statement. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsExpectFail) { + set_expected_title_(kFailTitle); + RunTestAndWaitForTitle("NetInternalsExpectFail"); +} + +// Checks a failed assert statement. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsAssertFail) { + set_expected_title_(kFailTitle); + RunTestAndWaitForTitle("NetInternalsAssertFail"); +} + +// Checks that testDone works when called by an observer in response to an +// event. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsObserverDone) { + RunTestAndWaitForTitle("NetInternalsObserverDone"); +} + +// Checks that a failed expect works when called by an observer in response +// to an event. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsObserverExpectFail) { + set_expected_title_(kFailTitle); + RunTestAndWaitForTitle("NetInternalsObserverExpectFail"); +} + +// Checks that a failed assertion works when called by an observer in response +// to an event. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsObserverAssertFail) { + set_expected_title_(kFailTitle); + RunTestAndWaitForTitle("NetInternalsObserverAssertFail"); +} + +//////////////////////////////////////////////////////////////////////////////// +// test_view.js +//////////////////////////////////////////////////////////////////////////////// + +// Runs the test suite twice, expecting a passing result the first time. Checks +// the first result, the order of events that occur, and the number of rows in +// the table. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsTestViewPassTwice) { + ASSERT_TRUE(test_server()->Start()); + RunTestAndWaitForTitle( + "NetInternalsTestView", + // URL that results in success. + Value::CreateStringValue( + test_server()->GetURL("files/title1.html").spec()), + // Resulting error code of the first test. + Value::CreateIntegerValue(net::OK), + // Number of times to run the test suite. + Value::CreateIntegerValue(2)); +} + +// Runs the test suite twice, expecting a failing result the first time. Checks +// the first result, the order of events that occur, and the number of rows in +// the table. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsTestViewFailTwice) { + RunTestAndWaitForTitle( + "NetInternalsTestView", + // URL that results in an error, due to the port. + Value::CreateStringValue("http://127.0.0.1:7/"), + // Resulting error code of the first test. + Value::CreateIntegerValue(net::ERR_UNSAFE_PORT), + // Number of times to run the test suite. + Value::CreateIntegerValue(2)); +} + +//////////////////////////////////////////////////////////////////////////////// +// prerender_view.js +//////////////////////////////////////////////////////////////////////////////// + +// Prerender two pages and check PrerenderView behavior. The first is expected +// to fail, the second is expected to succeed. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, NetInternalsPrerenderView) { + ASSERT_TRUE(test_server()->Start()); + RunTestAndWaitForTitle( + "NetInternalsPrerenderView", + // URL that can't be prerendered, since it triggers a download. + Value::CreateStringValue( + test_server()->GetURL("files/download-test1.lib").spec()), + // URL that can be prerendered. + Value::CreateStringValue( + test_server()->GetURL("files/title1.html").spec())); +} + +//////////////////////////////////////////////////////////////////////////////// +// log_view_painter.js +//////////////////////////////////////////////////////////////////////////////// + +// Check that we correctly remove cookies and login information. +IN_PROC_BROWSER_TEST_F(NetInternalsTest, + NetInternalsLogViewPainterStripInfo) { + RunTestAndWaitForTitle("NetInternalsLogViewPainterStripInfo"); +} + +} // namespace diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2d55c7c..98b89ef 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -34,7 +34,7 @@ 'theme_resources_standard', '../base/base.gyp:test_support_base', '../content/content.gyp:content_gpu', - '../content/content.gyp:test_support_content', + '../content/content.gyp:test_support_content', '../ipc/ipc.gyp:test_support_ipc', '../media/media.gyp:media_test_support', '../net/net.gyp:net', @@ -2605,6 +2605,7 @@ 'browser/ui/webui/test_chrome_web_ui_factory_browsertest.cc', 'browser/ui/webui/BidiCheckerWebUITest.cc', 'browser/ui/webui/BidiCheckerWebUITest.h', + 'browser/ui/webui/net_internals_ui_browsertest.cc', 'browser/ui/webui/web_ui_browsertest.cc', 'browser/ui/webui/web_ui_browsertest.h', 'browser/ui/webui/web_ui_test_handler.cc', diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 4b8bf01..0e7b571 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc @@ -45,6 +45,8 @@ const char kChromeUIKillURL[] = "chrome://kill/"; const char kChromeUIMemoryURL[] = "chrome://memory/"; const char kChromeUIMemoryRedirectURL[] = "chrome://memory-redirect/"; const char kChromeUINetworkViewCacheURL[] = "chrome://view-http-cache/"; +const char kChromeUINetInternalsURL[] = "chrome://net-internals/"; +const char kChromeUINewProfile[] = "chrome://newprofile/"; const char kChromeUINewTabURL[] = "chrome://newtab/"; const char kChromeUIPluginsURL[] = "chrome://plugins/"; const char kChromeUIPrintURL[] = "chrome://print/"; diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 2c8cd21..6cb79e4 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h @@ -47,6 +47,8 @@ extern const char kChromeUIKillURL[]; extern const char kChromeUIMemoryURL[]; extern const char kChromeUIMemoryRedirectURL[]; extern const char kChromeUINetworkViewCacheURL[]; +extern const char kChromeUINetInternalsURL[]; +extern const char kChromeUINewProfile[]; extern const char kChromeUINewTabURL[]; extern const char kChromeUIPluginsURL[]; extern const char kChromeUIPrintURL[]; diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc index b02d82aec..f6a2cc9 100644 --- a/chrome/test/base/ui_test_utils.cc +++ b/chrome/test/base/ui_test_utils.cc @@ -902,24 +902,28 @@ void WindowedNotificationObserver::Observe(int type, TitleWatcher::TitleWatcher(TabContents* tab_contents, const string16& expected_title) : expected_tab_(tab_contents), - expected_title_(expected_title), - title_observed_(false), + expected_title_observed_(false), quit_loop_on_observation_(false) { EXPECT_TRUE(tab_contents != NULL); + expected_titles_.push_back(expected_title); notification_registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_TITLE_UPDATED, Source<TabContents>(tab_contents)); } +void TitleWatcher::AlsoWaitForTitle(const string16& expected_title) { + expected_titles_.push_back(expected_title); +} + TitleWatcher::~TitleWatcher() { } -bool TitleWatcher::Wait() { - if (title_observed_) - return true; +const string16& TitleWatcher::WaitAndGetTitle() { + if (expected_title_observed_) + return observed_title_; quit_loop_on_observation_ = true; ui_test_utils::RunMessageLoop(); - return title_observed_; + return observed_title_; } void TitleWatcher::Observe(int type, @@ -930,10 +934,14 @@ void TitleWatcher::Observe(int type, TabContents* source_contents = Source<TabContents>(source).ptr(); ASSERT_EQ(expected_tab_, source_contents); - if (source_contents->GetTitle() != expected_title_) + std::vector<string16>::const_iterator it = + std::find(expected_titles_.begin(), + expected_titles_.end(), + source_contents->GetTitle()); + if (it == expected_titles_.end()) return; - - title_observed_ = true; + observed_title_ = *it; + expected_title_observed_ = true; if (quit_loop_on_observation_) MessageLoopForUI::current()->Quit(); } diff --git a/chrome/test/base/ui_test_utils.h b/chrome/test/base/ui_test_utils.h index 15f0898..84a4e7c 100644 --- a/chrome/test/base/ui_test_utils.h +++ b/chrome/test/base/ui_test_utils.h @@ -10,6 +10,7 @@ #include <queue> #include <set> #include <string> +#include <vector> #include "base/basictypes.h" #include "base/message_loop.h" @@ -492,9 +493,13 @@ class TitleWatcher : public NotificationObserver { TitleWatcher(TabContents* tab_contents, const string16& expected_title); virtual ~TitleWatcher(); - // Waits until the title for the tab is set to the |expected_title| - // passed into the constructor. - bool Wait() WARN_UNUSED_RESULT; + // Adds another title to watch for. + void AlsoWaitForTitle(const string16& expected_title); + + // Waits until the title matches either expected_title or one of the titles + // added with AlsoWaitForTitle. Returns the value of the most recently + // observed matching title. + const string16& WaitAndGetTitle() WARN_UNUSED_RESULT; private: // NotificationObserver @@ -503,9 +508,13 @@ class TitleWatcher : public NotificationObserver { const NotificationDetails& details) OVERRIDE; TabContents* expected_tab_; - string16 expected_title_; + std::vector<string16> expected_titles_; NotificationRegistrar notification_registrar_; - bool title_observed_; + + // The most recently observed expected title, if any. + string16 observed_title_; + + bool expected_title_observed_; bool quit_loop_on_observation_; DISALLOW_COPY_AND_ASSIGN(TitleWatcher); diff --git a/chrome/test/data/webui/net_internals/log_view_painter.js b/chrome/test/data/webui/net_internals/log_view_painter.js new file mode 100644 index 0000000..81547b3 --- /dev/null +++ b/chrome/test/data/webui/net_internals/log_view_painter.js @@ -0,0 +1,82 @@ +// Copyright (c) 2011 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. + +/** + * Tests the behavior of stripCookiesAndLoginInfo. + */ +netInternalsTest.test('NetInternalsLogViewPainterStripInfo', function() { + // Each entry in |expectations| is a list consisting of a header element + // before and after applying the filter. If the second entry is null, the + // element should be unmodified. + var expectations = [ + ['set-cookie: blah', 'set-cookie: [value was stripped]'], + ['set-cookie2: blah', 'set-cookie2: [value was stripped]'], + ['cookie: blah', 'cookie: [value was stripped]'], + ['authorization: NTLM blah', 'authorization: NTLM [value was stripped]'], + + ['proxy-authorization: Basic blah', + 'proxy-authorization: Basic [value was stripped]'], + + ['WWW-Authenticate: Basic realm="Something, or another"', null], + + ['WWW-Authenticate: Negotiate blah-token-blah', + 'WWW-Authenticate: Negotiate [value was stripped]'], + + ['WWW-Authenticate: NTLM asdllk2j3l423lk4j23l4kj', + 'WWW-Authenticate: NTLM [value was stripped]'], + + ['WWW-Authenticate: Kerberos , Negotiate asdfasdfasdfasfa', null], + ['WWW-Authenticate: Kerberos, Negotiate asdfasdfasdfasfa', null], + ['WWW-Authenticate: Digest , Negotiate asdfasdfasdfasfa', null], + ['WWW-Authenticate: Digest realm="Foo realm", Negotiate asdf', null], + ['WWW-Authenticate: Kerberos,Digest,Basic', null], + ['WWW-Authenticate: Digest realm="asdfasdf", nonce=5, qop="auth"', null], + ['WWW-Authenticate: Basic realm=foo,foo=bar , Digest ', null], + ['Proxy-Authenticate: Basic realm="Something, or another"', null], + + ['Proxy-Authenticate: Negotiate blah-token-blah', + 'Proxy-Authenticate: Negotiate [value was stripped]'], + + ['Proxy-Authenticate: NTLM asdllk2j3l423lk4j23l4kj', + 'Proxy-Authenticate: NTLM [value was stripped]'], + + ['Proxy-Authenticate: Kerberos , Negotiate asdfasdfa', null], + ['Proxy-Authenticate: Kerberos, Negotiate asdfasdfa', null], + ['Proxy-Authenticate: Digest , Negotiate asdfasdfa', null], + ['Proxy-Authenticate: Digest realm="Foo realm", Negotiate asdfasdfa', null], + ['Proxy-Authenticate: Kerberos,Digest,Basic', null], + ['Proxy-Authenticate: Digest realm="asdfasdf", nonce=5, qop="auth"', null], + ['Proxy-Authenticate: Basic realm=foo,foo=bar , Digest ', null] + ]; + + for (var i = 0; i < expectations.length; ++i) { + var expectation = expectations[i]; + // Position within params.headers where the authentication information goes. + for (var position = 0; position < 3; ++position) { + var entry = { + 'params': { + 'headers': [ + 'Host: clients1.google.com', + 'Connection: keep-alive', + 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)'], + 'line': 'GET / HTTP/1.1\r\n'}, + 'phase': 0, + 'source': {'id': 329, 'type': 1}, + 'time': '22468349', + 'type': 104}; + + entry.params.headers[position] = expectation[0]; + var stripped = stripCookiesAndLoginInfo(entry); + // The entry should be duplicated, so the original still has the deleted + // information. + expectNotEquals(stripped, entry); + if (expectation[1] == null) { + expectEquals(stripped.params.headers[position], expectation[0]); + } else { + expectEquals(stripped.params.headers[position], expectation[1]); + } + } + } + netInternalsTest.testDone(); +}); diff --git a/chrome/test/data/webui/net_internals/net_internals_test.js b/chrome/test/data/webui/net_internals/net_internals_test.js new file mode 100644 index 0000000..4b21b51 --- /dev/null +++ b/chrome/test/data/webui/net_internals/net_internals_test.js @@ -0,0 +1,280 @@ +// Copyright (c) 2011 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. + +/** + * @fileoverview The way these tests work is as follows: + * C++ in net_internals_ui_browsertest.cc does any necessary setup, and then + * calls the entry point for a test with RunJavascriptTest. The called + * function can then use the assert/expect functions defined in test_api.js. + * All callbacks from the browser are wrapped in such a way that they can + * also use the assert/expect functions. + * + * A test ends when an assert/expect test fails, an exception is thrown, or + * |netInternalsTest.testDone| is called. At that point, or soon afterwards, + * the title is updated to 'Test Failed' if an assert/expect test fails, or + * there was an exception. Otherwise, it's set to 'Test Passed'. The + * behavior when an assert/expect test fails or an assertion is thrown only + * after |netInternalsTest.testDone| is called is undefined. + */ + +// Start of namespace. +var netInternalsTest = (function() { + /** + * Use a shorter poll interval for tests, since a few tests wait for polled + * values to change. + * @type {number} + * @const + */ + var TESTING_POLL_INTERVAL_MS = 50; + + /** + * Indicates if the test is complete. + * @type {boolean} + */ + var done = false; + + /** + * Updates the title of the page to report success or failure. Must be + * called at most once for each test. + * @param {boolean} success Description of success param. + */ + function updateTitle(success) { + if (success) { + document.title = 'Test Passed'; + } else { + document.title = 'Test Failed'; + } + done = true; + } + + /** + * Called to indicate a test is complete. + */ + function testDone() { + done = true; + } + + /** + * Creates a test function that can use the expect and assert functions + * in test_api.js. On failure, will set title to 'Test Failed', and when + * a test is done and there was no failure, will set title to 'Test Passed'. + * Calling expect/assert functions after done has been called has undefined + * behavior. Returned test functions can safely call each other directly. + * + * The resulting function has no return value. + * @param {string} testName The name of the function, reported on error. + * @param {Function} testFunction The function to run. + * @return {function():void} Function that passes its parameters to + * testFunction, and passes the test result, if any, to the browser + * process by setting the window title. + */ + function createTestFunction(testName, testFunction) { + return function() { + // Convert arguments to an array, as their map method may be called on + // failure by runTestFunction. + var testArguments = Array.prototype.slice.call(arguments, 0); + + // If the test is already complete, do nothing. + if (done) + return; + + var result = runTestFunction(testName, testFunction, testArguments); + + // If the first value is false, the test failed. + if (!result[0]) { + // Print any error messages. + console.log(result[1]); + // Update title to indicate failure. + updateTitle(false); + } else if (done) { + // If the first result is true, and |done| is also true, the test + // passed. Update title to indicate success. + updateTitle(true); + } + }; + } + + /** + * Dictionary of tests. + * @type {Object.<string, Function>} + */ + var tests = {}; + + /** + * Used to declare a test function called by the NetInternals browser test. + * Takes in a name and a function, and adds it to the list of tests. + * @param {string} testName The of the test. + * @param {Function} testFunction The test function. + */ + function test(testName, testFunction) { + tests[testName] = testFunction; + } + + /** + * Called by the browser to start a test. If constants haven't been + * received from the browser yet, waits until they have been. + * Experimentally, this never seems to happen, but may theoretically be + * possible. + * @param {string} testName The of the test to run. + * @param {Function} testArguments The test arguments. + */ + function runTest(testName, testArguments) { + // If we've already received the constants, start the tests. + if (typeof(LogEventType) != 'undefined') { + startNetInternalsTest(testName, testArguments); + return; + } + + // Otherwise, wait until we do. + console.log('Received constants late.'); + + /** + * Observer that starts the tests once we've received the constants. + */ + function ConstantsObserver() { + this.testStarted_ = false; + } + + ConstantsObserver.prototype.onConstantsReceived = function() { + if (!this.testStarted_) { + this.testStarted_ = true; + startNetInternalsTest(testFunction, testArguments); + } + }; + + g_browser.addConstantsObserver(new ConstantsObserver()); + } + + /** + * Starts running the test. A test is run until an assert/expect statement + * fails or testDone is called. Those functions can only be called in the + * test function body, or in response to a message dispatched by + * |g_browser.receive|. + * @param {string} testName The of the test to run. + * @param {Function} testArguments The test arguments. + */ + function startNetInternalsTest(testName, testArguments) { + // Wrap g_browser.receive around a test function so that assert and expect + // functions can be called from observers. + g_browser.receive = createTestFunction('g_browser.receive', function() { + BrowserBridge.prototype.receive.apply(g_browser, arguments); + }); + + createTestFunction(testName, tests[testName]).apply(null, testArguments); + } + + /** + * Finds the first styled table that's a child of |parentId|, and returns the + * number of rows it has. Returns -1 if there's no such table. + * @param {string} parentId HTML element id containing a styled table. + * @return {number} Number of rows the style table's body has. + */ + function getStyledTableNumRows(parentId) { + // The tbody element of the first styled table in |parentId|. + var tbody = document.querySelector('#' + parentId + ' .styledTable tbody'); + if (!tbody) + return -1; + return tbody.children.length; + } + + /** + * Finds the first styled table that's a child of the element with the given + * id, and checks if it has exactly |expectedRows| rows, not including the + * header row. + * @param {string} parentId HTML element id containing a styled table. + * @param {number} expectedRows Expected number of rows in the table. + */ + function checkStyledTableRows(parentId, expectedRows) { + expectEquals(expectedRows, getStyledTableNumRows(parentId), + 'Incorrect number of rows in ' + parentId); + } + + /** + * Switches to the specified tab. + * TODO(mmenke): check that the tab visibility changes as expected. + * @param {string}: viewId Id of the view to switch to. + */ + function switchToView(viewId) { + document.location.hash = '#' + viewId; + } + + // Exported functions. + return { + test: test, + runTest: runTest, + testDone:testDone, + checkStyledTableRows: checkStyledTableRows, + switchToView: switchToView + }; +})(); + +netInternalsTest.test('NetInternalsDone', function() { + netInternalsTest.testDone(); +}); + +netInternalsTest.test('NetInternalsExpectFail', function() { + expectNotReached(); +}); + +netInternalsTest.test('NetInternalsAssertFail', function() { + assertNotReached(); +}); + +netInternalsTest.test('NetInternalsObserverDone', function() { + /** + * A HostResolverInfo observer that calls testDone() in response to the + * first seen event. + */ + function HostResolverInfoObserver() { + } + + HostResolverInfoObserver.prototype.onHostResolverInfoChanged = function() { + netInternalsTest.testDone(); + }; + + // Create the observer and add it to |g_browser|. + g_browser.addHostResolverInfoObserver(new HostResolverInfoObserver()); + + // Needed to trigger an update. + netInternalsTest.switchToView('dns'); +}); + +netInternalsTest.test('NetInternalsObserverExpectFail', function() { + /** + * A HostResolverInfo observer that triggers an exception in response to the + * first seen event. + */ + function HostResolverInfoObserver() { + } + + HostResolverInfoObserver.prototype.onHostResolverInfoChanged = function() { + expectNotReached(); + netInternalsTest.testDone(); + }; + + // Create the observer and add it to |g_browser|. + g_browser.addHostResolverInfoObserver(new HostResolverInfoObserver()); + + // Needed to trigger an update. + netInternalsTest.switchToView('dns'); +}); + +netInternalsTest.test('NetInternalsObserverAssertFail', function() { + /** + * A HostResolverInfo observer that triggers an assertion in response to the + * first seen event. + */ + function HostResolverInfoObserver() { + } + + HostResolverInfoObserver.prototype.onHostResolverInfoChanged = function() { + assertNotReached(); + }; + + // Create the observer and add it to |g_browser|. + g_browser.addHostResolverInfoObserver(new HostResolverInfoObserver()); + + // Needed to trigger an update. + netInternalsTest.switchToView('dns'); +}); diff --git a/chrome/test/data/webui/net_internals/prerender_view.js b/chrome/test/data/webui/net_internals/prerender_view.js new file mode 100644 index 0000000..c7c1370 --- /dev/null +++ b/chrome/test/data/webui/net_internals/prerender_view.js @@ -0,0 +1,158 @@ +// Copyright (c) 2011 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. + +/** + * Tries to prerender two pages, one that will fail and one that will succeed. + * Checks that we see all relevant events, and update the corresponding tables. + * The prerender that will fail will briefly be active before it fails. Having + * an active prerender will block another prerender from starting too soon, so + * |failureUrl| must be prerendered first. + */ +netInternalsTest.test('NetInternalsPrerenderView', + function (failureUrl, successUrl) { + // IDs for special HTML elements in prerender_view.html + var HISTORY_DIV_ID = 'prerender-view-history-div'; + var ACTIVE_DIV_ID = 'prerender-view-active-div'; + + // Phases of the test. + const STATE = { + // We've switched to the prerender tab, but have yet to receive the + // resulting onPrerenderInfoChanged event with no prerenders active or in + // the history. + START: 0, + // We've added the prefetch link for |failureUrl|. We may receive more + // than one event while in this state, as we may see it as active once + // or more before it moves to the history. We will not receive any + // event with both history and active prerenders empty in this state, + // as we only send notifications when the values change. + FAILURE_URL_LINKED: 1, + // We've added the prefetch link for |successUrl|. + SUCCESS_URL_LINKED: 2 + }; + + /** + * Observer responsible for running the test and checking results. + * @param {string} failureUrl URL that can't be prerendered. + * @param {string} successUrl URL that can be prerendered. + * @constructor + */ + function PrerenderTestObserver(failureUrl, successUrl) { + // True if we've started prerendering |successUrl|. + this.startedSuccessfulPrerender_ = false; + this.failureUrl_ = failureUrl; + this.successUrl_ = successUrl; + this.state_ = STATE.START; + } + + PrerenderTestObserver.prototype = { + /** + * Main function of the observer. Tracks state transitions, checks the + * table sizes, and does some sanity checking on received data. + * @param {Object} prerenderInfo State of prerendering pages. + */ + onPrerenderInfoChanged: function(prerenderInfo) { + console.log('State: ' + this.state_); + + // Verify that prerendering is enabled. + assertTrue(prerenderInfo.enabled, 'Prerendering not enabled.'); + + // Check number of rows in both tables. + netInternalsTest.checkStyledTableRows(HISTORY_DIV_ID, + prerenderInfo.history.length); + netInternalsTest.checkStyledTableRows(ACTIVE_DIV_ID, + prerenderInfo.active.length); + + if (this.state_ == STATE.START) { + this.start_(prerenderInfo); + } else if (this.state_ == STATE.FAILURE_URL_LINKED) { + this.failureUrlLinked_(prerenderInfo); + } else if (this.state_ == STATE.SUCCESS_URL_LINKED) { + this.successUrlLinked_(prerenderInfo); + } + }, + + /** + * Start by triggering a prerender of |failureUrl_|. + * At this point, we expect no active or historical prerender entries. + * @param {Object} prerenderInfo State of prerendering pages. + */ + start_: function(prerenderInfo) { + expectEquals(0, prerenderInfo.active.length); + expectEquals(0, prerenderInfo.history.length); + + // Adding the url we expect to fail. + addPrerenderLink(this.failureUrl_); + this.state_ = STATE.FAILURE_URL_LINKED; + }, + + /** + * We expect to either see the failure url as an active entry, or see it + * move straight to the history. In the latter case, we skip a state. + * @param {Object} prerenderInfo State of prerendering pages. + */ + failureUrlLinked_: function(prerenderInfo) { + // May see the failure url as active, or may see it move straight to the + // history. If not, skip to the next state. + if (prerenderInfo.active.length == 1) { + expectEquals(this.failureUrl_, prerenderInfo.active[0].url); + expectEquals(0, prerenderInfo.history.length); + return; + } + + // The prerender of |failureUrl_| has been cancelled, and is now in the + // history. Go ahead and prerender |successUrl_|. + this.prerenderSuccessUrl_(prerenderInfo); + }, + + /** + * Prerender |successUrl_|. The prerender of |failureUrl_| should have + * failed, and it should now be in the history. + * @param {Object} prerenderInfo State of prerendering pages. + */ + prerenderSuccessUrl_: function(prerenderInfo) { + // We may see the duration of the active prerender increase. If so, + // do nothing. + if (prerenderInfo.active.length == 1) + return; + + assertEquals(1, prerenderInfo.history.length); + expectEquals(this.failureUrl_, prerenderInfo.history[0].url); + expectEquals(0, prerenderInfo.active.length); + + addPrerenderLink(this.successUrl_); + this.state_ = STATE.SUCCESS_URL_LINKED; + }, + + /** + * At this point, we expect to see the failure url in the history, and the + * successUrl in the active entry list, and the test is done. + * @param {Object} prerenderInfo State of prerendering pages. + */ + successUrlLinked_: function(prerenderInfo) { + assertEquals(1, prerenderInfo.history.length); + expectEquals(this.failureUrl_, prerenderInfo.history[0].url); + assertEquals(1, prerenderInfo.active.length); + expectEquals(this.successUrl_, prerenderInfo.active[0].url); + netInternalsTest.testDone(); + }, + }; + + /** + * Adds a <link rel="prerender" href="url"> to the document. + * @param {string} url URL of the page to prerender. + */ + function addPrerenderLink(url) { + var link = document.createElement('link'); + link.setAttribute('rel', 'prerender'); + link.setAttribute('href', url); + document.body.appendChild(link); + } + + netInternalsTest.switchToView('prerender'); + + // Create the test observer, which will start the test once we see the initial + // onPrerenderInfoChanged event from changing the active tab. + var prerenderObserver = new PrerenderTestObserver(failureUrl, successUrl); + g_browser.addPrerenderInfoObserver(prerenderObserver); +}); diff --git a/chrome/test/data/webui/net_internals/test_view.js b/chrome/test/data/webui/net_internals/test_view.js new file mode 100644 index 0000000..4c917eb --- /dev/null +++ b/chrome/test/data/webui/net_internals/test_view.js @@ -0,0 +1,134 @@ +// Copyright (c) 2011 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. + +/** + * Navigates to the test tab, runs the test suite |totalIterations| times, using + * |url|, and expects to see |expectedResult| from each iteration. Checks the + * order and several fields of the events received. + */ +netInternalsTest.test('NetInternalsTestView', + function(url, expectedResult, totalIterations) { + // IDs for special HTML elements in test_view.html + var URL_INPUT_ID = 'test-view-url-input'; + var SUBMIT_BUTTON_ID = 'test-view-connection-tests-submit'; + var SUMMARY_DIV_ID = 'test-view-summary'; + + /** + * @param {string} url URL to run the test suite on. + * @param {number} expectedResult Expected result of the first test. + * @param {number} totalIterations Number of times to run the test suite. + * @constructor + */ + function TestObserver(url, expectedResult, totalIterations) { + this.url_ = url; + this.totalIterations_ = totalIterations; + this.expectedResult_ = expectedResult; + this.completedIterations_ = 0; + } + + TestObserver.prototype = { + /** + * Starts running the test suite. + */ + startTestSuite: function() { + // Initialize state used to track test suite progress. + this.seenStartSuite_ = false; + this.seenStartExperiment_ = false; + this.experimentsRun_ = 0; + + // Simulate entering the url and submitting the form. + $(URL_INPUT_ID).value = this.url_; + $(SUBMIT_BUTTON_ID).click(); + }, + + /** + * Checks that the table was created/cleared, and that no experiment is + * currently running. + */ + onStartedConnectionTestSuite: function() { + expectFalse(this.seenStartSuite_, 'Suite started more than once.'); + checkTestTableRows(0); + expectEquals(this.experimentsRun_, 0); + expectFalse(this.seenStartExperiment_, 0); + + this.seenStartSuite_ = true; + }, + + /** + * Checks that the table has one row per started experiment, and the events + * occur in the proper order. + * @param {Object} experiment Experiment that was just started. + */ + onStartedConnectionTestExperiment: function(experiment) { + console.log('Experiment: ' + this.experimentsRun_); + expectEquals(this.url_, experiment.url, 'Test run on wrong URL'); + expectTrue(this.seenStartSuite_, 'Experiment started before suite.'); + expectFalse(this.seenStartExperiment_, + 'Two experiments running at once.'); + checkTestTableRows(this.experimentsRun_ + 1); + + this.seenStartExperiment_ = true; + }, + + /** + * Checks that the table has one row per started experiment, and the events + * occur in the proper order. + * @param {Object} experiment Experiment that finished. + * @param {number} result Code indicating success or reason for failure. + */ + onCompletedConnectionTestExperiment: function(experiment, result) { + expectEquals(this.url_, experiment.url, 'Test run on wrong URL'); + // Can only rely on the error code of the first test. + if (this.experimentsRun_ == 0) + expectEquals(this.expectedResult_, result); + // If the first expected result is an error, all tests should return some + // error. + if (this.expectedResult_ < 0) + expectLT(result, 0); + + expectTrue(this.seenStartExperiment_, + 'Experiment stopped without starting.'); + checkTestTableRows(this.experimentsRun_ + 1); + + this.seenStartExperiment_ = false; + ++this.experimentsRun_; + }, + + /** + * Checks that we've received all 12 sets of results, and either runs the + * next test iteration, or ends the test, depending on the total number of + * iterations. + */ + onCompletedConnectionTestSuite: function() { + expectTrue(this.seenStartSuite_, 'Suite stopped without being started.'); + expectFalse(this.seenStartExperiment_, + 'Suite stopped while experiment was still running.'); + expectEquals(12, this.experimentsRun_, + 'Incorrect number of experiments run.'); + checkTestTableRows(this.experimentsRun_); + + ++this.completedIterations_; + if (this.completedIterations_ < this.totalIterations_) { + this.startTestSuite(); + } else { + netInternalsTest.testDone(); + } + } + }; + + /** + * Checks that there are |expected| rows in the test table. + * @param {number} expectedRows Expected number of rows in the table. + */ + function checkTestTableRows(expectedRows) { + netInternalsTest.checkStyledTableRows(SUMMARY_DIV_ID, expectedRows); + } + + netInternalsTest.switchToView('tests'); + + // Create observer and start the test. + var testObserver = new TestObserver(url, expectedResult, totalIterations); + g_browser.addConnectionTestsObserver(testObserver); + testObserver.startTestSuite(); +}); diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js index 8314159..72de125 100644 --- a/chrome/test/data/webui/test_api.js +++ b/chrome/test/data/webui/test_api.js @@ -474,18 +474,16 @@ var currentTestCase = null; } /** - * This is the starting point for tests run by WebUIBrowserTest. It clears - * |errors|, runs the test surrounded by an expect to catch Errors. If - * |errors| is non-empty, it reports a failure and a message by joining - * |errors|. + * This is the starting point for tests run by WebUIBrowserTest. If an error + * occurs, it reports a failure and a message created by joining individual + * error messages. * @param {string} testFunction The function name to call. * @param {Array} testArguments The arguments to call |testFunction| with. * @return {Array.<boolean, string>} [test-succeeded, message-if-failed] * @see errors - * @see createExpect + * @see runTestFunction **/ function runTest(testFunction, testArguments) { - errors.splice(0, errors.length); // Avoid eval() if at all possible, since it will not work on pages // that have enabled content-security-policy. var testBody = this[testFunction]; // global object -- not a method. @@ -496,6 +494,24 @@ var currentTestCase = null; testFunction.name ? testFunction.name : testBody.toString(); console.log('Running test ' + testName); } + return runTestFunction(testFunction, testBody, testArguments); + } + + /** + * This is the guts of WebUIBrowserTest. It clears |errors|, runs the + * test surrounded by an expect to catch Errors. If |errors| is + * non-empty, it reports a failure and a message by joining |errors|. + * Consumers can use this to use assert/expect functions asynchronously, + * but are then responsible for reporting errors to the browser themselves. + * @param {string} testFunction The function name to report on failure. + * @param {Function} testBody The function to call. + * @param {Array} testArguments The arguments to call |testBody| with. + * @return {Array.<boolean, string>} [test-succeeded, message-if-failed] + * @see errors + * @see createExpect + **/ + function runTestFunction(testFunction, testBody, testArguments) { + errors.splice(0, errors.length); createExpect(testBody).apply(null, testArguments); var result = [true]; @@ -717,6 +733,7 @@ var currentTestCase = null; window.registerMessageCallback = registerMessageCallback; window.registerMockMessageCallbacks = registerMockMessageCallbacks; window.runTest = runTest; + window.runTestFunction = runTestFunction; window.SaveArgumentsMatcher = SaveArgumentsMatcher; window.TEST = TEST; window.TEST_F = TEST_F; |