diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 20:34:25 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 20:34:25 +0000 |
commit | a77ac74a0e89dd8ae256c4de754919d2b253ef6c (patch) | |
tree | e6dcc5ae72549c5d2437479c5f1e36120143c89e /chrome_frame | |
parent | eb4e077ad36be4a7ba5f961de1a5ec98fda90064 (diff) | |
download | chromium_src-a77ac74a0e89dd8ae256c4de754919d2b253ef6c.zip chromium_src-a77ac74a0e89dd8ae256c4de754919d2b253ef6c.tar.gz chromium_src-a77ac74a0e89dd8ae256c4de754919d2b253ef6c.tar.bz2 |
Attempt to fix ChromeFrameTestWithWebServer tests.
- Use a single MockWebServer (HTTPTestServer) instance for the whole test case rather than one per instance.
- Run pending tasks and the end of each test.
- Try even harder to keep the browser from caching.
- Re-enable all previously disabled tests.
- Save a snapshot of the screen to the desktop (ChromiumSnapshotYYYYMMDDHHMMSS.png) when tests timeout.
- Use a local IPv4 address assigned to a NIC rather than the loopback address.
- Retry tests that timeout a single time.
BUG=112599,96449,37088,32321,111074
TEST=chrome_frame_tests.exe --gtest_filter=ChromeFrameTestWithWebServer.* becomes less flaky
Review URL: http://codereview.chromium.org/10007043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132637 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame.gyp | 2 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 36 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.h | 48 | ||||
-rw-r--r-- | chrome_frame/test/mock_ie_event_sink_test.cc | 2 | ||||
-rw-r--r-- | chrome_frame/test/net/fake_external_tab.cc | 29 | ||||
-rw-r--r-- | chrome_frame/test/test_with_web_server.cc | 136 | ||||
-rw-r--r-- | chrome_frame/test/test_with_web_server.h | 63 |
7 files changed, 227 insertions, 89 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index 921b0a1..a8f4f1d 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -79,6 +79,7 @@ 'dependencies': [ '../base/base.gyp:test_support_base', '../chrome/app/policy/cloud_policy_codegen.gyp:policy', + '../chrome/chrome.gyp:test_support_common', '../net/net.gyp:net', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', @@ -306,6 +307,7 @@ '../chrome/chrome.gyp:browser', '../chrome/chrome.gyp:debugger', '../chrome/chrome.gyp:image_pre_reader', + '../chrome/chrome.gyp:test_support_common', '../chrome/chrome.gyp:test_support_ui', '../chrome/chrome.gyp:utility', '../content/content.gyp:content_gpu', diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index fa504b8..1348b1a 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -9,6 +9,7 @@ #include <iepmapi.h> #include <sddl.h> #include <shlobj.h> +#include <winsock2.h> #include "base/command_line.h" #include "base/file_path.h" @@ -28,6 +29,7 @@ #include "chrome/common/chrome_paths_internal.h" #include "chrome/common/chrome_switches.h" #include "chrome_frame/utils.h" +#include "net/base/net_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -677,4 +679,38 @@ void ClearIESessionHistory() { file_util::Delete(session_history_path, true); } +std::string GetLocalIPv4Address() { + std::string address; + net::NetworkInterfaceList nic_list; + + if (!net::GetNetworkList(&nic_list)) { + LOG(ERROR) << "GetNetworkList failed to look up non-loopback adapters. " + << "Tests will be run over the loopback adapter, which may " + << "result in hangs."; + } else { + // GetNetworkList only returns 'Up' non-loopback adapters. Select the first + // IPv4 address found - we should be able to bind/connect over it. + for (size_t i = 0; i < nic_list.size(); ++i) { + if (nic_list[i].address.size() != net::kIPv4AddressSize) + continue; + char* address_string = + inet_ntoa(*reinterpret_cast<in_addr*>(&nic_list[i].address[0])); + DCHECK(address_string != NULL); + if (address_string != NULL) { + LOG(INFO) << "HTTP tests will run over " << address_string << "."; + address.assign(address_string); + break; + } + } + } + + if (address.empty()) { + LOG(ERROR) << "Failed to find a non-loopback IP_V4 address. Tests will be " + << "run over the loopback adapter, which may result in hangs."; + address.assign("127.0.0.1"); + } + + return address; +} + } // namespace chrome_frame_test diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h index 8911188..2b7466b 100644 --- a/chrome_frame/test/chrome_frame_test_utils.h +++ b/chrome_frame/test/chrome_frame_test_utils.h @@ -13,14 +13,18 @@ #include <string> #include "base/basictypes.h" +#include "base/cancelable_callback.h" #include "base/compiler_specific.h" +#include "base/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/process_util.h" #include "base/time.h" #include "base/test/test_reg_util_win.h" +#include "base/time.h" #include "base/win/registry.h" #include "base/win/scoped_comptr.h" +#include "chrome/test/base/ui_test_utils.h" #include "chrome_frame/chrome_tab.h" #include "chrome_frame/test/simulate_input.h" #include "chrome_frame/test_utils.h" @@ -189,13 +193,22 @@ class HungCOMCallDetector // We need a UI message loop in the main thread. class TimedMsgLoop { public: - TimedMsgLoop() : quit_loop_invoked_(false) { + TimedMsgLoop() : snapshot_on_timeout_(false), quit_loop_invoked_(false) { + } + + void set_snapshot_on_timeout(bool value) { + snapshot_on_timeout_ = value; } void RunFor(base::TimeDelta duration) { - QuitAfter(duration); quit_loop_invoked_ = false; + if (snapshot_on_timeout_) + timeout_closure_.Reset(base::Bind(&TimedMsgLoop::SnapshotAndQuit)); + else + timeout_closure_.Reset(MessageLoop::QuitClosure()); + loop_.PostDelayedTask(FROM_HERE, timeout_closure_.callback(), duration); loop_.MessageLoop::Run(); + timeout_closure_.Cancel(); } void PostTask(const tracked_objects::Location& from_here, @@ -209,10 +222,12 @@ class TimedMsgLoop { } void Quit() { + // Quit after no delay. QuitAfter(base::TimeDelta()); } void QuitAfter(base::TimeDelta delay) { + timeout_closure_.Cancel(); quit_loop_invoked_ = true; loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), delay); } @@ -221,8 +236,33 @@ class TimedMsgLoop { return !quit_loop_invoked_; } + void RunAllPending() { + loop_.RunAllPending(); + } + private: + static void SnapshotAndQuit() { + FilePath snapshot; + if (ui_test_utils::SaveScreenSnapshotToDesktop(&snapshot)) { + testing::UnitTest* unit_test = testing::UnitTest::GetInstance(); + const testing::TestInfo* test_info = unit_test->current_test_info(); + std::string name; + if (test_info != NULL) { + name.append(test_info->test_case_name()) + .append(1, '.') + .append(test_info->name()); + } else { + name = "unknown test"; + } + LOG(ERROR) << name << " timed out. Screen snapshot saved to " + << snapshot.value(); + } + MessageLoop::current()->Quit(); + } + MessageLoopForUI loop_; + base::CancelableClosure timeout_closure_; + bool snapshot_on_timeout_; bool quit_loop_invoked_; }; @@ -328,6 +368,10 @@ ScopedChromeFrameRegistrar::RegistrationType GetTestBedType(); // Clears IE8 session restore history. void ClearIESessionHistory(); +// Returns a local IPv4 address for the current machine. The address +// corresponding to a NIC is preferred over the loopback address. +std::string GetLocalIPv4Address(); + } // namespace chrome_frame_test // TODO(tommi): This is a temporary workaround while we're getting our diff --git a/chrome_frame/test/mock_ie_event_sink_test.cc b/chrome_frame/test/mock_ie_event_sink_test.cc index 11a7dbd..49d6840 100644 --- a/chrome_frame/test/mock_ie_event_sink_test.cc +++ b/chrome_frame/test/mock_ie_event_sink_test.cc @@ -180,6 +180,7 @@ void MockIEEventSink::ExpectDocumentReadystate(int ready_state) { // MockIEEventSinkTest methods MockIEEventSinkTest::MockIEEventSinkTest() : server_mock_(1337, L"127.0.0.1", GetTestDataFolder()) { + loop_.set_snapshot_on_timeout(true); EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _)) .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", "")); } @@ -187,6 +188,7 @@ MockIEEventSinkTest::MockIEEventSinkTest() : server_mock_(1337, L"127.0.0.1", MockIEEventSinkTest::MockIEEventSinkTest(int port, const std::wstring& address, const FilePath& root_dir) : server_mock_(port, address, root_dir) { + loop_.set_snapshot_on_timeout(true); EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _)) .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", "")); } diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc index aa88758..0655ede 100644 --- a/chrome_frame/test/net/fake_external_tab.cc +++ b/chrome_frame/test/net/fake_external_tab.cc @@ -720,32 +720,9 @@ void CFUrlRequestUnittestRunner::OnInitializationTimeout() { } void CFUrlRequestUnittestRunner::OverrideHttpHost() { - net::NetworkInterfaceList nic_list; - if (!net::GetNetworkList(&nic_list)) { - LOG(ERROR) << "GetNetworkList failed to look up non-loopback adapters. " - << "Tests will be run over the loopback adapter, which may " - << "result in hangs."; - return; - } - - // GetNetworkList only returns 'Up' non-loopback adapters. Select the first - // IPV4 address found - we should be able to bind/connect over it. - for (size_t i = 0; i < nic_list.size(); ++i) { - if (nic_list[i].address.size() != net::kIPv4AddressSize) - continue; - char* address_string = - inet_ntoa(*reinterpret_cast<in_addr*>(&nic_list[i].address[0])); - DCHECK(address_string != NULL); - if (address_string == NULL) - continue; - LOG(INFO) << "HTTP tests will run over " << address_string << "."; - override_http_host_.reset( - new ScopedCustomUrlRequestTestHttpHost(address_string)); - return; - } - - LOG(ERROR) << "Failed to find a non-loopback IP_V4 address. Tests will be " - << "run over the loopback adapter, which may result in hangs."; + override_http_host_.reset( + new ScopedCustomUrlRequestTestHttpHost( + chrome_frame_test::GetLocalIPv4Address())); } void CFUrlRequestUnittestRunner::PreEarlyInitialization() { diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc index 1c87f7b..ca84ec6 100644 --- a/chrome_frame/test/test_with_web_server.cc +++ b/chrome_frame/test/test_with_web_server.cc @@ -44,8 +44,10 @@ std::string CreateHttpHeaders(CFInvocation invocation, << "Content-Type: " << content_type << "\r\n"; if (invocation.type() == CFInvocation::HTTP_HEADER) ss << "X-UA-Compatible: chrome=1\r\n"; - if (add_no_cache_header) + if (add_no_cache_header) { ss << "Cache-Control: no-cache\r\n"; + ss << "Expires: Tue, 15 Nov 1994 08:12:31 GMT\r\n"; + } return ss.str(); } @@ -74,11 +76,12 @@ FilePath ChromeFrameTestWithWebServer::CFInstall_path_; FilePath ChromeFrameTestWithWebServer::CFInstance_path_; ScopedTempDir ChromeFrameTestWithWebServer::temp_dir_; FilePath ChromeFrameTestWithWebServer::chrome_user_data_dir_; +chrome_frame_test::TimedMsgLoop* ChromeFrameTestWithWebServer::loop_; +testing::StrictMock<MockWebServerListener>* + ChromeFrameTestWithWebServer::listener_mock_; +testing::StrictMock<MockWebServer>* ChromeFrameTestWithWebServer::server_mock_; -ChromeFrameTestWithWebServer::ChromeFrameTestWithWebServer() - : loop_(), - server_mock_(1337, L"127.0.0.1", - chrome_frame_test::GetTestDataFolder()) { +ChromeFrameTestWithWebServer::ChromeFrameTestWithWebServer() { } // static @@ -108,13 +111,28 @@ void ChromeFrameTestWithWebServer::SetUpTestCase() { CFInstall_path_ = test_file_path_.AppendASCII("CFInstall.js"); ASSERT_TRUE(file_util::CopyFile(CFInstall_src_path, CFInstall_path_)); + + loop_ = new chrome_frame_test::TimedMsgLoop(); + loop_->set_snapshot_on_timeout(true); + listener_mock_ = new testing::StrictMock<MockWebServerListener>(); + server_mock_ = new testing::StrictMock<MockWebServer>( + 1337, ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), + chrome_frame_test::GetTestDataFolder()); + server_mock_->set_listener(listener_mock_); } // static void ChromeFrameTestWithWebServer::TearDownTestCase() { + delete server_mock_; + server_mock_ = NULL; + delete listener_mock_; + listener_mock_ = NULL; + delete loop_; + loop_ = NULL; file_util::Delete(CFInstall_path_, false); file_util::Delete(CFInstance_path_, false); - EXPECT_TRUE(temp_dir_.Delete()); + if (temp_dir_.IsValid()) + EXPECT_TRUE(temp_dir_.Delete()); } // static @@ -130,12 +148,16 @@ void ChromeFrameTestWithWebServer::SetUp() { // Make sure that we are not accidentally enabling gcf protocol. SetConfigBool(kAllowUnsafeURLs, false); - server_mock_.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); - server_mock_.set_expected_result("OK"); + server_mock().ClearResults(); + server_mock().ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); + server_mock().set_expected_result("OK"); } void ChromeFrameTestWithWebServer::TearDown() { CloseBrowser(); + loop().RunAllPending(); + testing::Mock::VerifyAndClear(listener_mock_); + testing::Mock::VerifyAndClear(server_mock_); } bool ChromeFrameTestWithWebServer::LaunchBrowser(BrowserKind browser, @@ -145,7 +167,7 @@ bool ChromeFrameTestWithWebServer::LaunchBrowser(BrowserKind browser, // We should resolve the URL only if it is a relative url. GURL parsed_url(WideToUTF8(page)); if (!parsed_url.has_scheme()) { - url = server_mock_.Resolve(page); + url = server_mock().Resolve(page); } browser_ = browser; @@ -203,8 +225,8 @@ bool ChromeFrameTestWithWebServer::BringBrowserToTop() { bool ChromeFrameTestWithWebServer::WaitForTestToComplete( base::TimeDelta duration) { - loop_.RunFor(duration); - return true; + loop().RunFor(duration); + return !loop().WasTimedOut(); } bool ChromeFrameTestWithWebServer::WaitForOnLoad(int milliseconds) { @@ -215,11 +237,28 @@ const wchar_t kPostedResultSubstring[] = L"/writefile/"; void ChromeFrameTestWithWebServer::SimpleBrowserTestExpectedResult( BrowserKind browser, const wchar_t* page, const char* result) { - server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE), - kPostedResultSubstring); - ASSERT_TRUE(LaunchBrowser(browser, page)); - WaitForTestToComplete(TestTimeouts::action_max_timeout()); - ASSERT_EQ(result, server_mock_.posted_result()); + int tries = 0; + ExpectAndHandlePostedResult(); + // Retry tests that timeout once; see http://crbug.com/96449. + do { + // NOTE: Failed ASSERTs cause this function to exit immediately. + // Don't take a snapshot on the first try. + loop().set_snapshot_on_timeout(tries != 0); + ASSERT_TRUE(LaunchBrowser(browser, page)); + if (WaitForTestToComplete(TestTimeouts::action_max_timeout())) { + // The test exited without timing out. Confirm that the expected response + // was posted and return. + ASSERT_EQ(result, server_mock().posted_result()); + break; + } + ASSERT_EQ(std::string(), server_mock().posted_result()) + << "Test timed out yet provided a result."; + ASSERT_EQ(0, tries++) << "Failing test due to two timeouts."; + // Close the browser and try a second time. + CloseBrowser(); + LOG(ERROR) << "Retrying test once since it timed out."; + } while (true); + loop().set_snapshot_on_timeout(true); } void ChromeFrameTestWithWebServer::SimpleBrowserTest(BrowserKind browser, @@ -227,6 +266,14 @@ void ChromeFrameTestWithWebServer::SimpleBrowserTest(BrowserKind browser, SimpleBrowserTestExpectedResult(browser, page, "OK"); } +void ChromeFrameTestWithWebServer::ExpectAndHandlePostedResult() { + EXPECT_CALL(listener_mock(), OnExpectedResponse()) + .WillRepeatedly(QUIT_LOOP_SOON(loop(), + base::TimeDelta::FromMilliseconds(100))); + server_mock().ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE), + kPostedResultSubstring); +} + void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser, const wchar_t* page) { FilePath plugin_path; @@ -258,15 +305,12 @@ void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser, version = version_info->product_version(); } - server_mock_.set_expected_result(WideToUTF8(version)); + server_mock().set_expected_result(WideToUTF8(version)); EXPECT_TRUE(version_info); EXPECT_FALSE(version.empty()); - server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE), - kPostedResultSubstring); - EXPECT_TRUE(LaunchBrowser(browser, page)); - WaitForTestToComplete(TestTimeouts::action_max_timeout()); - ASSERT_EQ(version, UTF8ToWide(server_mock_.posted_result())); + + SimpleBrowserTestExpectedResult(browser, page, WideToASCII(version).c_str()); } // MockWebServer methods @@ -305,11 +349,8 @@ void MockWebServer::HandlePostedResponse( test_server::ConfigurableConnection* connection, const test_server::Request& request) { posted_result_ = request.content(); - if (posted_result_ == expected_result_) { - MessageLoop::current()->PostDelayedTask(FROM_HERE, - MessageLoop::QuitClosure(), - 100); - } + if (listener_ && posted_result_ == expected_result_) + listener_->OnExpectedResponse(); connection->Send("HTTP/1.1 200 OK\r\n", ""); } @@ -426,7 +467,7 @@ TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_iframeBasic) { const wchar_t kSrcPropertyTestPage[] = L"src_property_host.html"; -TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_SrcProperty) { +TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_SrcProperty) { SimpleBrowserTest(IE, kSrcPropertyTestPage); } @@ -444,14 +485,13 @@ TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceSingleton) { const wchar_t kCFIDelayPage[] = L"CFInstance_delay_host.html"; -TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceDelay) { +TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceDelay) { SimpleBrowserTest(IE, kCFIDelayPage); } const wchar_t kCFIFallbackPage[] = L"CFInstance_fallback_host.html"; -// http://crbug.com/37088 -TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceFallback) { +TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceFallback) { SimpleBrowserTest(IE, kCFIFallbackPage); } @@ -477,8 +517,7 @@ TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceZeroSize) { const wchar_t kCFIIfrPostPage[] = L"CFInstance_iframe_post_host.html"; -// http://crbug.com/32321 -TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceIfrPost) { +TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceIfrPost) { SimpleBrowserTest(IE, kCFIIfrPostPage); } @@ -503,14 +542,7 @@ TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstancePost) { const wchar_t kCFIRPCPage[] = L"CFInstance_rpc_host.html"; -// This test consistently times out in debug builds; see http://crbug.com/112599 -#ifndef NDEBUG -#define MAYBE_WidgetModeIE_CFInstanceRPC DISABLED_WidgetModeIE_CFInstanceRPC -#else -#define MAYBE_WidgetModeIE_CFInstanceRPC WidgetModeIE_CFInstanceRPC -#endif - -TEST_F(ChromeFrameTestWithWebServer, MAYBE_WidgetModeIE_CFInstanceRPC) { +TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPC) { if (chrome_frame_test::GetInstalledIEVersion() == IE_9) { LOG(INFO) << "Not running test on Vista/Windows 7 with IE9"; return; @@ -670,18 +702,17 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_InstallFlowTest) { ASSERT_TRUE(LaunchBrowser(IE, kInstallFlowTestUrl)); - loop_.RunFor(kChromeFrameLongNavigationTimeout); + loop().RunFor(kChromeFrameLongNavigationTimeout); ScopedChromeFrameRegistrar::RegisterAtPath( GetChromeFrameBuildPath().value(), chrome_frame_test::GetTestBedType()); - server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE), - kPostedResultSubstring); - loop_.RunFor(kChromeFrameLongNavigationTimeout); + ExpectAndHandlePostedResult(); + loop().RunFor(kChromeFrameLongNavigationTimeout); chrome_frame_test::CloseAllIEWindows(); - ASSERT_EQ("OK", server_mock_.posted_result()); + ASSERT_EQ("OK", server_mock().posted_result()); } } @@ -729,7 +760,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestPostReissue) { ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str())); - loop_.RunFor(kChromeFrameLongNavigationTimeout); + loop().RunFor(kChromeFrameLongNavigationTimeout); const test_server::Request* request = NULL; server.FindRequest("/quit?OK", &request); @@ -761,7 +792,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestMultipleGet) { ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str())); - loop_.RunFor(kChromeFrameVeryLongNavigationTimeout); + loop().RunFor(kChromeFrameVeryLongNavigationTimeout); const test_server::Request* request = NULL; server.FindRequest("/quit?OK", &request); @@ -793,8 +824,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_XHRConditionalHeaderTest) { const wchar_t kWindowCloseTestUrl[] = L"window_close.html"; -// http://code.google.com/p/chromium/issues/detail?id=111074 -TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_WindowClose) { +TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowClose) { SimpleBrowserTest(IE, kWindowCloseTestUrl); } @@ -879,7 +909,7 @@ TEST_F(ChromeFrameTestWithWebServer, FAILS_FullTabModeIE_RefreshMshtmlTest) { ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str())); - loop_.RunFor(kChromeFrameLongNavigationTimeout); + loop().RunFor(kChromeFrameLongNavigationTimeout); test_server::SimpleWebServer* ws = server.web_server(); const test_server::ConnectionList& connections = ws->connections(); @@ -1011,7 +1041,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestDownloadFromForm) { EXPECT_CALL(win_observer_mock, OnWindowClose(_)) .Times(testing::AtMost(1)) - .WillOnce(QUIT_LOOP(loop_)); + .WillOnce(QUIT_LOOP(loop())); SimpleWebServerTest server(46664); CustomResponse* response = new CustomResponse("/form.html"); @@ -1020,7 +1050,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestDownloadFromForm) { std::wstring url(server.FormatHttpPath(L"form.html")); ASSERT_TRUE(LaunchBrowser(IE, url.c_str())); - loop_.RunFor(kChromeFrameLongNavigationTimeout); + loop().RunFor(kChromeFrameLongNavigationTimeout); EXPECT_EQ(1, response->get_request_count()); EXPECT_EQ(1, response->post_request_count()); diff --git a/chrome_frame/test/test_with_web_server.h b/chrome_frame/test/test_with_web_server.h index 78c3166..f080ed3 100644 --- a/chrome_frame/test/test_with_web_server.h +++ b/chrome_frame/test/test_with_web_server.h @@ -48,6 +48,16 @@ class CFInvocation { Type method_; }; +// An interface for listeners of interesting events on a MockWebServer. +class WebServerListener { + public: + virtual ~WebServerListener() {} + + // Invoked when a MockWebServer receives an expected response; see + // MockWebServer::ExpectAndHandlePostedResult. + virtual void OnExpectedResponse() = 0; +}; + // Simple Gmock friendly web server. Sample usage: // MockWebServer mock(9999, "0.0.0.0"); // EXPECT_CALL(mock, Get(_, StrEq("/favicon.ico"), _)).WillRepeatedly(SendFast( @@ -70,15 +80,15 @@ class CFInvocation { class MockWebServer : public test_server::HTTPTestServer { public: MockWebServer(int port, const std::wstring& address, FilePath root_dir) - : test_server::HTTPTestServer(port, address, root_dir) {} + : test_server::HTTPTestServer(port, address, root_dir), listener_(NULL) {} // Overriden from test_server::HTTPTestServer. MOCK_METHOD3(Get, void(test_server::ConfigurableConnection* connection, const std::wstring& path, - const test_server::Request&r)); + const test_server::Request& r)); MOCK_METHOD3(Post, void(test_server::ConfigurableConnection* connection, const std::wstring& path, - const test_server::Request&r)); + const test_server::Request& r)); // Expect a GET request for |url|. Respond with the file appropriate for // the given |url|. Modify the file to follow the given CFInvocation method. @@ -102,6 +112,12 @@ class MockWebServer : public test_server::HTTPTestServer { void ExpectAndServeRequestAnyNumberTimes(CFInvocation invocation, const std::wstring& path_prefix); + void set_listener(WebServerListener* listener) { listener_ = listener; } + + // Expect a POST to an URL containing |post_suffix|, saving the response + // contents for retrieval by posted_result(). Invokes the listener's + // OnExpectedResponse method if the posted response matches the expected + // result. void ExpectAndHandlePostedResult(CFInvocation invocation, const std::wstring& post_suffix); @@ -123,6 +139,11 @@ class MockWebServer : public test_server::HTTPTestServer { void HandlePostedResponse(test_server::ConfigurableConnection* connection, const test_server::Request& request); + void ClearResults() { + posted_result_.clear(); + expected_result_.clear(); + } + void set_expected_result(const std::string& expected_result) { expected_result_ = expected_result; } @@ -132,11 +153,17 @@ class MockWebServer : public test_server::HTTPTestServer { } private: + WebServerListener* listener_; // Holds the results of tests which post success/failure. std::string posted_result_; std::string expected_result_; }; +class MockWebServerListener : public WebServerListener { + public: + MOCK_METHOD0(OnExpectedResponse, void()); +}; + // Class that: // 1) Starts the local webserver, // 2) Supports launching browsers - Internet Explorer with local url @@ -152,21 +179,26 @@ class ChromeFrameTestWithWebServer : public testing::Test { enum BrowserKind { INVALID, IE, CHROME }; bool LaunchBrowser(BrowserKind browser, const wchar_t* url); + + // Returns true if the test completed in time, or false if it timed out. bool WaitForTestToComplete(base::TimeDelta duration); // Waits for the page to notify us of the window.onload event firing. // Note that the milliseconds value is only approximate. bool WaitForOnLoad(int milliseconds); - // Launches the specified browser and waits for the test to complete - // (see WaitForTestToComplete). Then checks that the outcome is equal - // to the expected result. + // Launches the specified browser and waits for the test to complete (see + // WaitForTestToComplete). Then checks that the outcome is equal to the + // expected result. The test is repeated once if it fails due to a timeout. // This function uses EXPECT_TRUE and ASSERT_TRUE for all steps performed // hence no return value. void SimpleBrowserTestExpectedResult(BrowserKind browser, const wchar_t* page, const char* result); void SimpleBrowserTest(BrowserKind browser, const wchar_t* page); + // Sets up expectations for a page to post back a result. + void ExpectAndHandlePostedResult(); + // Test if chrome frame correctly reports its version. void VersionTest(BrowserKind browser, const wchar_t* page); @@ -179,6 +211,18 @@ class ChromeFrameTestWithWebServer : public testing::Test { return test_file_path_; } + static chrome_frame_test::TimedMsgLoop& loop() { + return *loop_; + } + + static testing::StrictMock<MockWebServerListener>& listener_mock() { + return *listener_mock_; + } + + static testing::StrictMock<MockWebServer>& server_mock() { + return *server_mock_; + } + static void SetUpTestCase(); static void TearDownTestCase(); @@ -197,10 +241,13 @@ class ChromeFrameTestWithWebServer : public testing::Test { // The user data directory used for Chrome instances. static ScopedTempDir temp_dir_; + // The web server from which we serve the web! + static chrome_frame_test::TimedMsgLoop* loop_; + static testing::StrictMock<MockWebServerListener>* listener_mock_; + static testing::StrictMock<MockWebServer>* server_mock_; + BrowserKind browser_; base::win::ScopedHandle browser_handle_; - chrome_frame_test::TimedMsgLoop loop_; - testing::StrictMock<MockWebServer> server_mock_; }; // A helper class for doing some bookkeeping when using the |