summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/chrome_frame_test_utils.h
diff options
context:
space:
mode:
authorananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-22 00:07:15 +0000
committerananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-22 00:07:15 +0000
commit3c8a5c513f77bff458cd834a223d6d6eda858ba2 (patch)
tree0fb211b5a7848e1782fc1f82ba9114d602a08b66 /chrome_frame/test/chrome_frame_test_utils.h
parent6b365e70044137c8f83e598a28e934b553c80a21 (diff)
downloadchromium_src-3c8a5c513f77bff458cd834a223d6d6eda858ba2.zip
chromium_src-3c8a5c513f77bff458cd834a223d6d6eda858ba2.tar.gz
chromium_src-3c8a5c513f77bff458cd834a223d6d6eda858ba2.tar.bz2
Ensure that chrome frame tests don't hang indefinitely if IE does not respond to outgoing
COM calls issued by these tests. These tests hang intermittently on the IE9 builder on the experimental waterfall. To achieve this we register a COM message filter and set a windows timer in the ChromeFrame TimedMsgLoop object. In the message filter we look for a WM_TIMER created by the message loop object and on finding it abort the outgoing COM call. This flag is percolated to the related event sinks which leak the underlying interfaces to prevent the Release calls from hanging too. BUG=none TEST=none Review URL: http://codereview.chromium.org/6051003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69901 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/test/chrome_frame_test_utils.h')
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.h126
1 files changed, 125 insertions, 1 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h
index 5d20e8a..0bd0aad 100644
--- a/chrome_frame/test/chrome_frame_test_utils.h
+++ b/chrome_frame/test/chrome_frame_test_utils.h
@@ -7,6 +7,7 @@
#include <atlbase.h>
#include <atlcom.h>
+#include <atlwin.h>
#include <exdisp.h>
#include <exdispid.h>
#include <mshtml.h>
@@ -31,6 +32,8 @@
// Include without path to make GYP build see it.
#include "chrome_tab.h" // NOLINT
+#include "gtest/gtest.h"
+
// Needed for CreateFunctor.
#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"
@@ -74,11 +77,122 @@ class LowIntegrityToken {
bool impersonated_;
};
+// This class implements the COM IMessageFilter interface and is used to detect
+// hung outgoing COM calls which are typically to IE. If IE is hung for any
+// reason the chrome frame tests should not hang indefinitely. This class
+// basically cancels the outgoing call if the WM_TIMER which is set by the
+// TimedMsgLoop object is posted to the message queue.
+class HungCOMCallDetector
+ : public CComObjectRootEx<CComMultiThreadModel>,
+ public IMessageFilter,
+ public CWindowImpl<HungCOMCallDetector> {
+ public:
+ HungCOMCallDetector()
+ : is_hung_(false) {
+ LOG(INFO) << __FUNCTION__;
+ }
+
+ ~HungCOMCallDetector() {
+ LOG(INFO) << __FUNCTION__;
+ }
+
+ BEGIN_MSG_MAP(HungCOMCallDetector)
+ MESSAGE_HANDLER(WM_TIMER, OnTimer)
+ END_MSG_MAP()
+
+ BEGIN_COM_MAP(HungCOMCallDetector)
+ COM_INTERFACE_ENTRY(IMessageFilter)
+ END_COM_MAP()
+
+ static CComObject<HungCOMCallDetector>* Setup(int timeout_seconds) {
+ CComObject<HungCOMCallDetector>* this_instance = NULL;
+ CComObject<HungCOMCallDetector>::CreateInstance(&this_instance);
+ EXPECT_TRUE(this_instance != NULL);
+ scoped_refptr<HungCOMCallDetector> ref_instance = this_instance;
+
+ HRESULT hr = ref_instance->Initialize(timeout_seconds);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to Initialize Hung COM call detector. Error:"
+ << hr;
+ return NULL;
+ }
+ return this_instance;
+ }
+
+ void TearDown() {
+ ScopedComPtr<IMessageFilter> prev_filter;
+ CoRegisterMessageFilter(prev_filter_.get(), prev_filter.Receive());
+ DestroyWindow();
+ m_hWnd = NULL;
+ }
+
+ STDMETHOD_(DWORD, HandleInComingCall)(DWORD call_type,
+ HTASK caller,
+ DWORD tick_count,
+ LPINTERFACEINFO interface_info) {
+ return SERVERCALL_ISHANDLED;
+ }
+
+ STDMETHOD_(DWORD, RetryRejectedCall)(HTASK callee,
+ DWORD tick_count,
+ DWORD reject_type) {
+ return -1;
+ }
+
+ STDMETHOD_(DWORD, MessagePending)(HTASK callee,
+ DWORD tick_count,
+ DWORD pending_type) {
+ MSG msg = {0};
+ if (PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)) {
+ is_hung_ = true;
+ return PENDINGMSG_CANCELCALL;
+ }
+ return PENDINGMSG_WAITDEFPROCESS;
+ }
+
+ bool is_hung() const {
+ return is_hung_;
+ }
+
+ LRESULT OnTimer(UINT msg, WPARAM wp, LPARAM lp, BOOL& handled) { // NOLINT
+ return 1;
+ }
+
+ private:
+ HRESULT Initialize(int timeout_seconds) {
+ // Create a window for the purpose of setting a windows timer for
+ // detecting whether any outgoing COM call issued in this context
+ // hangs.
+ // We then register a COM message filter which basically looks for the
+ // timer posted to this window and cancels the outgoing call.
+ Create(HWND_MESSAGE);
+ if (!IsWindow()) {
+ LOG(ERROR) << "Failed to create window. Error:" << GetLastError();
+ return E_FAIL;
+ }
+
+ HRESULT hr = CoRegisterMessageFilter(this, prev_filter_.Receive());
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to register message filter. Error:" << hr;
+ return hr;
+ }
+
+ static const int kHungDetectTimerId = 0x0000baba;
+ SetTimer(kHungDetectTimerId, 1000 * (timeout_seconds + 2), NULL);
+ return S_OK;
+ }
+
+ // used to detect if outgoing COM calls hung.
+ bool is_hung_;
+ ScopedComPtr<IMessageFilter> prev_filter_;
+};
+
// MessageLoopForUI wrapper that runs only for a limited time.
// We need a UI message loop in the main thread.
class TimedMsgLoop {
public:
- TimedMsgLoop() : quit_loop_invoked_(false) {}
+ TimedMsgLoop() : quit_loop_invoked_(false) {
+ }
void RunFor(int seconds) {
QuitAfter(seconds);
@@ -207,6 +321,16 @@ class ScopedVirtualizeHklmAndHkcu {
scoped_ptr<TempRegKeyOverride> hkcu_;
};
+// Attempts to kill all the processes on the current machine that were launched
+// from the given executable name, ending them with the given exit code. If
+// filter is non-null, then only processes selected by the filter are killed.
+// Returns true if all processes were able to be killed off, false if at least
+// one couldn't be killed.
+// NOTE: This function is based on the base\process_util.h helper function
+// KillProcesses. Takes in the wait flag as a parameter.
+bool KillProcesses(const std::wstring& executable_name, int exit_code,
+ bool wait);
+
} // namespace chrome_frame_test
// TODO(tommi): This is a temporary workaround while we're getting our