summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/chrome_frame.gyp55
-rw-r--r--chrome_frame/chrome_frame_reporting.cc13
-rw-r--r--chrome_frame/crash_reporting/crash_report.cc16
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.cc239
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.h188
-rw-r--r--chrome_frame/test/chrome_frame_unittests.cc305
-rw-r--r--chrome_frame/test/chrome_frame_unittests.h127
-rw-r--r--chrome_frame/test/reliability/page_load_test.cc624
-rw-r--r--chrome_frame/test/reliability/page_load_test.h17
-rw-r--r--chrome_frame/test/reliability/reliability_test_suite.h30
-rw-r--r--chrome_frame/test/reliability/run_all_unittests.cc10
-rw-r--r--chrome_frame/utils.cc35
-rw-r--r--chrome_frame/utils.h15
13 files changed, 1283 insertions, 391 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index 870f9da..905e34f 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -446,6 +446,8 @@
'test/net/test_automation_provider.h',
'test/net/test_automation_resource_message_filter.cc',
'test/net/test_automation_resource_message_filter.h',
+ 'chrome_tab.h',
+ 'chrome_tab.idl',
],
'include_dirs': [
# To allow including "chrome_tab.h"
@@ -465,6 +467,59 @@
},
{
+ 'target_name': 'chrome_frame_reliability_tests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../build/temp_gyp/googleurl.gyp:googleurl',
+ '../chrome/chrome.gyp:browser',
+ '../chrome/chrome.gyp:utility',
+ '../testing/gtest.gyp:gtest',
+ '../base/allocator/allocator.gyp:allocator',
+ 'chrome_frame_npapi',
+ 'chrome_frame_strings',
+ ],
+ 'sources': [
+ 'test/reliability/run_all_unittests.cc',
+ 'test/reliability/page_load_test.cc',
+ 'test/reliability/page_load_test.h',
+ 'test/reliability/reliability_test_suite.h',
+ 'test/chrome_frame_test_utils.cc',
+ 'test/chrome_frame_test_utils.h',
+ 'chrome_tab.h',
+ 'chrome_tab.idl',
+ '../base/test/test_file_util_win.cc',
+ '../chrome/test/ui/ui_test.cc',
+ '../chrome/test/ui/ui_test_suite.cc',
+ '../chrome/test/ui/ui_test_suite.h',
+ '../chrome/test/chrome_process_util_win.cc',
+ '../chrome/test/chrome_process_util.cc',
+ '../chrome/test/chrome_process_util.h',
+ '../chrome/test/chrome_process_util_win.cc',
+ ],
+ 'include_dirs': [
+ # To allow including "chrome_tab.h"
+ '<(INTERMEDIATE_DIR)',
+ ],
+ 'resource_include_dirs': [
+ '<(INTERMEDIATE_DIR)',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'sources': [
+ '<(SHARED_INTERMEDIATE_DIR)/chrome_frame/chrome_frame_resources.rc',
+ '<(SHARED_INTERMEDIATE_DIR)/chrome_frame/chrome_frame_strings.rc',
+ ],
+ 'dependencies': [
+ # TODO(slightlyoff): Get automation targets working on OS X
+ '../chrome/chrome.gyp:automation',
+ '../chrome/installer/installer.gyp:installer_util',
+ '../google_update/google_update.gyp:google_update',
+ ]
+ }],
+ ],
+ },
+
+ {
'target_name': 'chrome_frame_npapi',
'type': 'static_library',
'dependencies': [
diff --git a/chrome_frame/chrome_frame_reporting.cc b/chrome_frame/chrome_frame_reporting.cc
index 170a710..688651e 100644
--- a/chrome_frame/chrome_frame_reporting.cc
+++ b/chrome_frame/chrome_frame_reporting.cc
@@ -11,6 +11,7 @@
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/install_util.h"
#include "chrome_frame/chrome_frame_reporting.h"
+#include "chrome_frame/utils.h"
// Well known SID for the system principal.
const wchar_t kSystemPrincipalSid[] = L"S-1-5-18";
@@ -46,11 +47,13 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* dll_path) {
extern "C" IMAGE_DOS_HEADER __ImageBase;
bool InitializeCrashReporting() {
- // We want to use the Google Update crash reporting. We need to check if the
- // user allows it first.
- if (!GoogleUpdateSettings::GetCollectStatsConsent())
- return true;
-
+ // In headless mode we want crashes to be reported back.
+ if (!IsHeadlessMode()) {
+ // We want to use the Google Update crash reporting. We need to check if the
+ // user allows it first.
+ if (!GoogleUpdateSettings::GetCollectStatsConsent())
+ return true;
+ }
// Build the pipe name. It can be either:
// System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
// Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
diff --git a/chrome_frame/crash_reporting/crash_report.cc b/chrome_frame/crash_reporting/crash_report.cc
index 1c594c5..f858941 100644
--- a/chrome_frame/crash_reporting/crash_report.cc
+++ b/chrome_frame/crash_reporting/crash_report.cc
@@ -1,3 +1,4 @@
+
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,10 +11,13 @@
#include "breakpad/src/client/windows/handler/exception_handler.h"
#include "chrome_frame/crash_reporting/vectored_handler.h"
#include "chrome_frame/crash_reporting/vectored_handler-impl.h"
+#include "chrome_frame/utils.h"
namespace {
// TODO(joshia): factor out common code with chrome used for crash reporting
const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
+const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
+
google_breakpad::ExceptionHandler* g_breakpad = NULL;
__declspec(naked)
@@ -56,6 +60,15 @@ class Win32VEHTraits : public VEHTraitsBase {
extern "C" IMAGE_DOS_HEADER __ImageBase;
+std::wstring GetCrashServerPipeName(const std::wstring& user_sid) {
+ if (IsHeadlessMode())
+ return kChromePipeName;
+
+ std::wstring pipe_name = kGoogleUpdatePipeName;
+ pipe_name += user_sid;
+ return pipe_name;
+}
+
bool InitializeVectoredCrashReporting(
bool full_dump,
const wchar_t* user_sid,
@@ -66,8 +79,7 @@ bool InitializeVectoredCrashReporting(
if (g_breakpad)
return true;
- std::wstring pipe_name(kGoogleUpdatePipeName);
- pipe_name += user_sid;
+ std::wstring pipe_name = GetCrashServerPipeName(user_sid);
if (dump_path.empty()) {
return false;
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();
+}
+
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 1edbee9..b97e461 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -47,6 +47,10 @@ const wchar_t kDevChannelName[] = L"-dev";
const wchar_t kChromeAttachExternalTabPrefix[] = L"attach_external_tab";
+// Indicates that we are running in a test environment, where execptions, etc
+// are handled by the chrome test crash server.
+const wchar_t kChromeFrameHeadlessMode[] = L"ChromeFrameHeadlessMode";
+
HRESULT UtilRegisterTypeLib(HINSTANCE tlb_instance,
LPCOLESTR index,
bool for_current_user_only) {
@@ -546,6 +550,31 @@ bool GetConfigBool(bool default_value, const wchar_t* value_name) {
return (value != FALSE);
}
+bool SetConfigInt(const wchar_t* value_name, int value) {
+ RegKey config_key;
+ if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey,
+ KEY_SET_VALUE)) {
+ if (config_key.WriteValue(value_name, value)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SetConfigBool(const wchar_t* value_name, bool value) {
+ return SetConfigInt(value_name, value);
+}
+
+bool DeleteConfigValue(const wchar_t* value_name) {
+ RegKey config_key;
+ if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey,
+ KEY_WRITE)) {
+ return config_key.DeleteValue(value_name);
+ }
+ return false;
+}
+
bool IsOptInUrl(const wchar_t* url) {
RegKey config_key;
if (!config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, KEY_READ))
@@ -667,3 +696,9 @@ bool IsSubFrameRequest(IUnknown* service_provider) {
return is_non_top_level_request;
}
+
+bool IsHeadlessMode() {
+ bool headless = GetConfigBool(false, kChromeFrameHeadlessMode);
+ return headless;
+}
+
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index a685691..f71bb7d 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -181,6 +181,19 @@ bool GetConfigBool(bool default_value, const wchar_t* value_name);
// Gets an integer configuration value from the registry.
int GetConfigInt(int default_value, const wchar_t* value_name);
+// Sets an integer configuration value in the registry.
+bool SetConfigInt(const wchar_t* value_name, int value);
+
+// Sets a boolean integer configuration value in the registry.
+bool SetConfigBool(const wchar_t* value_name, bool value);
+
+// Deletes the configuration value passed in.
+bool DeleteConfigValue(const wchar_t* value_name);
+
+// Returns true if we are running in headless mode in which case we need to
+// gather crash dumps, etc to send them to the crash server.
+bool IsHeadlessMode();
+
// Check if this url is opting into Chrome Frame based on static settings.
bool IsOptInUrl(const wchar_t* url);
@@ -278,4 +291,6 @@ STDMETHODIMP QueryInterfaceIfDelegateSupports(void* obj, REFIID iid,
#define COM_INTERFACE_BLIND_DELEGATE() \
COM_INTERFACE_ENTRY_FUNC_BLIND(0, CheckOutgoingInterface<_ComMapClass>)
+extern const wchar_t kChromeFrameHeadlessMode[];
+
#endif // CHROME_FRAME_UTILS_H_