diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-09 01:09:28 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-09 01:09:28 +0000 |
commit | 7bc272f38646abb81b58c89a59d8e6842f9e9631 (patch) | |
tree | 8e3c884ad1549c445e86925df673fcd0d8285d1d /chrome_frame/test | |
parent | 0923559a1a020690c1d199fda3c55f67d2d54335 (diff) | |
download | chromium_src-7bc272f38646abb81b58c89a59d8e6842f9e9631.zip chromium_src-7bc272f38646abb81b58c89a59d8e6842f9e9631.tar.gz chromium_src-7bc272f38646abb81b58c89a59d8e6842f9e9631.tar.bz2 |
Added support for running reliability tests for ChromeFrame on similar lines as Chrome. We only run these
tests for IE at this point. The reliability test code for Chrome has been copied and modified accordingly.
Other related changes in this CL include the following:-
1. If ChromeFrame is running in headless mode determined by a registry value in HKCU\Software\Google\ChromeFrame
we initialize ChromeFrame crash reporting and connect to the Chrome crash server. This would enable us to
gather crash dumps from the reliability test runs and report the same.
2. The LowIntegrity fixes for the WebBrowser which Stoyan had done a while back are only needed for IE7 on Vista.
For this CL though we just do the requisite hacks if the OS is Vista. For Windows7 the returned IWebBrowser
interface pointer works fine.
3. I moved the WebBrowserEventSink to chrome_frame_test_utils as this class is now shared.
Fixes portions of http://code.google.com/p/chromium/issues/detail?id=29451
Bug=29451
Review URL: http://codereview.chromium.org/465074
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34119 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/test')
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 239 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.h | 188 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_unittests.cc | 305 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_unittests.h | 127 | ||||
-rw-r--r-- | chrome_frame/test/reliability/page_load_test.cc | 624 | ||||
-rw-r--r-- | chrome_frame/test/reliability/page_load_test.h | 17 | ||||
-rw-r--r-- | chrome_frame/test/reliability/reliability_test_suite.h | 30 | ||||
-rw-r--r-- | chrome_frame/test/reliability/run_all_unittests.cc | 10 |
8 files changed, 1156 insertions, 384 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index 8777651..9f2a6de 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -16,6 +16,7 @@ #include "base/string_util.h" #include "base/win_util.h" #include "chrome/common/chrome_switches.h" +#include "chrome_frame/utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace chrome_frame_test { @@ -623,4 +624,242 @@ bool LowIntegrityToken::IsImpersonated() { return false; } +HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) { + if (!web_browser) + return E_INVALIDARG; + + HRESULT hr = S_OK; + DWORD cocreate_flags = CLSCTX_LOCAL_SERVER; + chrome_frame_test::LowIntegrityToken token; + // Vista has a bug which manifests itself when a medium integrity process + // launches a COM server like IE which runs in protected mode due to UAC. + // This causes the IWebBrowser2 interface which is returned to be useless, + // i.e it does not receive any events, etc. Our workaround for this is + // to impersonate a low integrity token and then launch IE. + if (win_util::GetWinVersion() == win_util::WINVERSION_VISTA) { + // Create medium integrity browser that will launch IE broker. + ScopedComPtr<IWebBrowser2> medium_integrity_browser; + hr = medium_integrity_browser.CreateInstance(CLSID_InternetExplorer, NULL, + CLSCTX_LOCAL_SERVER); + if (FAILED(hr)) + return hr; + medium_integrity_browser->Quit(); + // Broker remains alive. + if (!token.Impersonate()) { + hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; + } + + cocreate_flags |= CLSCTX_ENABLE_CLOAKING; + } + + hr = ::CoCreateInstance(CLSID_InternetExplorer, NULL, + cocreate_flags, IID_IWebBrowser2, + reinterpret_cast<void**>(web_browser)); + // ~LowIntegrityToken() will switch integrity back to medium. + return hr; +} + +_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 + } +}; + +_ATL_FUNC_INFO WebBrowserEventSink::kVoidMethodInfo = { + CC_STDCALL, VT_EMPTY, 0, {NULL}}; + +_ATL_FUNC_INFO WebBrowserEventSink::kDocumentCompleteInfo = { + CC_STDCALL, VT_EMPTY, 2, { + VT_DISPATCH, + VT_VARIANT | VT_BYREF + } +}; + +// WebBrowserEventSink member defines +void WebBrowserEventSink::Uninitialize() { + DisconnectFromChromeFrame(); + if (web_browser2_.get()) { + DispEventUnadvise(web_browser2_); + web_browser2_->Quit(); + web_browser2_.Release(); + } +} + +STDMETHODIMP WebBrowserEventSink::OnBeforeNavigate2Internal( + IDispatch* dispatch, VARIANT* url, VARIANT* flags, + VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, + VARIANT_BOOL* cancel) { + DLOG(INFO) << __FUNCTION__; + // Reset any existing reference to chrome frame since this is a new + // navigation. + chrome_frame_ = NULL; + return OnBeforeNavigate2(dispatch, url, flags, target_frame_name, + post_data, headers, cancel); +} + +STDMETHODIMP_(void) WebBrowserEventSink::OnNavigateComplete2Internal( + IDispatch* dispatch, VARIANT* url) { + DLOG(INFO) << __FUNCTION__; + ConnectToChromeFrame(); + OnNavigateComplete2(dispatch, url); +} + +STDMETHODIMP_(void) WebBrowserEventSink::OnDocumentCompleteInternal( + IDispatch* dispatch, VARIANT* url) { + DLOG(INFO) << __FUNCTION__; + OnDocumentComplete(dispatch, url); +} + +HRESULT WebBrowserEventSink::OnLoadInternal(const VARIANT* param) { + DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; + OnLoad(param->bstrVal); + return S_OK; +} + +HRESULT WebBrowserEventSink::OnLoadErrorInternal(const VARIANT* param) { + DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; + OnLoadError(param->bstrVal); + return S_OK; +} + +HRESULT WebBrowserEventSink::OnMessageInternal(const VARIANT* param) { + DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; + OnMessage(param->bstrVal); + return S_OK; +} + +HRESULT WebBrowserEventSink::LaunchIEAndNavigate( + const std::wstring& navigate_url) { + HRESULT hr = LaunchIEAsComServer(web_browser2_.Receive()); + EXPECT_EQ(S_OK, hr); + if (hr == S_OK) { + web_browser2_->put_Visible(VARIANT_TRUE); + hr = DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2); + EXPECT_TRUE(hr == S_OK); + hr = Navigate(navigate_url); + } + return hr; +} + +HRESULT WebBrowserEventSink::Navigate(const std::wstring& navigate_url) { + VARIANT empty = ScopedVariant::kEmptyVariant; + ScopedVariant url; + url.Set(navigate_url.c_str()); + + HRESULT hr = S_OK; + hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty); + EXPECT_TRUE(hr == S_OK); + return hr; +} + +void WebBrowserEventSink::SetFocusToChrome() { + chrome_frame_test::SetKeyboardFocusToWindow( + GetAttachedChromeRendererWindow(), 1, 1); +} + +void WebBrowserEventSink::SendInputToChrome( + const std::string& input_string) { + chrome_frame_test::SendInputToWindow( + GetAttachedChromeRendererWindow(), input_string); +} + +void WebBrowserEventSink::ConnectToChromeFrame() { + DCHECK(web_browser2_); + ScopedComPtr<IShellBrowser> shell_browser; + DoQueryService(SID_STopLevelBrowser, web_browser2_, + shell_browser.Receive()); + + if (shell_browser) { + ScopedComPtr<IShellView> shell_view; + shell_browser->QueryActiveShellView(shell_view.Receive()); + if (shell_view) { + shell_view->GetItemObject(SVGIO_BACKGROUND, __uuidof(IChromeFrame), + reinterpret_cast<void**>(chrome_frame_.Receive())); + } + + if (chrome_frame_) { + ScopedVariant onmessage(onmessage_.ToDispatch()); + ScopedVariant onloaderror(onloaderror_.ToDispatch()); + ScopedVariant onload(onload_.ToDispatch()); + EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onmessage(onmessage)); + EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onloaderror(onloaderror)); + EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onload(onload)); + } + } +} + +void WebBrowserEventSink::DisconnectFromChromeFrame() { + if (chrome_frame_) { + ScopedVariant dummy(static_cast<IDispatch*>(NULL)); + chrome_frame_->put_onmessage(dummy); + chrome_frame_->put_onload(dummy); + chrome_frame_->put_onloaderror(dummy); + chrome_frame_.Release(); + } +} + +HWND WebBrowserEventSink::GetAttachedChromeRendererWindow() { + DCHECK(chrome_frame_); + HWND renderer_window = NULL; + ScopedComPtr<IOleWindow> ole_window; + ole_window.QueryFrom(chrome_frame_); + EXPECT_TRUE(ole_window.get()); + + if (ole_window) { + HWND activex_window = NULL; + ole_window->GetWindow(&activex_window); + EXPECT_TRUE(IsWindow(activex_window)); + + // chrome tab window is the first (and the only) child of activex + HWND chrome_tab_window = GetWindow(activex_window, GW_CHILD); + EXPECT_TRUE(IsWindow(chrome_tab_window)); + renderer_window = GetWindow(chrome_tab_window, GW_CHILD); + } + + DCHECK(IsWindow(renderer_window)); + return renderer_window; +} + +HRESULT WebBrowserEventSink::SetWebBrowser(IWebBrowser2* web_browser2) { + DCHECK(web_browser2_.get() == NULL); + web_browser2_ = web_browser2; + web_browser2_->put_Visible(VARIANT_TRUE); + HRESULT hr = DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2); + return hr; +} + } // 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 2947539..277fc52 100644 --- a/chrome_frame/test/chrome_frame_test_utils.h +++ b/chrome_frame/test/chrome_frame_test_utils.h @@ -5,10 +5,25 @@ #ifndef CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_ #define CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_ +#include <atlbase.h> +#include <atlcom.h> +#include <string> +#include <exdisp.h> +#include <exdispid.h> +#include <mshtml.h> +#include <shlguid.h> +#include <shobjidl.h> #include <windows.h> #include "base/basictypes.h" +#include "base/message_loop.h" #include "base/process_util.h" +#include "base/scoped_comptr_win.h" +#include "base/scoped_variant_win.h" + +#include "chrome_frame/test_utils.h" +// Include without path to make GYP build see it. +#include "chrome_tab.h" // NOLINT namespace chrome_frame_test { @@ -90,6 +105,179 @@ class LowIntegrityToken { bool impersonated_; }; +// MessageLoopForUI wrapper that runs only for a limited time. +// We need a UI message loop in the main thread. +class TimedMsgLoop { + public: + void RunFor(int seconds) { + QuitAfter(seconds); + loop_.MessageLoop::Run(); + } + + void PostDelayedTask( + const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { + loop_.PostDelayedTask(from_here, task, delay_ms); + } + + void Quit() { + loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask); + } + + void QuitAfter(int seconds) { + loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds); + } + + MessageLoopForUI loop_; +}; + +// Launches IE as a COM server and returns the corresponding IWebBrowser2 +// interface pointer. +// Returns S_OK on success. +HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser); + +#ifndef DISPID_NEWPROCESS +#define DISPID_NEWPROCESS 284 +#endif // DISPID_NEWPROCESS + +// This class sets up event sinks to the IWebBrowser interface. Currently it +// subscribes to the following events:- +// 1. DISPID_BEFORENAVIGATE2 +// 2. DISPID_NAVIGATEERROR +// 3. DISPID_NAVIGATECOMPLETE2 +// 4. DISPID_NEWWINDOW3 +// 5. DISPID_DOCUMENTCOMPLETE +// Other events can be subscribed to on an if needed basis. +class WebBrowserEventSink + : public CComObjectRootEx<CComMultiThreadModel>, + public IDispEventSimpleImpl<0, WebBrowserEventSink, + &DIID_DWebBrowserEvents2> { + public: + typedef IDispEventSimpleImpl<0, WebBrowserEventSink, + &DIID_DWebBrowserEvents2> DispEventsImpl; + WebBrowserEventSink() + : ALLOW_THIS_IN_INITIALIZER_LIST( + onmessage_(this, &WebBrowserEventSink::OnMessageInternal)), + ALLOW_THIS_IN_INITIALIZER_LIST( + onloaderror_(this, &WebBrowserEventSink::OnLoadErrorInternal)), + ALLOW_THIS_IN_INITIALIZER_LIST( + onload_(this, &WebBrowserEventSink::OnLoadInternal)) { + } + + ~WebBrowserEventSink() { + Uninitialize(); + } + + void Uninitialize(); + + // Helper function to launch IE and navigate to a URL. + // Returns S_OK on success, S_FALSE if the test was not run, other + // errors on failure. + HRESULT LaunchIEAndNavigate(const std::wstring& navigate_url); + + virtual HRESULT Navigate(const std::wstring& navigate_url); + + // Set input focus to chrome frame window. + void SetFocusToChrome(); + + // Send keyboard input to the renderer window hosted in chrome using + // SendInput API + void SendInputToChrome(const std::string& input_string); + +BEGIN_COM_MAP(WebBrowserEventSink) +END_COM_MAP() + +BEGIN_SINK_MAP(WebBrowserEventSink) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, + OnBeforeNavigate2Internal, &kBeforeNavigate2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, + OnDownloadBegin, &kVoidMethodInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, + OnNavigateComplete2Internal, &kNavigateComplete2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, + OnNavigateError, &kNavigateErrorInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, + OnNewWindow3, &kNewWindow3Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, + OnDocumentCompleteInternal, &kDocumentCompleteInfo) +END_SINK_MAP() + + STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url, + VARIANT* frame_name, VARIANT* status_code, + VARIANT* cancel) { + DLOG(INFO) << __FUNCTION__; + } + + STDMETHOD(OnBeforeNavigate2)(IDispatch* dispatch, VARIANT* url, VARIANT* + flags, VARIANT* target_frame_name, + VARIANT* post_data, VARIANT* headers, + VARIANT_BOOL* cancel) { + return S_OK; + } + + STDMETHOD(OnBeforeNavigate2Internal)(IDispatch* dispatch, VARIANT* url, + VARIANT* flags, + VARIANT* target_frame_name, + VARIANT* post_data, VARIANT* headers, + VARIANT_BOOL* cancel); + STDMETHOD_(void, OnDownloadBegin)() {} + STDMETHOD_(void, OnNavigateComplete2Internal)(IDispatch* dispatch, + VARIANT* url); + STDMETHOD_(void, OnNavigateComplete2)(IDispatch* dispatch, VARIANT* url) {} + STDMETHOD_(void, OnNewWindow3)(IDispatch** dispatch, VARIANT_BOOL* Cancel, + DWORD flags, BSTR url_context, BSTR url) {} + + STDMETHOD_(void, OnDocumentCompleteInternal)(IDispatch* dispatch, + VARIANT* url); + + STDMETHOD_(void, OnDocumentComplete)(IDispatch* dispatch, + VARIANT* url) {} +#ifdef _DEBUG + STDMETHOD(Invoke)(DISPID dispid, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS* params, VARIANT* result, + EXCEPINFO* except_info, UINT* arg_error) { + DLOG(INFO) << __FUNCTION__ << L" disp id :" << dispid; + return DispEventsImpl::Invoke(dispid, riid, lcid, flags, params, result, + except_info, arg_error); + } +#endif // _DEBUG + + // Chrome frame callbacks + virtual void OnLoad(const wchar_t* url) {} + virtual void OnLoadError(const wchar_t* url) {} + virtual void OnMessage(const wchar_t* message) {} + + IWebBrowser2* web_browser2() { + return web_browser2_.get(); + } + + HRESULT SetWebBrowser(IWebBrowser2* web_browser2); + + protected: + // IChromeFrame callbacks + HRESULT OnLoadInternal(const VARIANT* param); + HRESULT OnLoadErrorInternal(const VARIANT* param); + HRESULT OnMessageInternal(const VARIANT* param); + + void ConnectToChromeFrame(); + void DisconnectFromChromeFrame(); + HWND GetAttachedChromeRendererWindow(); + + public: + ScopedComPtr<IWebBrowser2> web_browser2_; + ScopedComPtr<IChromeFrame> chrome_frame_; + DispCallback<WebBrowserEventSink> onmessage_; + DispCallback<WebBrowserEventSink> onloaderror_; + DispCallback<WebBrowserEventSink> onload_; + + protected: + static _ATL_FUNC_INFO kBeforeNavigate2Info; + static _ATL_FUNC_INFO kNavigateComplete2Info; + static _ATL_FUNC_INFO kNavigateErrorInfo; + static _ATL_FUNC_INFO kNewWindow3Info; + static _ATL_FUNC_INFO kVoidMethodInfo; + static _ATL_FUNC_INFO kDocumentCompleteInfo; +}; + } // namespace chrome_frame_test #endif // CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_ diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc index 81edf87..ea7de65 100644 --- a/chrome_frame/test/chrome_frame_unittests.cc +++ b/chrome_frame/test/chrome_frame_unittests.cc @@ -37,48 +37,6 @@ 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 - } -}; - -_ATL_FUNC_INFO WebBrowserEventSink::kVoidMethodInfo = { - CC_STDCALL, VT_EMPTY, 0, {NULL}}; - void ChromeFrameTestWithWebServer::CloseAllBrowsers() { // Web browsers tend to relaunch themselves in other processes, meaning the // KillProcess stuff above might not have actually cleaned up all our browser @@ -582,7 +540,6 @@ TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceDefaultCtor) { SimpleBrowserTest(FIREFOX, kCFIDefaultCtorPage, L"CFInstanceDefaultCtor"); } - const wchar_t kCFInstallBasicTestPage[] = L"files/CFInstall_basic.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallBasic) { @@ -850,49 +807,25 @@ template <> struct RunnableMethodTraits<ChromeFrameAutomationClient> { 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 PostDelayedTask( - const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { - loop_.PostDelayedTask(from_here, task, delay_ms); - } - - 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<TimedMsgLoop> { - void RetainCallee(TimedMsgLoop* obj) {} - void ReleaseCallee(TimedMsgLoop* obj) {} +template <> struct RunnableMethodTraits<chrome_frame_test::TimedMsgLoop> { + void RetainCallee(chrome_frame_test::TimedMsgLoop* obj) {} + void ReleaseCallee(chrome_frame_test::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)) + CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::Quit)) #define QUIT_LOOP_SOON(loop, seconds) testing::InvokeWithoutArgs(\ - CreateFunctor(&loop, &TimedMsgLoop::QuitAfter, seconds)) + CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::QuitAfter, \ + seconds)) // We mock ChromeFrameDelegate only. The rest is with real AutomationProxy TEST(CFACWithChrome, CreateTooFast) { MockCFDelegate cfd; - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; int timeout = 0; // Chrome cannot send Hello message so fast. const std::wstring profile = L"Adam.N.Epilinter"; @@ -915,7 +848,7 @@ TEST(CFACWithChrome, CreateTooFast) { // that this is an unexpected call, and still to execute and action. TEST(CFACWithChrome, CreateNotSoFast) { MockCFDelegate cfd; - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; int timeout = 10000; @@ -950,7 +883,7 @@ MATCHER_P(EqNavigationInfoUrl, url, "IPC::NavigationInfo matcher") { TEST(CFACWithChrome, NavigateOk) { MockCFDelegate cfd; - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; const std::string url = "about:version"; int timeout = 10000; @@ -990,7 +923,7 @@ TEST(CFACWithChrome, NavigateOk) { // Bug: http://b/issue?id=2033644 TEST(CFACWithChrome, DISABLED_NavigateFailed) { MockCFDelegate cfd; - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; const std::wstring profile = L"Adam.N.Epilinter"; const std::string url = "http://127.0.0.3:65412/"; int timeout = 10000; @@ -1041,7 +974,7 @@ class CFACMockTest : public testing::Test { public: MockProxyFactory factory_; MockCFDelegate cfd_; - TimedMsgLoop loop_; + chrome_frame_test::TimedMsgLoop loop_; MockAutomationProxy proxy_; scoped_ptr<AutomationHandleTracker> tracker_; MockAutomationMessageSender dummy_sender_; @@ -1205,170 +1138,12 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_SubIFrame) { SimpleBrowserTest(IE, kSubIFrameTestPage, L"sub_frame"); } -HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) { - if (!web_browser) - return E_INVALIDARG; - - HRESULT hr = S_OK; - DWORD cocreate_flags = CLSCTX_LOCAL_SERVER; - chrome_frame_test::LowIntegrityToken token; - if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { - // Create medium integrity browser that will launch IE broker. - ScopedComPtr<IWebBrowser2> medium_integrity_browser; - hr = medium_integrity_browser.CreateInstance(CLSID_InternetExplorer, NULL, - CLSCTX_LOCAL_SERVER); - if (FAILED(hr)) - return hr; - medium_integrity_browser->Quit(); - // Broker remains alive. - if (!token.Impersonate()) { - hr = HRESULT_FROM_WIN32(GetLastError()); - return hr; - } - - cocreate_flags |= CLSCTX_ENABLE_CLOAKING; - } - - hr = ::CoCreateInstance(CLSID_InternetExplorer, NULL, - cocreate_flags, IID_IWebBrowser2, - reinterpret_cast<void**>(web_browser)); - // ~LowIntegrityToken() will switch integrity back to medium. - return hr; -} - -// WebBrowserEventSink member defines -void WebBrowserEventSink::Uninitialize() { - chrome_frame_ = NULL; - if (web_browser2_.get()) { - DispEventUnadvise(web_browser2_); - web_browser2_->Quit(); - web_browser2_.Release(); - } -} - -STDMETHODIMP WebBrowserEventSink::OnBeforeNavigate2Internal( - IDispatch* dispatch, VARIANT* url, VARIANT* flags, - VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, - VARIANT_BOOL* cancel) { - DLOG(INFO) << __FUNCTION__; - // Reset any existing reference to chrome frame since this is a new - // navigation. - chrome_frame_ = NULL; - return OnBeforeNavigate2(dispatch, url, flags, target_frame_name, - post_data, headers, cancel); -} - -STDMETHODIMP_(void) WebBrowserEventSink::OnNavigateComplete2Internal( - IDispatch* dispatch, VARIANT* url) { - DLOG(INFO) << __FUNCTION__; - ConnectToChromeFrame(); - OnNavigateComplete2(dispatch, url); -} - -HRESULT WebBrowserEventSink::OnLoadInternal(const VARIANT* param) { - DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; - OnLoad(param->bstrVal); - return S_OK; -} - -HRESULT WebBrowserEventSink::OnLoadErrorInternal(const VARIANT* param) { - DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; - OnLoadError(param->bstrVal); - return S_OK; -} - -HRESULT WebBrowserEventSink::OnMessageInternal(const VARIANT* param) { - DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal; - OnMessage(param->bstrVal); - return S_OK; -} - -HRESULT WebBrowserEventSink::LaunchIEAndNavigate( - const std::wstring& navigate_url) { - HRESULT hr = LaunchIEAsComServer(web_browser2_.Receive()); - EXPECT_EQ(S_OK, hr); - if (hr == S_OK) { - web_browser2_->put_Visible(VARIANT_TRUE); - hr = DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2); - EXPECT_TRUE(hr == S_OK); - hr = Navigate(navigate_url); - } - return hr; -} - -HRESULT WebBrowserEventSink::Navigate(const std::wstring& navigate_url) { - VARIANT empty = ScopedVariant::kEmptyVariant; - ScopedVariant url; - url.Set(navigate_url.c_str()); - - HRESULT hr = S_OK; - hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty); - EXPECT_TRUE(hr == S_OK); - return hr; -} - -void WebBrowserEventSink::SetFocusToChrome() { - chrome_frame_test::SetKeyboardFocusToWindow(GetChromeRendererWindow(), 1, 1); -} - -void WebBrowserEventSink::SendInputToChrome( - const std::string& input_string) { - chrome_frame_test::SendInputToWindow(GetChromeRendererWindow(), input_string); -} - -void WebBrowserEventSink::ConnectToChromeFrame() { - DCHECK(web_browser2_); - ScopedComPtr<IShellBrowser> shell_browser; - DoQueryService(SID_STopLevelBrowser, web_browser2_, - shell_browser.Receive()); - - if (shell_browser) { - ScopedComPtr<IShellView> shell_view; - shell_browser->QueryActiveShellView(shell_view.Receive()); - if (shell_view) { - shell_view->GetItemObject(SVGIO_BACKGROUND, __uuidof(IChromeFrame), - reinterpret_cast<void**>(chrome_frame_.Receive())); - } - - if (chrome_frame_) { - ScopedVariant onmessage(onmessage_.ToDispatch()); - ScopedVariant onloaderror(onloaderror_.ToDispatch()); - ScopedVariant onload(onload_.ToDispatch()); - EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onmessage(onmessage)); - EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onloaderror(onloaderror)); - EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onload(onload)); - } - } -} - -HWND WebBrowserEventSink::GetChromeRendererWindow() { - DCHECK(chrome_frame_); - HWND renderer_window = NULL; - ScopedComPtr<IOleWindow> ole_window; - ole_window.QueryFrom(chrome_frame_); - EXPECT_TRUE(ole_window.get()); - - if (ole_window) { - HWND activex_window = NULL; - ole_window->GetWindow(&activex_window); - EXPECT_TRUE(IsWindow(activex_window)); - - // chrome tab window is the first (and the only) child of activex - HWND chrome_tab_window = GetWindow(activex_window, GW_CHILD); - EXPECT_TRUE(IsWindow(chrome_tab_window)); - renderer_window = GetWindow(chrome_tab_window, GW_CHILD); - } - - DCHECK(IsWindow(renderer_window)); - return renderer_window; -} - const int kChromeFrameLaunchDelay = 5; const int kChromeFrameLongNavigationTimeoutInSeconds = 10; // This class provides functionality to add expectations to IE full tab mode // tests. -class MockWebBrowserEventSink : public WebBrowserEventSink { +class MockWebBrowserEventSink : public chrome_frame_test::WebBrowserEventSink { public: // Needed to support PostTask. static bool ImplementsThreadSafeReferenceCounting() { @@ -1412,7 +1187,7 @@ using testing::_; const wchar_t kChromeFrameFileUrl[] = L"cf:file:///C:/"; TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) { - TimedMsgLoop loop; + chrome_frame_test::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. @@ -1457,7 +1232,7 @@ const wchar_t kChromeFrameFullTabWindowOpenPopupUrl[] = // 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, DISABLED_FullTabModeIE_WindowOpen) { - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; CComObjectStackEx<MockWebBrowserEventSink> mock; ::testing::InSequence sequence; @@ -1517,7 +1292,7 @@ const wchar_t kChromeFrameAboutVersion[] = // Marking this test FLAKY as it fails at times on the buildbot. // http://code.google.com/p/chromium/issues/detail?id=26549 TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) { - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; CComObjectStackEx<MockWebBrowserEventSink> mock; EXPECT_CALL(mock, @@ -1554,7 +1329,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) { const wchar_t kChromeFrameFullTabModeKeyEventUrl[] = L"files/keyevent.html"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameKeyboardTest) { - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; ASSERT_TRUE(LaunchBrowser(IE, kChromeFrameFullTabModeKeyEventUrl)); @@ -1590,7 +1365,7 @@ template <typename T> T** ReceivePointer(scoped_refptr<T>& p) { // NOLINT // Full tab mode back/forward test // Launch and navigate chrome frame to a set of URLs and test back forward TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; CComObjectStackEx<MockWebBrowserEventSink> mock; ::testing::InSequence sequence; // Everything in sequence @@ -1604,8 +1379,9 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { .WillOnce(testing::Return()); EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( - CreateFunctor(&mock, &WebBrowserEventSink::Navigate, - std::wstring(kSubFrameUrl2))))); + CreateFunctor( + &mock, &chrome_frame_test::WebBrowserEventSink::Navigate, + std::wstring(kSubFrameUrl2))))); // Navigate to url 3 after the previous navigation is complete EXPECT_CALL(mock, @@ -1617,8 +1393,9 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { .WillOnce(testing::Return()); EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( - CreateFunctor(&mock, &WebBrowserEventSink::Navigate, - std::wstring(kSubFrameUrl3))))); + CreateFunctor( + &mock, &chrome_frame_test::WebBrowserEventSink::Navigate, + std::wstring(kSubFrameUrl3))))); // We have reached url 3 and have two back entries for url 1 & 2 // Go back to url 2 now @@ -1659,7 +1436,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, - &WebBrowserEventSink::Uninitialize)), + &chrome_frame_test::WebBrowserEventSink::Uninitialize)), testing::IgnoreResult(testing::InvokeWithoutArgs( &chrome_frame_test::CloseAllIEWindows)), QUIT_LOOP_SOON(loop, 2))); @@ -1671,13 +1448,15 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { ASSERT_TRUE(mock.web_browser2() != NULL); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); + mock.Uninitialize(); + chrome_frame_test::CloseAllIEWindows(); } const wchar_t kChromeFrameAboutBlankUrl[] = L"cf:about:blank"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameFocusTest) { - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; ASSERT_TRUE(LaunchBrowser(IE, kChromeFrameAboutBlankUrl)); @@ -1710,7 +1489,7 @@ const wchar_t kAnchor3Url[] = L"http://localhost:1337/files/anchor.html#a3"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { const char tab_enter_keystrokes[] = { VK_TAB, VK_RETURN, 0 }; static const std::string tab_enter(tab_enter_keystrokes); - TimedMsgLoop loop; + chrome_frame_test::TimedMsgLoop loop; CComObjectStackEx<MockWebBrowserEventSink> mock; ::testing::InSequence sequence; // Everything in sequence @@ -1736,10 +1515,12 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchorUrl))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, - &WebBrowserEventSink::SetFocusToChrome)), + &chrome_frame_test::WebBrowserEventSink::SetFocusToChrome)), testing::InvokeWithoutArgs(CreateFunctor(&loop, - &TimedMsgLoop::PostDelayedTask, FROM_HERE, NewRunnableMethod( - &mock, &WebBrowserEventSink::SendInputToChrome, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod( + &mock, + &chrome_frame_test::WebBrowserEventSink::SendInputToChrome, std::string(tab_enter)), 0)))); EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kAnchor1Url)), @@ -1754,8 +1535,12 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { // Forward: 0 EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor1Url))) .WillOnce(testing::InvokeWithoutArgs( - CreateFunctor(&loop, &TimedMsgLoop::PostDelayedTask, FROM_HERE, - NewRunnableMethod(&mock, &WebBrowserEventSink::SendInputToChrome, + CreateFunctor( + &loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, + FROM_HERE, + NewRunnableMethod( + &mock, + &chrome_frame_test::WebBrowserEventSink::SendInputToChrome, std::string(tab_enter)), 0))); EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kAnchor2Url)), @@ -1770,8 +1555,12 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { // Forward: 0 EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) .WillOnce(testing::InvokeWithoutArgs( - CreateFunctor(&loop, &TimedMsgLoop::PostDelayedTask, FROM_HERE, - NewRunnableMethod(&mock, &WebBrowserEventSink::SendInputToChrome, + CreateFunctor( + &loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, + FROM_HERE, + NewRunnableMethod( + &mock, + &chrome_frame_test::WebBrowserEventSink::SendInputToChrome, std::string(tab_enter)), 0))); EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(kAnchor3Url)), @@ -1847,7 +1636,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor3Url))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, - &WebBrowserEventSink::Uninitialize)), + &chrome_frame_test::WebBrowserEventSink::Uninitialize)), testing::IgnoreResult(testing::InvokeWithoutArgs( &chrome_frame_test::CloseAllIEWindows)), QUIT_LOOP_SOON(loop, 2))); @@ -1859,4 +1648,6 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { ASSERT_TRUE(mock.web_browser2() != NULL); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); + mock.Uninitialize(); + chrome_frame_test::CloseAllIEWindows(); } diff --git a/chrome_frame/test/chrome_frame_unittests.h b/chrome_frame/test/chrome_frame_unittests.h index b009faf..f5bd3cb 100644 --- a/chrome_frame/test/chrome_frame_unittests.h +++ b/chrome_frame/test/chrome_frame_unittests.h @@ -104,132 +104,5 @@ class ChromeFrameTestWithWebServer: public testing::Test { ChromeFrameHTTPServer server_; }; -// This class sets up event sinks to the IWebBrowser interface. Currently it -// subscribes to the following events:- -// 1. DISPID_BEFORENAVIGATE2 -// 2. DISPID_NAVIGATEERROR -// 3. DISPID_NAVIGATECOMPLETE2 -// 4. DISPID_NEWWINDOW3 -// Other events can be subscribed to on an if needed basis. -class WebBrowserEventSink - : public CComObjectRootEx<CComSingleThreadModel>, - public IDispEventSimpleImpl<0, WebBrowserEventSink, - &DIID_DWebBrowserEvents2> { - public: - typedef IDispEventSimpleImpl<0, WebBrowserEventSink, - &DIID_DWebBrowserEvents2> DispEventsImpl; - WebBrowserEventSink() - : ALLOW_THIS_IN_INITIALIZER_LIST( - onmessage_(this, &WebBrowserEventSink::OnMessageInternal)), - ALLOW_THIS_IN_INITIALIZER_LIST( - onloaderror_(this, &WebBrowserEventSink::OnLoadErrorInternal)), - ALLOW_THIS_IN_INITIALIZER_LIST( - onload_(this, &WebBrowserEventSink::OnLoadInternal)) { - } - - ~WebBrowserEventSink() { - Uninitialize(); - } - - void Uninitialize(); - - // Helper function to launch IE and navigate to a URL. - // Returns S_OK on success, S_FALSE if the test was not run, other - // errors on failure. - HRESULT LaunchIEAndNavigate(const std::wstring& navigate_url); - - HRESULT Navigate(const std::wstring& navigate_url); - - // Set input focus to chrome frame window. - void SetFocusToChrome(); - - // Send keyboard input to the renderer window hosted in chrome using - // SendInput API - void SendInputToChrome(const std::string& input_string); - -BEGIN_COM_MAP(WebBrowserEventSink) -END_COM_MAP() - -BEGIN_SINK_MAP(WebBrowserEventSink) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, - OnBeforeNavigate2Internal, &kBeforeNavigate2Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, - OnDownloadBegin, &kVoidMethodInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, - OnNavigateComplete2Internal, &kNavigateComplete2Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, - OnNavigateError, &kNavigateErrorInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, - OnNewWindow3, &kNewWindow3Info) -END_SINK_MAP() - - STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url, - VARIANT* frame_name, VARIANT* status_code, - VARIANT* cancel) { - DLOG(INFO) << __FUNCTION__; - } - - STDMETHOD(OnBeforeNavigate2)(IDispatch* dispatch, VARIANT* url, VARIANT* - flags, VARIANT* target_frame_name, - VARIANT* post_data, VARIANT* headers, - VARIANT_BOOL* cancel) { - return S_OK; - } - - STDMETHOD(OnBeforeNavigate2Internal)(IDispatch* dispatch, VARIANT* url, - VARIANT* flags, - VARIANT* target_frame_name, - VARIANT* post_data, VARIANT* headers, - VARIANT_BOOL* cancel); - STDMETHOD_(void, OnDownloadBegin)() {} - STDMETHOD_(void, OnNavigateComplete2Internal)(IDispatch* dispatch, - VARIANT* url); - STDMETHOD_(void, OnNavigateComplete2)(IDispatch* dispatch, VARIANT* url) {} - STDMETHOD_(void, OnNewWindow3)(IDispatch** dispatch, VARIANT_BOOL* Cancel, - DWORD flags, BSTR url_context, BSTR url) {} - -#ifdef _DEBUG - STDMETHOD(Invoke)(DISPID dispid, REFIID riid, - LCID lcid, WORD flags, DISPPARAMS* params, VARIANT* result, - EXCEPINFO* except_info, UINT* arg_error) { - DLOG(INFO) << __FUNCTION__ << L" disp id :" << dispid; - return DispEventsImpl::Invoke(dispid, riid, lcid, flags, params, result, - except_info, arg_error); - } -#endif // _DEBUG - - // Chrome frame callbacks - virtual void OnLoad(const wchar_t* url) {} - virtual void OnLoadError(const wchar_t* url) {} - virtual void OnMessage(const wchar_t* message) {} - - IWebBrowser2* web_browser2() { - return web_browser2_.get(); - } - - protected: - // IChromeFrame callbacks - HRESULT OnLoadInternal(const VARIANT* param); - HRESULT OnLoadErrorInternal(const VARIANT* param); - HRESULT OnMessageInternal(const VARIANT* param); - - void ConnectToChromeFrame(); - HWND GetChromeRendererWindow(); - - public: - ScopedComPtr<IWebBrowser2> web_browser2_; - ScopedComPtr<IChromeFrame> chrome_frame_; - DispCallback<WebBrowserEventSink> onmessage_; - DispCallback<WebBrowserEventSink> onloaderror_; - DispCallback<WebBrowserEventSink> onload_; - - protected: - static _ATL_FUNC_INFO kBeforeNavigate2Info; - static _ATL_FUNC_INFO kNavigateComplete2Info; - static _ATL_FUNC_INFO kNavigateErrorInfo; - static _ATL_FUNC_INFO kNewWindow3Info; - static _ATL_FUNC_INFO kVoidMethodInfo; -}; - #endif // CHROME_FRAME_TEST_CHROME_FRAME_UNITTESTS_H_ diff --git a/chrome_frame/test/reliability/page_load_test.cc b/chrome_frame/test/reliability/page_load_test.cc new file mode 100644 index 0000000..dd869e5 --- /dev/null +++ b/chrome_frame/test/reliability/page_load_test.cc @@ -0,0 +1,624 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file provides reliablity tests which run for ChromeFrame. +// +// Usage: +// <reliability test exe> --list=file --startline=start --endline=end [...] +// Upon invocation, it visits each of the URLs on line numbers between start +// and end, inclusive, stored in the input file. The line number starts from 1. +// +// Optional Switches: +// --iterations=num: goes through the list of URLs constructed in usage 2 or 3 +// num times. +// --continuousload: continuously visits the list of URLs without restarting +// browser for each page load. +// --memoryusage: prints out memory usage when visiting each page. +// --logfile=filepath: saves the visit log to the specified path. +// --timeout=millisecond: time out as specified in millisecond during each +// page load. +// --nopagedown: won't simulate page down key presses after page load. +// --noclearprofile: do not clear profile dir before firing up each time. +// --savedebuglog: save Chrome, V8, and test debug log for each page loaded. +#include <fstream> +#include <iostream> + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/file_version_info.h" +#include "base/keyboard_codes.h" +#include "base/i18n/time_formatting.h" +#include "base/path_service.h" +#include "base/registry.h" +#include "base/string_util.h" +#include "base/test/test_file_util.h" +#include "base/time.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_paths_internal.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/logging_chrome.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome_frame/test/chrome_frame_test_utils.h" +#include "chrome/test/automation/automation_messages.h" +#include "chrome/test/automation/automation_proxy.h" +#include "chrome/test/automation/browser_proxy.h" +#include "chrome/test/automation/tab_proxy.h" +#include "chrome/test/automation/window_proxy.h" +#include "chrome/test/ui/ui_test.h" +#include "chrome/test/reliability/page_load_test.h" +#include "chrome_frame/utils.h" +#include "net/base/net_util.h" + + +namespace { + +// See comments at the beginning of the file for the definition of switches. +const char kListSwitch[] = "list"; +const char kStartIndexSwitch[] = "startline"; +const char kEndIndexSwitch[] = "endline"; +const char kIterationSwitch[] = "iterations"; +const char kContinuousLoadSwitch[] = "continuousload"; +const char kMemoryUsageSwitch[] = "memoryusage"; +const char kLogFileSwitch[] = "logfile"; +const char kTimeoutSwitch[] = "timeout"; +const char kNoPageDownSwitch[] = "nopagedown"; +const char kNoClearProfileSwitch[] = "noclearprofile"; +const char kSaveDebugLogSwitch[] = "savedebuglog"; + +// These are copied from v8 definitions as we cannot include them. +const char kV8LogFileSwitch[] = "logfile"; +const char kV8LogFileDefaultName[] = "v8.log"; + +// String name of local chrome dll for looking up file information. +const wchar_t kChromeDll[] = L"chrome.dll"; + +FilePath g_url_file_path; +int32 g_start_index = 1; +int32 g_end_index = kint32max; +int32 g_iterations = 1; +bool g_memory_usage = false; +bool g_continuous_load = false; +bool g_browser_existing = false; +bool g_page_down = true; +bool g_clear_profile = true; +std::string g_end_url; +FilePath g_log_file_path; +bool g_save_debug_log = false; +FilePath g_chrome_log_path; +FilePath g_v8_log_path; +FilePath g_test_log_path; +bool g_stand_alone = false; + +const int kUrlNavigationTimeoutSeconds = 20; +int g_timeout_ms = kUrlNavigationTimeoutSeconds; + +// Overrides a number of IWebBrowser2 event sink handlers as provided by the +// base chrome_frame_test::WebBrowserEventSink class and provides functionality +// for reliability testing. +class WebBrowserEventSinkImpl : public chrome_frame_test::WebBrowserEventSink { + public: + typedef chrome_frame_test::WebBrowserEventSink Base; + + WebBrowserEventSinkImpl() + : navigation_started_(false), + navigation_completed_(false), + message_loop_(NULL), + is_chrome_frame_navigation_(false) {} + + ~WebBrowserEventSinkImpl() {} + + STDMETHOD_(void, OnDocumentComplete)(IDispatch* dispatch, VARIANT* url) { + if (url->bstrVal && !_wcsicmp(url->bstrVal, url_.c_str())) { + navigation_started_ = false; + // If this is a chrome frame navigation then the OnDocumentComplete event + // does not indicate that we actually finished navigation. For that we + // have to wait for the OnLoad notification from ChromeFrame to arrive. + if (!is_chrome_frame_navigation_) { + navigation_completed_ = true; + DCHECK(message_loop_); + message_loop_->Quit(); + } + } + } + + virtual void OnLoad(const wchar_t* url) { + navigation_completed_ = true; + DCHECK(message_loop_); + message_loop_->Quit(); + } + + virtual HRESULT Navigate(const std::wstring& navigate_url) { + if (StartsWith(navigate_url, L"cf:", true)) { + is_chrome_frame_navigation_ = true; + url_ = navigate_url.substr(wcslen(L"cf:")); + } else { + url_ = navigate_url; + } + navigation_started_ = true; + navigation_completed_ = false; + + return Base::Navigate(navigate_url); + } + + bool navigation_started() const { + return navigation_started_; + } + + bool navigation_completed() const { + return navigation_completed_; + } + + const std::wstring& url() const { + return url_; + } + + bool is_chrome_frame_navigation() const { + return is_chrome_frame_navigation_; + } + + void set_message_loop(chrome_frame_test::TimedMsgLoop* message_loop) { + message_loop_ = message_loop; + } + + private: + bool navigation_started_; + bool navigation_completed_; + std::wstring url_; + chrome_frame_test::TimedMsgLoop* message_loop_; + bool is_chrome_frame_navigation_; +}; + +class PageLoadTest : public testing::Test { + public: + enum NavigationResult { + NAVIGATION_ERROR = 0, + NAVIGATION_SUCCESS, + }; + + typedef struct { + // These are results from the test automation that drives Chrome + NavigationResult result; + int crash_dump_count; + // These are stability metrics recorded by Chrome itself + bool browser_clean_exit; + int browser_launch_count; + int page_load_count; + int browser_crash_count; + int renderer_crash_count; + int plugin_crash_count; + } NavigationMetrics; + + PageLoadTest() {} + + // Accept URL as std::string here because the url may also act as a test id + // and needs to be logged in its original format even if invalid. + void NavigateToURLLogResult(const std::string& url_string, + std::ofstream& log_file, + NavigationMetrics* metrics_output) { + GURL url(url_string); + NavigationMetrics metrics = {NAVIGATION_ERROR}; + std::ofstream test_log; + + // Create a test log. + g_test_log_path = FilePath(FILE_PATH_LITERAL("test_log.log")); + test_log.open(g_test_log_path.value().c_str()); + + // Check file version info for chrome dll. + scoped_ptr<FileVersionInfo> file_info; +#if defined(OS_WIN) + file_info.reset(FileVersionInfo::CreateFileVersionInfo(kChromeDll)); +#elif defined(OS_LINUX) || defined(OS_MACOSX) + // TODO(fmeawad): the version retrieved here belongs to the test module and + // not the chrome binary, need to be changed to chrome binary instead. + file_info.reset(FileVersionInfo::CreateFileVersionInfoForCurrentModule()); +#endif // !defined(OS_WIN) + std::wstring last_change = file_info->last_change(); + test_log << "Last Change: "; + test_log << last_change << std::endl; + + + // Log timestamp for test start. + base::Time time_now = base::Time::Now(); + double time_start = time_now.ToDoubleT(); + test_log << "Test Start: "; + test_log << base::TimeFormatFriendlyDateAndTime(time_now) << std::endl; + + HRESULT hr = E_FAIL; + + chrome_frame_test::TimedMsgLoop message_loop; + + CComObjectStack<WebBrowserEventSinkImpl> browser_event_sink; + browser_event_sink.set_message_loop(&message_loop); + + if (!g_continuous_load && !g_browser_existing) { + ScopedComPtr<IWebBrowser2> web_browser2; + hr = chrome_frame_test::LaunchIEAsComServer(web_browser2.Receive()); + EXPECT_HRESULT_SUCCEEDED(hr); + EXPECT_TRUE(web_browser2.get() != NULL); + + EXPECT_HRESULT_SUCCEEDED(browser_event_sink.SetWebBrowser(web_browser2)); + g_browser_existing = true; + } + + // Log Browser Launched time. + time_now = base::Time::Now(); + test_log << "browser_launched_seconds="; + test_log << (time_now.ToDoubleT() - time_start) << std::endl; + + // This is essentially what NavigateToURL does except we don't fire + // assertion when page loading fails. We log the result instead. + hr = browser_event_sink.Navigate(UTF8ToWide(url.spec())); + if (SUCCEEDED(hr)) { + message_loop.RunFor(g_timeout_ms); + if (browser_event_sink.navigation_completed()) + metrics.result = NAVIGATION_SUCCESS; + } + + // Log navigate complete time. + time_now = base::Time::Now(); + test_log << "navigate_complete_seconds="; + test_log << (time_now.ToDoubleT() - time_start) << std::endl; + + if (!g_continuous_load) { + browser_event_sink.Uninitialize(); + chrome_frame_test::CloseAllIEWindows(); + g_browser_existing = false; + } + + // Log end of test time. + time_now = base::Time::Now(); + test_log << "total_duration_seconds="; + test_log << (time_now.ToDoubleT() - time_start) << std::endl; + + // Get navigation result and metrics, and optionally write to the log file + // provided. The log format is: + // <url> <navigation_result> <browser_crash_count> <renderer_crash_count> + // <plugin_crash_count> <crash_dump_count> [chrome_log=<path> + // v8_log=<path>] crash_dump=<path> + if (log_file.is_open()) { + log_file << url_string; + switch (metrics.result) { + case NAVIGATION_ERROR: + log_file << " error"; + break; + case NAVIGATION_SUCCESS: + log_file << " success"; + break; + default: + break; + } + } + + // Get stability metrics recorded by Chrome itself. + if (browser_event_sink.is_chrome_frame_navigation()) { + GetStabilityMetrics(&metrics); + } + + if (log_file.is_open()) { + log_file << " " << metrics.browser_crash_count \ + // The renderer crash count is flaky due to 1183283. + // Ignore the count since we also catch crash by + // crash_dump_count. + << " " << 0 \ + << " " << metrics.plugin_crash_count \ + << " " << metrics.crash_dump_count; + } + + // Close test log. + test_log.close(); + + if (log_file.is_open() && g_save_debug_log && !g_continuous_load) + SaveDebugLogs(log_file); + + // Log revision information for Chrome build under test. + log_file << " " << "revision=" << last_change; + + // Get crash dumps. + LogOrDeleteNewCrashDumps(log_file, &metrics); + + if (log_file.is_open()) { + log_file << std::endl; + } + + if (metrics_output) { + *metrics_output = metrics; + } + } + + void NavigateThroughURLList(std::ofstream& log_file) { + std::ifstream file(g_url_file_path.value().c_str()); + ASSERT_TRUE(file.is_open()); + + // We navigate to URLs in the following order. + // CF -> CF -> host -> CF -> CF -> host. + for (int line_index = 1; + line_index <= g_end_index && !file.eof(); + ++line_index) { + std::string url_str; + std::getline(file, url_str); + + if (file.fail()) { + break; + } + + // Every 3rd URL goes into the host browser. + if (line_index % 3 != 0) { + std::string actual_url; + actual_url = "cf:"; + actual_url += url_str; + url_str = actual_url; + } + + if (g_start_index <= line_index) { + NavigateToURLLogResult(url_str, log_file, NULL); + } + } + + file.close(); + } + + protected: + virtual void SetUp() { + // Initialize crash_dumps_dir_path_. + PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dumps_dir_path_); + file_util::FileEnumerator enumerator(crash_dumps_dir_path_, + false, // not recursive + file_util::FileEnumerator::FILES); + for (FilePath path = enumerator.Next(); !path.value().empty(); + path = enumerator.Next()) { + if (path.MatchesExtension(FILE_PATH_LITERAL(".dmp"))) + crash_dumps_[path.BaseName()] = true; + } + + if (g_clear_profile) { + FilePath user_data_dir; + chrome::GetChromeFrameUserDataDirectory(&user_data_dir); + ASSERT_TRUE(file_util::DieFileDie(user_data_dir, true)); + } + + SetConfigBool(kChromeFrameHeadlessMode, true); + } + + virtual void TearDown() { + DeleteConfigValue(kChromeFrameHeadlessMode); + } + + FilePath ConstructSavedDebugLogPath(const FilePath& debug_log_path, + int index) { + std::string suffix("_"); + suffix.append(IntToString(index)); + return debug_log_path.InsertBeforeExtensionASCII(suffix); + } + + void SaveDebugLog(const FilePath& log_path, const std::wstring& log_id, + std::ofstream& log_file, int index) { + if (!log_path.empty()) { + FilePath saved_log_file_path = + ConstructSavedDebugLogPath(log_path, index); + if (file_util::Move(log_path, saved_log_file_path)) { + log_file << " " << log_id << "=" << saved_log_file_path.value(); + } + } + } + + // Rename the chrome and v8 debug log files if existing, and save the file + // paths in the log_file provided. + void SaveDebugLogs(std::ofstream& log_file) { + static int url_count = 1; + SaveDebugLog(g_chrome_log_path, L"chrome_log", log_file, url_count); + SaveDebugLog(g_v8_log_path, L"v8_log", log_file, url_count); + SaveDebugLog(g_test_log_path, L"test_log", log_file, url_count); + url_count++; + } + + // If a log_file is provided, log the crash dump with the given path; + // otherwise, delete the crash dump file. + void LogOrDeleteCrashDump(std::ofstream& log_file, + FilePath crash_dump_file_name) { + FilePath crash_dump_file_path(crash_dumps_dir_path_); + crash_dump_file_path = crash_dump_file_path.Append(crash_dump_file_name); + FilePath crash_text_file_path = + crash_dump_file_path.ReplaceExtension(FILE_PATH_LITERAL("txt")); + + if (log_file.is_open()) { + crash_dumps_[crash_dump_file_name] = true; + log_file << " crash_dump=" << crash_dump_file_path.value().c_str(); + } else { + ASSERT_TRUE(file_util::DieFileDie( + crash_dump_file_path, false)); + ASSERT_TRUE(file_util::DieFileDie( + crash_text_file_path, false)); + } + } + + // Check whether there are new .dmp files. Additionally, write + // " crash_dump=<full path name of the .dmp file>" + // to log_file. + void LogOrDeleteNewCrashDumps(std::ofstream& log_file, + NavigationMetrics* metrics) { + int num_dumps = 0; + + file_util::FileEnumerator enumerator(crash_dumps_dir_path_, + false, // not recursive + file_util::FileEnumerator::FILES); + for (FilePath path = enumerator.Next(); !path.value().empty(); + path = enumerator.Next()) { + if (path.MatchesExtension(FILE_PATH_LITERAL(".dmp")) && + !crash_dumps_[path.BaseName()]) { + LogOrDeleteCrashDump(log_file, path.BaseName()); + num_dumps++; + } + } + if (metrics) + metrics->crash_dump_count = num_dumps; + } + + // Get a PrefService whose contents correspond to the Local State file + // that was saved by the app as it closed. The caller takes ownership of the + // returned PrefService object. + PrefService* GetLocalState() { + FilePath local_state_path; + chrome::GetChromeFrameUserDataDirectory(&local_state_path); + + PrefService* local_state = new PrefService(local_state_path); + return local_state; + } + + void GetStabilityMetrics(NavigationMetrics* metrics) { + if (!metrics) + return; + scoped_ptr<PrefService> local_state(GetLocalState()); + if (!local_state.get()) + return; + local_state->RegisterBooleanPref(prefs::kStabilityExitedCleanly, false); + local_state->RegisterIntegerPref(prefs::kStabilityLaunchCount, -1); + local_state->RegisterIntegerPref(prefs::kStabilityPageLoadCount, -1); + local_state->RegisterIntegerPref(prefs::kStabilityCrashCount, 0); + local_state->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0); + + metrics->browser_clean_exit = + local_state->GetBoolean(prefs::kStabilityExitedCleanly); + metrics->browser_launch_count = + local_state->GetInteger(prefs::kStabilityLaunchCount); + metrics->page_load_count = + local_state->GetInteger(prefs::kStabilityPageLoadCount); + metrics->browser_crash_count = + local_state->GetInteger(prefs::kStabilityCrashCount); + metrics->renderer_crash_count = + local_state->GetInteger(prefs::kStabilityRendererCrashCount); + // TODO(huanr) + metrics->plugin_crash_count = 0; + + if (!metrics->browser_clean_exit) + metrics->browser_crash_count++; + } + + FilePath GetSampleDataDir() { + FilePath test_dir; + PathService::Get(chrome::DIR_TEST_DATA, &test_dir); + test_dir = test_dir.AppendASCII("reliability"); + test_dir = test_dir.AppendASCII("sample_pages"); + return test_dir; + } + + // The pathname of Chrome's crash dumps directory. + FilePath crash_dumps_dir_path_; + + // The set of all the crash dumps we have seen. Each crash generates a + // .dmp and a .txt file in the crash dumps directory. We only store the + // .dmp files in this set. + // + // The set is implemented as a std::map. The key is the file name, and + // the value is false (the file is not in the set) or true (the file is + // in the set). The initial value for any key in std::map is 0 (false), + // which in this case means a new file is not in the set initially, + // exactly the semantics we want. + std::map<FilePath, bool> crash_dumps_; +}; + +TEST_F(PageLoadTest, IEFullTabMode_Reliability) { + std::ofstream log_file; + + if (!g_log_file_path.empty()) { + log_file.open(g_log_file_path.value().c_str()); + } + + EXPECT_FALSE(g_url_file_path.empty()); + + for (int k = 0; k < g_iterations; ++k) { + NavigateThroughURLList(log_file); + } + + log_file.close(); +} + +} // namespace + +namespace { + void ReportHandler(const std::string& str) { + // Ignore report events. + } +} + +void SetPageRange(const CommandLine& parsed_command_line) { + // If calling into this function, we are running as a standalone program. + g_stand_alone = true; + + // Since we use --enable-dcheck for reliability tests, suppress the error + // dialog in the test process. + logging::SetLogReportHandler(ReportHandler); + + if (parsed_command_line.HasSwitch(kStartIndexSwitch)) { + ASSERT_TRUE( + StringToInt(WideToUTF16(parsed_command_line.GetSwitchValue( + kStartIndexSwitch)), &g_start_index)); + ASSERT_GT(g_start_index, 0); + } + + if (parsed_command_line.HasSwitch(kEndIndexSwitch)) { + ASSERT_TRUE( + StringToInt(WideToUTF16(parsed_command_line.GetSwitchValue( + kEndIndexSwitch)), &g_end_index)); + ASSERT_GT(g_end_index, 0); + } + + ASSERT_TRUE(g_end_index >= g_start_index); + + if (parsed_command_line.HasSwitch(kListSwitch)) + g_url_file_path = parsed_command_line.GetSwitchValuePath(kListSwitch); + + if (parsed_command_line.HasSwitch(kIterationSwitch)) { + ASSERT_TRUE( + StringToInt(WideToUTF16(parsed_command_line.GetSwitchValue( + kIterationSwitch)), &g_iterations)); + ASSERT_GT(g_iterations, 0); + } + + if (parsed_command_line.HasSwitch(kMemoryUsageSwitch)) + g_memory_usage = true; + + if (parsed_command_line.HasSwitch(kContinuousLoadSwitch)) + g_continuous_load = true; + + if (parsed_command_line.HasSwitch(kLogFileSwitch)) + g_log_file_path = parsed_command_line.GetSwitchValuePath(kLogFileSwitch); + + if (parsed_command_line.HasSwitch(kTimeoutSwitch)) { + ASSERT_TRUE( + StringToInt(WideToUTF16(parsed_command_line.GetSwitchValue( + kTimeoutSwitch)), &g_timeout_ms)); + ASSERT_GT(g_timeout_ms, 0); + } + + if (parsed_command_line.HasSwitch(kNoPageDownSwitch)) + g_page_down = false; + + if (parsed_command_line.HasSwitch(kNoClearProfileSwitch)) + g_clear_profile = false; + + if (parsed_command_line.HasSwitch(kSaveDebugLogSwitch)) { + g_save_debug_log = true; + g_chrome_log_path = logging::GetLogFileName(); + // We won't get v8 log unless --no-sandbox is specified. + if (parsed_command_line.HasSwitch(switches::kNoSandbox)) { + PathService::Get(base::DIR_CURRENT, &g_v8_log_path); + g_v8_log_path = g_v8_log_path.AppendASCII(kV8LogFileDefaultName); + // The command line switch may override the default v8 log path. + if (parsed_command_line.HasSwitch(switches::kJavaScriptFlags)) { + CommandLine v8_command_line( + parsed_command_line.GetSwitchValuePath(switches::kJavaScriptFlags)); + if (v8_command_line.HasSwitch(kV8LogFileSwitch)) { + g_v8_log_path = v8_command_line.GetSwitchValuePath(kV8LogFileSwitch); + if (!file_util::AbsolutePath(&g_v8_log_path)) + g_v8_log_path = FilePath(); + } + } + } + } +} + diff --git a/chrome_frame/test/reliability/page_load_test.h b/chrome_frame/test/reliability/page_load_test.h new file mode 100644 index 0000000..f5aac19 --- /dev/null +++ b/chrome_frame/test/reliability/page_load_test.h @@ -0,0 +1,17 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file declares helper functions necessary to run reliablity test under +// UI test framework. + +#ifndef CHROME_FRAME_TEST_RELIABILITY_PAGE_LOAD_TEST_H_ +#define CHROME_FRAME_TEST_RELIABILITY_PAGE_LOAD_TEST_H_ + +#include "base/command_line.h" + +// Parse the command line options and set the page range accordingly. +void SetPageRange(const CommandLine&); + +#endif // CHROME_FRAME_TEST_RELIABILITY_PAGE_LOAD_TEST_H_ + diff --git a/chrome_frame/test/reliability/reliability_test_suite.h b/chrome_frame/test/reliability/reliability_test_suite.h new file mode 100644 index 0000000..4e41ede --- /dev/null +++ b/chrome_frame/test/reliability/reliability_test_suite.h @@ -0,0 +1,30 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_TEST_RELIABILITY_RELIABILITY_TEST_SUITE_H_ +#define CHROME_FRAME_TEST_RELIABILITY_RELIABILITY_TEST_SUITE_H_ + +#include "chrome_frame/test/reliability/page_load_test.h" +#include "chrome/test/ui/ui_test_suite.h" + +class ReliabilityTestSuite : public UITestSuite { + public: + ReliabilityTestSuite(int argc, char** argv) : UITestSuite(argc, argv) { + } + + protected: + virtual void Initialize() { + CoInitializeEx(NULL, COINIT_MULTITHREADED); + SetPageRange(*CommandLine::ForCurrentProcess()); + UITestSuite::Initialize(); + } + + virtual void Shutdown() { + CoUninitialize(); + UITestSuite::Shutdown(); + } +}; + +#endif // CHROME_FRAME_TEST_RELIABILITY_RELIABILITY_TEST_SUITE_H_ + diff --git a/chrome_frame/test/reliability/run_all_unittests.cc b/chrome_frame/test/reliability/run_all_unittests.cc new file mode 100644 index 0000000..734a801 --- /dev/null +++ b/chrome_frame/test/reliability/run_all_unittests.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome_frame/test/reliability/reliability_test_suite.h" + +int main(int argc, char **argv) { + return ReliabilityTestSuite(argc, argv).Run(); +} + |