// Copyright (c) 2006-2008 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 #include // IShellWindows includes. Unfortunately we can't keep these in // alphabetic order since exdisp will bark if some interfaces aren't fully // defined. #include #include #include "base/basictypes.h" #include "base/file_version_info.h" #include "base/file_util.h" #include "base/scoped_bstr_win.h" #include "base/scoped_variant_win.h" #include "base/sys_info.h" #include "gmock/gmock.h" #include "net/url_request/url_request_unittest.h" #include "chrome_frame/test/chrome_frame_unittests.h" #include "chrome_frame/chrome_frame_automation.h" #include "chrome_frame/chrome_frame_delegate.h" #include "chrome_frame/crash_reporting/vectored_handler-impl.h" #include "chrome_frame/test/chrome_frame_test_utils.h" #include "chrome_frame/test_utils.h" #include "chrome_frame/utils.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/helper.h" #include "testing/gmock_mutant.h" using testing::CreateFunctor; const wchar_t kDocRoot[] = L"chrome_frame\\test\\data"; const int kLongWaitTimeout = 60 * 1000; const int kShortWaitTimeout = 25 * 1000; _ATL_FUNC_INFO WebBrowserEventSink::kNavigateErrorInfo = { CC_STDCALL, VT_EMPTY, 5, { VT_DISPATCH, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_BOOL | VT_BYREF, } }; _ATL_FUNC_INFO WebBrowserEventSink::kNavigateComplete2Info = { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_VARIANT | VT_BYREF } }; _ATL_FUNC_INFO WebBrowserEventSink::kBeforeNavigate2Info = { CC_STDCALL, VT_EMPTY, 7, { VT_DISPATCH, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_VARIANT | VT_BYREF, VT_BOOL | VT_BYREF } }; _ATL_FUNC_INFO WebBrowserEventSink::kNewWindow3Info = { CC_STDCALL, VT_EMPTY, 5, { VT_DISPATCH | VT_BYREF, VT_BOOL | VT_BYREF, VT_UINT, VT_BSTR, VT_BSTR } }; void ChromeFrameTestWithWebServer::SetUp() { server_.SetUp(); results_dir_ = server_.GetDataDir(); file_util::AppendToPath(&results_dir_, L"dump"); } void ChromeFrameTestWithWebServer::TearDown() { CloseBrowser(); // Web browsers tend to relaunch themselves in other processes, meaning the // KillProcess stuff above might not have actually cleaned up all our browser // instances, so make really sure browsers are dead. base::KillProcesses(chrome_frame_test::kIEImageName, 0, NULL); base::KillProcesses(chrome_frame_test::kIEBrokerImageName, 0, NULL); base::KillProcesses(chrome_frame_test::kFirefoxImageName, 0, NULL); base::KillProcesses(chrome_frame_test::kSafariImageName, 0, NULL); base::KillProcesses(chrome_frame_test::kChromeImageName, 0, NULL); server_.TearDown(); } bool ChromeFrameTestWithWebServer::LaunchBrowser(BrowserKind browser, const wchar_t* page) { std::wstring url = UTF8ToWide(server_.Resolve(page).spec()); browser_ = browser; if (browser == IE) { browser_handle_.Set(chrome_frame_test::LaunchIE(url)); } else if (browser == FIREFOX) { browser_handle_.Set(chrome_frame_test::LaunchFirefox(url)); } else if (browser == OPERA) { browser_handle_.Set(chrome_frame_test::LaunchOpera(url)); } else if (browser == SAFARI) { browser_handle_.Set(chrome_frame_test::LaunchSafari(url)); } else if (browser == CHROME) { browser_handle_.Set(chrome_frame_test::LaunchChrome(url)); } else { NOTREACHED(); } return browser_handle_.IsValid(); } void ChromeFrameTestWithWebServer::CloseBrowser() { if (!browser_handle_.IsValid()) return; int attempts = 0; if (browser_ == IE) { attempts = chrome_frame_test::CloseAllIEWindows(); } else { attempts = chrome_frame_test::CloseVisibleWindowsOnAllThreads( browser_handle_); } if (attempts > 0) { DWORD wait = ::WaitForSingleObject(browser_handle_, 20000); if (wait == WAIT_OBJECT_0) { browser_handle_.Close(); } else { DLOG(ERROR) << "WaitForSingleObject returned " << wait; } } else { DLOG(ERROR) << "No attempts to close browser windows"; } if (browser_handle_.IsValid()) { DWORD exit_code = 0; if (!::GetExitCodeProcess(browser_handle_, &exit_code) || exit_code == STILL_ACTIVE) { DLOG(ERROR) << L"Forcefully killing browser process. Exit:" << exit_code; base::KillProcess(browser_handle_, 0, true); } browser_handle_.Close(); } } bool ChromeFrameTestWithWebServer::BringBrowserToTop() { return chrome_frame_test::EnsureProcessInForeground(GetProcessId( browser_handle_)); } bool ChromeFrameTestWithWebServer::WaitForTestToComplete(int milliseconds) { return server_.WaitToFinish(milliseconds); } bool ChromeFrameTestWithWebServer::WaitForOnLoad(int milliseconds) { DWORD start = ::GetTickCount(); std::string data; while (!ReadResultFile(L"OnLoadEvent", &data) || data.length() == 0) { DWORD now = ::GetTickCount(); if (start > now) { // Very simple check for overflow. In that case we just restart the // wait. start = now; } else if (static_cast(now - start) > milliseconds) { break; } Sleep(100); } return data.compare("loaded") == 0; } bool ChromeFrameTestWithWebServer::ReadResultFile(const std::wstring& file_name, std::string* data) { std::wstring full_path = results_dir_; file_util::AppendToPath(&full_path, file_name); return file_util::ReadFileToString(full_path, data); } bool ChromeFrameTestWithWebServer::CheckResultFile( const std::wstring& file_name, const std::string& expected_result) { std::string data; bool ret = ReadResultFile(file_name, &data); if (ret) ret = (data == expected_result); if (!ret) { DLOG(ERROR) << "Error text: " << (data.empty() ? "" : data.c_str()); } return ret; } void ChromeFrameTestWithWebServer::SimpleBrowserTest(BrowserKind browser, const wchar_t* page, const wchar_t* result_file_to_check) { ASSERT_TRUE(LaunchBrowser(browser, page)); ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout)); ASSERT_TRUE(CheckResultFile(result_file_to_check, "OK")); } void ChromeFrameTestWithWebServer::OptionalBrowserTest(BrowserKind browser, const wchar_t* page, const wchar_t* result_file_to_check) { if (!LaunchBrowser(browser, page)) { DLOG(ERROR) << "Failed to launch browser " << ToString(browser); } else { ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout)); ASSERT_TRUE(CheckResultFile(result_file_to_check, "OK")); } } void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser, const wchar_t* page, const wchar_t* result_file_to_check) { std::wstring plugin_path; PathService::Get(base::DIR_MODULE, &plugin_path); file_util::AppendToPath(&plugin_path, L"servers/npchrome_tab.dll"); static FileVersionInfo* version_info = FileVersionInfo::CreateFileVersionInfo(plugin_path); std::wstring version; if (version_info) version = version_info->product_version(); // If we can't find the npchrome_tab.dll in the src tree, we turn to // the directory where chrome is installed. if (!version_info) { installer::Version* ver_system = InstallUtil::GetChromeVersion(true); installer::Version* ver_user = InstallUtil::GetChromeVersion(false); ASSERT_TRUE(ver_system || ver_user); bool system_install = ver_system ? true : false; std::wstring npchrome_path(installer::GetChromeInstallPath(system_install)); file_util::AppendToPath(&npchrome_path, ver_system ? ver_system->GetString() : ver_user->GetString()); file_util::AppendToPath(&npchrome_path, L"npchrome_tab.dll"); version_info = FileVersionInfo::CreateFileVersionInfo(npchrome_path); if (version_info) version = version_info->product_version(); } EXPECT_TRUE(version_info); EXPECT_FALSE(version.empty()); EXPECT_TRUE(LaunchBrowser(browser, page)); ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout)); ASSERT_TRUE(CheckResultFile(result_file_to_check, WideToUTF8(version))); } const wchar_t kPostMessageBasicPage[] = L"files/postmessage_basic_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PostMessageBasic) { SimpleBrowserTest(IE, kPostMessageBasicPage, L"PostMessage"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_PostMessageBasic) { SimpleBrowserTest(FIREFOX, kPostMessageBasicPage, L"PostMessage"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_PostMessageBasic) { OptionalBrowserTest(OPERA, kPostMessageBasicPage, L"PostMessage"); } TEST_F(ChromeFrameTestWithWebServer, FullTabIE_MIMEFilterBasic) { const wchar_t kMIMEFilterBasicPage[] = L"files/chrome_frame_mime_filter_test.html"; SimpleBrowserTest(IE, kMIMEFilterBasicPage, L"MIMEFilter"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_Resize) { SimpleBrowserTest(IE, L"files/chrome_frame_resize.html", L"Resize"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_Resize) { SimpleBrowserTest(FIREFOX, L"files/chrome_frame_resize.html", L"Resize"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_Resize) { OptionalBrowserTest(OPERA, L"files/chrome_frame_resize.html", L"Resize"); } const wchar_t kNavigateURLAbsolutePage[] = L"files/navigateurl_absolute_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_NavigateURLAbsolute) { SimpleBrowserTest(IE, kNavigateURLAbsolutePage, L"NavigateURL"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_NavigateURLAbsolute) { SimpleBrowserTest(FIREFOX, kNavigateURLAbsolutePage, L"NavigateURL"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_NavigateURLAbsolute) { OptionalBrowserTest(OPERA, kNavigateURLAbsolutePage, L"NavigateURL"); } const wchar_t kNavigateURLRelativePage[] = L"files/navigateurl_relative_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_NavigateURLRelative) { SimpleBrowserTest(IE, kNavigateURLRelativePage, L"NavigateURL"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_NavigateURLRelative) { SimpleBrowserTest(FIREFOX, kNavigateURLRelativePage, L"NavigateURL"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_NavigateURLRelative) { OptionalBrowserTest(OPERA, kNavigateURLRelativePage, L"NavigateURL"); } const wchar_t kNavigateSimpleObjectFocus[] = L"files/simple_object_focus.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_ObjectFocus) { SimpleBrowserTest(FIREFOX, kNavigateSimpleObjectFocus, L"ObjectFocus"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_ObjectFocus) { SimpleBrowserTest(IE, kNavigateSimpleObjectFocus, L"ObjectFocus"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_ObjectFocus) { if (!LaunchBrowser(OPERA, kNavigateSimpleObjectFocus)) { DLOG(ERROR) << "Failed to launch browser " << ToString(OPERA); } else { ASSERT_TRUE(WaitForOnLoad(kLongWaitTimeout)); BringBrowserToTop(); // Tab through a couple of times. Once should be enough in theory // but in practice activating the browser can take a few milliseconds more. bool ok; for (int i = 0; i < 5 && (ok = CheckResultFile(L"ObjectFocus", "OK")) == false; ++i) { Sleep(300); chrome_frame_test::SendMnemonic(VK_TAB, false, false, false); } ASSERT_TRUE(ok); } } const wchar_t kiframeBasicPage[] = L"files/iframe_basic_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_iframeBasic) { SimpleBrowserTest(IE, kiframeBasicPage, L"PostMessage"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_iframeBasic) { SimpleBrowserTest(FIREFOX, kiframeBasicPage, L"PostMessage"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_iframeBasic) { OptionalBrowserTest(OPERA, kiframeBasicPage, L"PostMessage"); } const wchar_t kSrcPropertyTestPage[] = L"files/src_property_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_SrcProperty) { SimpleBrowserTest(IE, kSrcPropertyTestPage, L"SrcProperty"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_SrcProperty) { SimpleBrowserTest(FIREFOX, kSrcPropertyTestPage, L"SrcProperty"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_SrcProperty) { OptionalBrowserTest(OPERA, kSrcPropertyTestPage, L"SrcProperty"); } const wchar_t kCFInstanceBasicTestPage[] = L"files/CFInstance_basic_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceBasic) { SimpleBrowserTest(IE, kCFInstanceBasicTestPage, L"CFInstanceBasic"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceBasic) { SimpleBrowserTest(FIREFOX, kCFInstanceBasicTestPage, L"CFInstanceBasic"); } const wchar_t kCFISingletonPage[] = L"files/CFInstance_singleton_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceSingleton) { SimpleBrowserTest(IE, kCFISingletonPage, L"CFInstanceSingleton"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceSingleton) { SimpleBrowserTest(FIREFOX, kCFISingletonPage, L"CFInstanceSingleton"); } const wchar_t kCFIDelayPage[] = L"files/CFInstance_delay_host.html"; TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceDelay) { SimpleBrowserTest(IE, kCFIDelayPage, L"CFInstanceDelay"); } TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeFF_CFInstanceDelay) { SimpleBrowserTest(FIREFOX, kCFIDelayPage, L"CFInstanceDelay"); } TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstanceDelay) { OptionalBrowserTest(OPERA, kCFIDelayPage, L"CFInstanceDelay"); } const wchar_t kCFIFallbackPage[] = L"files/CFInstance_fallback_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceFallback) { SimpleBrowserTest(IE, kCFIFallbackPage, L"CFInstanceFallback"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceFallback) { SimpleBrowserTest(FIREFOX, kCFIFallbackPage, L"CFInstanceFallback"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceFallback) { OptionalBrowserTest(OPERA, kCFIFallbackPage, L"CFInstanceFallback"); } const wchar_t kCFINoSrcPage[] = L"files/CFInstance_no_src_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceNoSrc) { SimpleBrowserTest(IE, kCFINoSrcPage, L"CFInstanceNoSrc"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceNoSrc) { SimpleBrowserTest(FIREFOX, kCFINoSrcPage, L"CFInstanceNoSrc"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceNoSrc) { OptionalBrowserTest(OPERA, kCFINoSrcPage, L"CFInstanceNoSrc"); } const wchar_t kCFIIfrOnLoadPage[] = L"files/CFInstance_iframe_onload_host.html"; // disabled since it's unlikely that we care about this case TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceIfrOnLoad) { SimpleBrowserTest(IE, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceIfrOnLoad) { SimpleBrowserTest(FIREFOX, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceIfrOnLoad) { OptionalBrowserTest(OPERA, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad"); } const wchar_t kCFIZeroSizePage[] = L"files/CFInstance_zero_size_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceZeroSize) { SimpleBrowserTest(IE, kCFIZeroSizePage, L"CFInstanceZeroSize"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceZeroSize) { SimpleBrowserTest(FIREFOX, kCFIZeroSizePage, L"CFInstanceZeroSize"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceZeroSize) { OptionalBrowserTest(OPERA, kCFIZeroSizePage, L"CFInstanceZeroSize"); } const wchar_t kCFIIfrPostPage[] = L"files/CFInstance_iframe_post_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceIfrPost) { SimpleBrowserTest(IE, kCFIIfrPostPage, L"CFInstanceIfrPost"); } // Flakes out on the bots, http://crbug.com/26372 TEST_F(ChromeFrameTestWithWebServer, FLAKY_WidgetModeFF_CFInstanceIfrPost) { SimpleBrowserTest(FIREFOX, kCFIIfrPostPage, L"CFInstanceIfrPost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceIfrPost) { OptionalBrowserTest(CHROME, kCFIIfrPostPage, L"CFInstanceIfrPost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceIfrPost) { OptionalBrowserTest(SAFARI, kCFIIfrPostPage, L"CFInstanceIfrPost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceIfrPost) { OptionalBrowserTest(OPERA, kCFIIfrPostPage, L"CFInstanceIfrPost"); } const wchar_t kCFIPostPage[] = L"files/CFInstance_post_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstancePost) { SimpleBrowserTest(IE, kCFIPostPage, L"CFInstancePost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstancePost) { SimpleBrowserTest(FIREFOX, kCFIPostPage, L"CFInstancePost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstancePost) { OptionalBrowserTest(CHROME, kCFIPostPage, L"CFInstancePost"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstancePost) { OptionalBrowserTest(SAFARI, kCFIPostPage, L"CFInstancePost"); } TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstancePost) { OptionalBrowserTest(OPERA, kCFIPostPage, L"CFInstancePost"); } const wchar_t kCFIRPCPage[] = L"files/CFInstance_rpc_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPC) { SimpleBrowserTest(IE, kCFIRPCPage, L"CFInstanceRPC"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceRPC) { SimpleBrowserTest(FIREFOX, kCFIRPCPage, L"CFInstanceRPC"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPC) { OptionalBrowserTest(CHROME, kCFIRPCPage, L"CFInstanceRPC"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceRPC) { OptionalBrowserTest(SAFARI, kCFIRPCPage, L"CFInstanceRPC"); } TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstanceRPC) { OptionalBrowserTest(OPERA, kCFIRPCPage, L"CFInstanceRPC"); } const wchar_t kCFIRPCInternalPage[] = L"files/CFInstance_rpc_internal_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPCInternal) { SimpleBrowserTest(IE, kCFIRPCInternalPage, L"CFInstanceRPCInternal"); } // Disabled: http://b/issue?id=2050201 TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeFF_CFInstanceRPCInternal) { SimpleBrowserTest(FIREFOX, kCFIRPCInternalPage, L"CFInstanceRPCInternal"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPCInternal) { OptionalBrowserTest(CHROME, kCFIRPCInternalPage, L"CFInstanceRPCInternal"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceRPCInternal) { OptionalBrowserTest(SAFARI, kCFIRPCInternalPage, L"CFInstanceRPCInternal"); } const wchar_t kCFIDefaultCtorPage[] = L"files/CFInstance_default_ctor_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceDefaultCtor) { SimpleBrowserTest(IE, kCFIDefaultCtorPage, L"CFInstanceDefaultCtor"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceDefaultCtor) { SimpleBrowserTest(FIREFOX, kCFIDefaultCtorPage, L"CFInstanceDefaultCtor"); } const wchar_t kCFInstallBasicTestPage[] = L"files/CFInstall_basic.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallBasic) { SimpleBrowserTest(IE, kCFInstallBasicTestPage, L"CFInstallBasic"); } const wchar_t kCFInstallPlaceTestPage[] = L"files/CFInstall_place.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallPlace) { SimpleBrowserTest(IE, kCFInstallPlaceTestPage, L"CFInstallPlace"); } const wchar_t kCFInstallOverlayTestPage[] = L"files/CFInstall_overlay.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallOverlay) { SimpleBrowserTest(IE, kCFInstallOverlayTestPage, L"CFInstallOverlay"); } const wchar_t kCFInstallDismissTestPage[] = L"files/CFInstall_dismiss.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallDismiss) { SimpleBrowserTest(IE, kCFInstallDismissTestPage, L"CFInstallDismiss"); } const wchar_t kInitializeHiddenPage[] = L"files/initialize_hidden.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_InitializeHidden) { SimpleBrowserTest(IE, kInitializeHiddenPage, L"InitializeHidden"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_InitializeHidden) { SimpleBrowserTest(FIREFOX, kInitializeHiddenPage, L"InitializeHidden"); } // Disabled due to a problem with Opera. // http://b/issue?id=1708275 TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_InitializeHidden) { OptionalBrowserTest(OPERA, kInitializeHiddenPage, L"InitializeHidden"); } const wchar_t kInHeadPage[] = L"files/in_head.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_InHead) { SimpleBrowserTest(FIREFOX, kInHeadPage, L"InHead"); } const wchar_t kVersionPage[] = L"files/version.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_Version) { VersionTest(IE, kVersionPage, L"version"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_Version) { VersionTest(FIREFOX, kVersionPage, L"version"); } const wchar_t kEventListenerPage[] = L"files/event_listener.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_EventListener) { SimpleBrowserTest(IE, kEventListenerPage, L"EventListener"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_EventListener) { SimpleBrowserTest(FIREFOX, kEventListenerPage, L"EventListener"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_EventListener) { OptionalBrowserTest(OPERA, kEventListenerPage, L"EventListener"); } const wchar_t kPrivilegedApisPage[] = L"files/privileged_apis_host.html"; TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PrivilegedApis) { SimpleBrowserTest(IE, kPrivilegedApisPage, L"PrivilegedApis"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_PrivilegedApis) { SimpleBrowserTest(FIREFOX, kPrivilegedApisPage, L"PrivilegedApis"); } TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_PrivilegedApis) { OptionalBrowserTest(OPERA, kPrivilegedApisPage, L"PrivilegedApis"); } class ChromeFrameTestEnvironment: public testing::Environment { public: ~ChromeFrameTestEnvironment() { } void SetUp() { ScopedChromeFrameRegistrar::RegisterDefaults(); } void TearDown() { } }; ::testing::Environment* const chrome_frame_env = ::testing::AddGlobalTestEnvironment(new ChromeFrameTestEnvironment); // TODO(stoyan): - Move everything below in separate file(s). struct LaunchDelegateMock : public ProxyFactory::LaunchDelegate { MOCK_METHOD2(LaunchComplete, void(ChromeFrameAutomationProxy*, AutomationLaunchResult)); }; TEST(ProxyFactoryTest, CreateDestroy) { ProxyFactory f; LaunchDelegateMock d; EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(1); void* id = f.GetAutomationServer(0, L"Adam.N.Epilinter", L"", false, &d); f.ReleaseAutomationServer(id); } TEST(ProxyFactoryTest, CreateSameProfile) { ProxyFactory f; LaunchDelegateMock d; EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(2); void* i1 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d); void* i2 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d); EXPECT_EQ(i1, i2); f.ReleaseAutomationServer(i2); f.ReleaseAutomationServer(i1); } TEST(ProxyFactoryTest, CreateDifferentProfiles) { ProxyFactory f; LaunchDelegateMock d; EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(2); void* i1 = f.GetAutomationServer(0, L"Adam.N.Epilinter", L"", false, &d); void* i2 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d); EXPECT_NE(i1, i2); f.ReleaseAutomationServer(i2); f.ReleaseAutomationServer(i1); } // ChromeFrameAutomationClient [CFAC] tests. struct MockCFDelegate : public ChromeFrameDelegateImpl { MOCK_CONST_METHOD0(GetWindow, WindowType()); MOCK_METHOD1(GetBounds, void(RECT* bounds)); MOCK_METHOD0(GetDocumentUrl, std::string()); MOCK_METHOD2(ExecuteScript, bool(const std::string& script, std::string* result)); MOCK_METHOD0(OnAutomationServerReady, void()); MOCK_METHOD2(OnAutomationServerLaunchFailed, void( AutomationLaunchResult reason, const std::string& server_version)); // This remains in interface since we call it if Navigate() // returns immediate error. MOCK_METHOD2(OnLoadFailed, void(int error_code, const std::string& url)); // Do not mock this method. :) Use it as message demuxer and dispatcher // to the following methods (which we mock) // MOCK_METHOD1(OnMessageReceived, void(const IPC::Message&)); MOCK_METHOD2(OnNavigationStateChanged, void(int tab_handle, int flags)); MOCK_METHOD2(OnUpdateTargetUrl, void(int tab_handle, const std::wstring& new_target_url)); MOCK_METHOD2(OnAcceleratorPressed, void(int tab_handle, const MSG& accel_message)); MOCK_METHOD2(OnTabbedOut, void(int tab_handle, bool reverse)); MOCK_METHOD3(OnOpenURL, void(int tab_handle, const GURL& url, int open_disposition)); MOCK_METHOD2(OnDidNavigate, void(int tab_handle, const IPC::NavigationInfo& navigation_info)); MOCK_METHOD3(OnNavigationFailed, void(int tab_handle, int error_code, const GURL& gurl)); MOCK_METHOD2(OnLoad, void(int tab_handle, const GURL& url)); MOCK_METHOD4(OnMessageFromChromeFrame, void(int tab_handle, const std::string& message, const std::string& origin, const std::string& target)); MOCK_METHOD5(OnHandleContextMenu, void(int tab_handle, HANDLE menu_handle, int x_pos, int y_pos, int align_flags)); MOCK_METHOD3(OnRequestStart, void(int tab_handle, int request_id, const IPC::AutomationURLRequest& request)); MOCK_METHOD3(OnRequestRead, void(int tab_handle, int request_id, int bytes_to_read)); MOCK_METHOD3(OnRequestEnd, void(int tab_handle, int request_id, const URLRequestStatus& status)); MOCK_METHOD3(OnSetCookieAsync, void(int tab_handle, const GURL& url, const std::string& cookie)); // Use for sending network responses void SetAutomationSender(IPC::Message::Sender* automation) { automation_ = automation; } // Set-expectation helpers void SetOnNavigationStateChanged(int tab_handle) { EXPECT_CALL(*this, OnNavigationStateChanged(testing::Eq(tab_handle), testing::_)) .Times(testing::AnyNumber()); } // Response sender helpers void ReplyStarted(const IPC::AutomationURLResponse* response, int tab_handle, int request_id, const IPC::AutomationURLRequest& request) { automation_->Send(new AutomationMsg_RequestStarted(0, tab_handle, request_id, *response)); } void ReplyData(const std::string* data, int tab_handle, int request_id, int bytes_to_read) { automation_->Send(new AutomationMsg_RequestData(0, tab_handle, request_id, *data)); } void ReplyEOF(int tab_handle, int request_id) { automation_->Send(new AutomationMsg_RequestEnd(0, tab_handle, request_id, URLRequestStatus())); } void Reply404(int tab_handle, int request_id, const IPC::AutomationURLRequest& request) { const IPC::AutomationURLResponse notfound = {"", "HTTP/1.1 404\r\n\r\n"}; automation_->Send(new AutomationMsg_RequestStarted(0, tab_handle, request_id, notfound)); automation_->Send(new AutomationMsg_RequestEnd(0, tab_handle, request_id, URLRequestStatus())); } IPC::Message::Sender* automation_; }; class MockProxyFactory : public ProxyFactory { public: MOCK_METHOD5(GetAutomationServer, void*(int, const std::wstring&, const std::wstring& extra_argument, bool, ProxyFactory::LaunchDelegate*)); MOCK_METHOD1(ReleaseAutomationServer, bool(void* id)); MockProxyFactory() : thread_("mock factory worker") { thread_.Start(); loop_ = thread_.message_loop(); } // Fake implementation void GetServerImpl(ChromeFrameAutomationProxy* pxy, AutomationLaunchResult result, int timeout, ProxyFactory::LaunchDelegate* d) { Task* task = NewRunnableMethod(d, &ProxyFactory::LaunchDelegate::LaunchComplete, pxy, result); loop_->PostDelayedTask(FROM_HERE, task, timeout/2); } base::Thread thread_; MessageLoop* loop_; }; class MockAutomationProxy : public ChromeFrameAutomationProxy { public: MOCK_METHOD1(Send, bool(IPC::Message*)); MOCK_METHOD3(SendAsAsync, void(IPC::SyncMessage* msg, void* callback, void* key)); MOCK_METHOD1(CancelAsync, void(void* key)); MOCK_METHOD1(CreateTabProxy, scoped_refptr(int handle)); MOCK_METHOD0(server_version, std::string(void)); MOCK_METHOD1(SendProxyConfig, void(const std::string&)); MOCK_METHOD1(SetEnableExtensionAutomation, void(const std::vector&)); ~MockAutomationProxy() {} }; struct MockAutomationMessageSender : public AutomationMessageSender { MOCK_METHOD1(Send, bool(IPC::Message*)); MOCK_METHOD3(SendWithTimeout, bool(IPC::Message* , int , bool*)); void ForwardTo(MockAutomationProxy *p) { proxy_ = p; ON_CALL(*this, Send(testing::_)) .WillByDefault(testing::Invoke(proxy_, &MockAutomationProxy::Send)); } MockAutomationProxy* proxy_; }; template <> struct RunnableMethodTraits { void RetainCallee(ProxyFactory::LaunchDelegate* obj) {} void ReleaseCallee(ProxyFactory::LaunchDelegate* obj) {} }; template <> struct RunnableMethodTraits { void RetainCallee(MockProxyFactory* obj) {} void ReleaseCallee(MockProxyFactory* obj) {} }; template <> struct RunnableMethodTraits { void RetainCallee(ChromeFrameAutomationClient* obj) {} void ReleaseCallee(ChromeFrameAutomationClient* obj) {} }; // MessageLoopForUI wrapper that runs only for a limited time. // We need a UI message loop in the main thread. struct TimedMsgLoop { public: void RunFor(int seconds) { QuitAfter(seconds); loop_.MessageLoop::Run(); } void Quit() { loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask); } void QuitAfter(int seconds) { loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds); } MessageLoopForUI loop_; }; template <> struct RunnableMethodTraits { void RetainCallee(TimedMsgLoop* obj) {} void ReleaseCallee(TimedMsgLoop* obj) {} }; // Saves typing. It's somewhat hard to create a wrapper around // testing::InvokeWithoutArgs since it returns a // non-public (testing::internal) type. #define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\ CreateFunctor(&loop, &TimedMsgLoop::Quit)) #define QUIT_LOOP_SOON(loop, seconds) testing::InvokeWithoutArgs(\ CreateFunctor(&loop, &TimedMsgLoop::QuitAfter, seconds)) // We mock ChromeFrameDelegate only. The rest is with real AutomationProxy TEST(CFACWithChrome, CreateTooFast) { MockCFDelegate cfd; TimedMsgLoop loop; int timeout = 0; // Chrome cannot send Hello message so fast. const std::wstring profile = L"Adam.N.Epilinter"; scoped_ptr client; client.reset(new ChromeFrameAutomationClient()); EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(AUTOMATION_TIMEOUT, testing::_)) .Times(1) .WillOnce(QUIT_LOOP(loop)); EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false)); loop.RunFor(10); client->Uninitialize(); } // This test may fail if Chrome take more that 10 seconds (timeout var) to // launch. In this case GMock shall print something like "unexpected call to // OnAutomationServerLaunchFailed". I'm yet to find out how to specify // that this is an unexpected call, and still to execute and action. TEST(CFACWithChrome, CreateNotSoFast) { MockCFDelegate cfd; TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; int timeout = 10000; scoped_ptr client; client.reset(new ChromeFrameAutomationClient); EXPECT_CALL(cfd, OnAutomationServerReady()) .Times(1) .WillOnce(QUIT_LOOP(loop)); EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(testing::_, testing::_)) .Times(0); EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false)); loop.RunFor(11); client->Uninitialize(); client.reset(NULL); } MATCHER_P(MsgType, msg_type, "IPC::Message::type()") { const IPC::Message& m = arg; return (m.type() == msg_type); } MATCHER_P(EqNavigationInfoUrl, url, "IPC::NavigationInfo matcher") { if (url.is_valid() && url != arg.url) return false; // TODO(stevet): other members return true; } TEST(CFACWithChrome, NavigateOk) { MockCFDelegate cfd; TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; const std::string url = "about:version"; int timeout = 10000; scoped_ptr client; client.reset(new ChromeFrameAutomationClient); EXPECT_CALL(cfd, OnAutomationServerReady()) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor( client.get(), &ChromeFrameAutomationClient::InitiateNavigation, url, std::string(), false)))); // cfd.SetOnNavigationStateChanged(); EXPECT_CALL(cfd, OnNavigationStateChanged(testing::_, testing::_)) .Times(testing::AnyNumber()); { testing::InSequence s; EXPECT_CALL(cfd, OnDidNavigate(testing::_, EqNavigationInfoUrl(GURL()))) .Times(1); EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_)).Times(1); EXPECT_CALL(cfd, OnLoad(testing::_, testing::_)) .Times(1) .WillOnce(QUIT_LOOP(loop)); } EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false)); loop.RunFor(10); client->Uninitialize(); client.reset(NULL); } // Bug: http://b/issue?id=2033644 TEST(CFACWithChrome, DISABLED_NavigateFailed) { MockCFDelegate cfd; TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; const std::string url = "http://127.0.0.3:65412/"; int timeout = 10000; scoped_ptr client; client.reset(new ChromeFrameAutomationClient); EXPECT_CALL(cfd, OnAutomationServerReady()) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor( client.get(), &ChromeFrameAutomationClient::InitiateNavigation, url, std::string(), false)))); EXPECT_CALL(cfd, OnNavigationStateChanged(testing::_, testing::_)) .Times(testing::AnyNumber()); EXPECT_CALL(cfd, OnNavigationFailed(testing::_, testing::_, testing::_)) .Times(1); EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_)) .Times(testing::AnyNumber()); EXPECT_CALL(cfd, OnLoad(testing::_, testing::_)) .Times(0); EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false)); loop.RunFor(10); client->Uninitialize(); client.reset(NULL); } MATCHER_P(EqURLRequest, x, "IPC::AutomationURLRequest matcher") { if (arg.url != x.url) return false; if (arg.method != x.method) return false; if (arg.referrer != x.referrer) return false; if (arg.extra_request_headers != x.extra_request_headers) return false; // TODO(stevet): uploaddata member return true; } MATCHER_P(EqUrlGet, url, "Quick URL matcher for 'HTTP GET' request") { if (arg.url != url) return false; if (arg.method != "GET") return false; return true; } TEST(CFACWithChrome, UseHostNetworkStack) { MockCFDelegate cfd; TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; const std::string url = "http://bongo.com"; int timeout = 10000; scoped_ptr client; client.reset(new ChromeFrameAutomationClient); client->set_use_chrome_network(false); cfd.SetAutomationSender(client.get()); EXPECT_CALL(cfd, OnAutomationServerReady()) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor( client.get(), &ChromeFrameAutomationClient::InitiateNavigation, url, std::string(), false)))); EXPECT_CALL(cfd, OnNavigationStateChanged(testing::_, testing::_)) .Times(testing::AnyNumber()); EXPECT_CALL(cfd, GetBounds(testing::_)) .Times(testing::AtMost(1)); EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_)) .Times(testing::AnyNumber()); // Note slash appending to the url string, because of GURL inside chrome const IPC::AutomationURLResponse found = {"", "HTTP/0.9 200\r\n\r\n\r\n", }; // Hard coded tab and request ids static const int tab_id = 1; int request_id = 2; EXPECT_CALL(cfd, OnRequestStart(tab_id, request_id, EqUrlGet(url + '/'))) .Times(1) .WillOnce(testing::Invoke(CreateFunctor(&cfd, &MockCFDelegate::ReplyStarted, &found))); // Return some trivial page, that have a link to a "logo.gif" image const std::string data = "Hello" ""; EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::Ge(0))) .Times(2) .WillOnce(testing::Invoke(CreateFunctor(&cfd, &MockCFDelegate::ReplyData, &data))) .WillOnce(testing::WithArgs<0, 1>(testing::Invoke(CreateFunctor(&cfd, &MockCFDelegate::ReplyEOF)))); EXPECT_CALL(cfd, OnDidNavigate(tab_id, EqNavigationInfoUrl(GURL(url)))) .Times(1); EXPECT_CALL(cfd, OnLoad(tab_id, GURL(url))) .Times(1); // Expect request for logo.gif request_id++; EXPECT_CALL(cfd, OnRequestStart(tab_id, request_id, EqUrlGet(url + "/logo.gif"))) .Times(1) .WillOnce(testing::Invoke(CreateFunctor(&cfd, &MockCFDelegate::Reply404))); EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::_)) .Times(testing::AtMost(1)); // Chrome makes a brave request for favicon.ico request_id++; EXPECT_CALL(cfd, OnRequestStart(tab_id, request_id, EqUrlGet(url + "/favicon.ico"))) .Times(1) .WillOnce(testing::Invoke(CreateFunctor(&cfd, &MockCFDelegate::Reply404))); EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::_)) .Times(testing::AtMost(1)); bool incognito = true; EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", incognito)); loop.RunFor(10); client->Uninitialize(); client.reset(NULL); } // [CFAC] -- uses a ProxyFactory for creation of ChromeFrameAutomationProxy // -- uses ChromeFrameAutomationProxy // -- uses TabProxy obtained from ChromeFrameAutomationProxy // -- uses ChromeFrameDelegate as outgoing interface // // We mock ProxyFactory to return mock object (MockAutomationProxy) implementing // ChromeFrameAutomationProxy interface. // Since CFAC uses TabProxy for few calls and TabProxy is not easy mockable, // we create 'real' TabProxy but with fake AutomationSender (the one responsible // for sending messages over channel). // Additionally we have mock implementation ChromeFrameDelagate interface - // MockCFDelegate. // Test fixture, saves typing all of it's members. class CFACMockTest : public testing::Test { public: MockProxyFactory factory_; MockCFDelegate cfd_; TimedMsgLoop loop_; MockAutomationProxy proxy_; scoped_ptr tracker_; MockAutomationMessageSender dummy_sender_; scoped_refptr tab_; scoped_ptr client_; // the victim of all tests std::wstring profile_; int timeout_; void* id_; // Automation server id we are going to return int tab_handle_; // Tab handle. Any non-zero value is Ok. inline ChromeFrameAutomationProxy* get_proxy() { return static_cast(&proxy_); } inline void CreateTab() { ASSERT_EQ(NULL, tab_.get()); tab_ = new TabProxy(&dummy_sender_, tracker_.get(), tab_handle_); } // Easy methods to set expectations. void SetAutomationServerOk() { EXPECT_CALL(factory_, GetAutomationServer(testing::Eq(timeout_), testing::StrEq(profile_), testing::_, testing::_, testing::NotNull())) .Times(1) .WillOnce(testing::DoAll( testing::WithArgs<0, 4>( testing::Invoke(CreateFunctor(&factory_, &MockProxyFactory::GetServerImpl, get_proxy(), AUTOMATION_SUCCESS))), testing::Return(id_))); EXPECT_CALL(factory_, ReleaseAutomationServer(testing::Eq(id_))).Times(1); } void Set_CFD_LaunchFailed(AutomationLaunchResult result) { EXPECT_CALL(cfd_, OnAutomationServerLaunchFailed( testing::Eq(result), testing::_)) .Times(1) .WillOnce(QUIT_LOOP(loop_)); } protected: CFACMockTest() : tracker_(NULL), timeout_(500), profile_(L"Adam.N.Epilinter") { id_ = reinterpret_cast(5); tab_handle_ = 3; } virtual void SetUp() { dummy_sender_.ForwardTo(&proxy_); tracker_.reset(new AutomationHandleTracker(&dummy_sender_)); client_.reset(new ChromeFrameAutomationClient); client_->set_proxy_factory(&factory_); } }; // Could be implemented as MockAutomationProxy member (we have WithArgs<>!) ACTION_P3(HandleCreateTab, tab_handle, external_tab_container, tab_wnd) { // arg0 - message // arg1 - callback // arg2 - key CallbackRunner >* c = reinterpret_cast >*>(arg1); c->Run(external_tab_container, tab_wnd, tab_handle); delete c; delete arg0; } TEST_F(CFACMockTest, MockedCreateTabOk) { int timeout = 500; CreateTab(); SetAutomationServerOk(); EXPECT_CALL(proxy_, server_version()).Times(testing::AnyNumber()) .WillRepeatedly(testing::Return("")); // We need some valid HWNDs, when responding to CreateExternalTab HWND h1 = ::GetDesktopWindow(); HWND h2 = ::GetDesktopWindow(); EXPECT_CALL(proxy_, SendAsAsync(testing::Property(&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab__ID), testing::NotNull(), testing::_)) .Times(1) .WillOnce(HandleCreateTab(tab_handle_, h1, h2)); EXPECT_CALL(proxy_, CreateTabProxy(testing::Eq(tab_handle_))) .WillOnce(testing::Return(tab_)); EXPECT_CALL(cfd_, OnAutomationServerReady()) .WillOnce(QUIT_LOOP(loop_)); // Here we go! EXPECT_TRUE(client_->Initialize(&cfd_, timeout, false, profile_, L"", false)); loop_.RunFor(10); client_->Uninitialize(); } TEST_F(CFACMockTest, MockedCreateTabFailed) { HWND null_wnd = NULL; SetAutomationServerOk(); EXPECT_CALL(proxy_, server_version()).Times(testing::AnyNumber()) .WillRepeatedly(testing::Return("")); EXPECT_CALL(proxy_, SendAsAsync(testing::Property(&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab__ID), testing::NotNull(), testing::_)) .Times(1) .WillOnce(HandleCreateTab(tab_handle_, null_wnd, null_wnd)); EXPECT_CALL(proxy_, CreateTabProxy(testing::_)).Times(0); Set_CFD_LaunchFailed(AUTOMATION_CREATE_TAB_FAILED); // Here we go! EXPECT_TRUE(client_->Initialize(&cfd_, timeout_, false, profile_, L"", false)); loop_.RunFor(4); client_->Uninitialize(); } const wchar_t kMetaTagPage[] = L"files/meta_tag.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_MetaTag) { SimpleBrowserTest(IE, kMetaTagPage, L"meta_tag"); } const wchar_t kCFProtocolPage[] = L"files/cf_protocol.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFProtocol) { SimpleBrowserTest(IE, kCFProtocolPage, L"chrome_frame_protocol"); } const wchar_t kPersistentCookieTest[] = L"files/persistent_cookie_test_page.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_PersistentCookieTest) { SimpleBrowserTest(IE, kPersistentCookieTest, L"PersistentCookieTest"); } const wchar_t kNavigateOutPage[] = L"files/navigate_out.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_NavigateOut) { SimpleBrowserTest(IE, kNavigateOutPage, L"navigate_out"); } const wchar_t kReferrerMainTest[] = L"files/referrer_main.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ReferrerTest) { SimpleBrowserTest(IE, kReferrerMainTest, L"FullTab_ReferrerTest"); } const wchar_t kSubFrameTestPage[] = L"files/full_tab_sub_frame_main.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_SubFrame) { SimpleBrowserTest(IE, kSubFrameTestPage, L"sub_frame"); } const wchar_t kSubIFrameTestPage[] = L"files/full_tab_sub_iframe_main.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_SubIFrame) { SimpleBrowserTest(IE, kSubIFrameTestPage, L"sub_frame"); } HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) { if (!web_browser) return E_INVALIDARG; ScopedComPtr web_browser2; HRESULT hr = CoCreateInstance( CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, reinterpret_cast(web_browser2.Receive())); if (SUCCEEDED(hr)) { *web_browser = web_browser2.Detach(); } return hr; } // WebBrowserEventSink member defines HRESULT WebBrowserEventSink::LaunchIEAndNavigate( const std::wstring& navigate_url, _IDispEvent* sink) { int major_version = 0; int minor_version = 0; int bugfix_version = 0; base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, &bugfix_version); if (major_version > 5) { DLOG(INFO) << __FUNCTION__ << " Not running test on Windows version: " << major_version; return S_FALSE; } EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2_.Receive())); web_browser2_->put_Visible(VARIANT_TRUE); HRESULT hr = sink->DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2); EXPECT_TRUE(hr == S_OK); VARIANT empty = ScopedVariant::kEmptyVariant; ScopedVariant url; url.Set(navigate_url.c_str()); hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty); EXPECT_TRUE(hr == S_OK); return hr; } const int kChromeFrameLongNavigationTimeoutInSeconds = 10; // This class provides functionality to add expectations to IE full tab mode // tests. class MockWebBrowserEventSink : public WebBrowserEventSink { public: // Needed to support PostTask. static bool ImplementsThreadSafeReferenceCounting() { return true; } MOCK_METHOD7_WITH_CALLTYPE(__stdcall, OnBeforeNavigate2, HRESULT (IDispatch* dispatch, // NOLINT VARIANT* url, VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, VARIANT_BOOL* cancel)); MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnNavigateComplete2, void (IDispatch* dispatch, // NOLINT VARIANT* url)); MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNewWindow3, void (IDispatch** dispatch, // NOLINT VARIANT_BOOL* Cancel, DWORD flags, BSTR url_context, BSTR url)); MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNavigateError, void (IDispatch* dispatch, // NOLINT VARIANT* url, VARIANT* frame_name, VARIANT* status_code, VARIANT* cancel)); }; using testing::_; const wchar_t kChromeFrameFileUrl[] = L"cf:file:///C:/"; TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) { TimedMsgLoop loop; // If a navigation fails then IE issues a navigation to an interstitial // page. Catch this to track navigation errors as the NavigateError // notification does not seem to fire reliably. CComObjectStackEx mock; EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kChromeFrameFileUrl)), _, _, _, _, _)) .Times(1) .WillOnce(testing::Return(S_OK)); EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StartsWith(L"res:")), _, _, _, _, _)) .Times(1) .WillOnce(testing::DoAll( QUIT_LOOP(loop), testing::Return(S_OK))); HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFileUrl, &mock); ASSERT_HRESULT_SUCCEEDED(hr); if (hr == S_FALSE) return; ASSERT_TRUE(mock.web_browser2() != NULL); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); mock.Uninitialize(); chrome_frame_test::CloseAllIEWindows(); } const wchar_t kChromeFrameFullTabWindowOpenTestUrl[] = L"http://localhost:1337/files/chrome_frame_window_open.html"; const wchar_t kChromeFrameFullTabWindowOpenPopupUrl[] = L"http://localhost:1337/files/chrome_frame_window_open_popup.html"; // This test checks if window.open calls issued by a full tab mode ChromeFrame // instance make it back to IE and then transitions back to Chrome as the // window.open target page is supposed to render within Chrome. TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowOpen) { TimedMsgLoop loop; CComObjectStackEx mock; EXPECT_CALL(mock, OnBeforeNavigate2( _, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kChromeFrameFullTabWindowOpenTestUrl)), _, _, _, _, _)) .Times(1) .WillOnce(testing::Return(S_OK)); EXPECT_CALL(mock, OnBeforeNavigate2( _, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kChromeFrameFullTabWindowOpenPopupUrl)), _, _, _, _, _)) .Times(1) .WillOnce(testing::DoAll( QUIT_LOOP_SOON(loop, 2), testing::Return(S_OK))); HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFullTabWindowOpenTestUrl, &mock); ASSERT_HRESULT_SUCCEEDED(hr); if (hr == S_FALSE) return; ASSERT_TRUE(mock.web_browser2() != NULL); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); ASSERT_TRUE(CheckResultFile(L"ChromeFrameWindowOpenPopup", "OK")); mock.Uninitialize(); chrome_frame_test::CloseAllIEWindows(); } const wchar_t kChromeFrameAboutBlankUrl[] = L"cf:about:blank"; const wchar_t kChromeFrameAboutVersion[] = L"cf:about:version"; // This test launches chrome frame in full tab mode in IE by having IE navigate // to cf:about:blank. It then looks for the chrome renderer window and posts // the WM_RBUTTONDOWN/WM_RBUTTONUP messages to it, which bring up the context // menu. This is followed by keyboard messages sent via SendInput to select // the About chrome frame menu option, which would then bring up a new window // with the chrome revision. The test finally checks for success by comparing // the URL of the window being opened with cf:about:version, which indicates // that the operation succeeded. TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) { TimedMsgLoop loop; CComObjectStackEx mock; EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kChromeFrameAboutBlankUrl)), _, _, _, _, _)) .Times(1) .WillOnce(testing::Return(S_OK)); EXPECT_CALL(mock, OnNavigateComplete2(_, _)) .Times(1) .WillOnce(testing::InvokeWithoutArgs( &chrome_frame_test::ShowChromeFrameContextMenu)); EXPECT_CALL(mock, OnNewWindow3(_, _, _, _, testing::StrCaseEq(kChromeFrameAboutVersion))) .Times(1) .WillOnce(QUIT_LOOP(loop)); HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameAboutBlankUrl, &mock); ASSERT_HRESULT_SUCCEEDED(hr); if (hr == S_FALSE) return; ASSERT_TRUE(mock.web_browser2() != NULL); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); mock.Uninitialize(); chrome_frame_test::CloseAllIEWindows(); }