summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.cc91
1 files changed, 86 insertions, 5 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc
index c0670fe..3b0c132 100644
--- a/chrome_frame/test/chrome_frame_test_utils.cc
+++ b/chrome_frame/test/chrome_frame_test_utils.cc
@@ -27,6 +27,16 @@
namespace chrome_frame_test {
+const wchar_t kCrashServicePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
+
+const DWORD kCrashServicePipeDesiredAccess = FILE_READ_DATA |
+ FILE_WRITE_DATA |
+ FILE_WRITE_ATTRIBUTES;
+
+const DWORD kCrashServicePipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
+ SECURITY_SQOS_PRESENT;
+const int kCrashServiceStartupTimeoutMs = 500;
+
const wchar_t kIEImageName[] = L"iexplore.exe";
const wchar_t kIEBrokerImageName[] = L"ieuser.exe";
const wchar_t kFirefoxImageName[] = L"firefox.exe";
@@ -489,7 +499,63 @@ CloseIeAtEndOfScope::~CloseIeAtEndOfScope() {
DLOG_IF(ERROR, closed != 0) << "Closed " << closed << " windows forcefully";
}
+// Attempt to connect to a running crash_service instance. Success occurs if we
+// can actually connect to the service's pipe or we receive ERROR_PIPE_BUSY.
+// Waits up to |timeout_ms| for success. |timeout_ms| may be 0, meaning only try
+// once, or negative, meaning wait forever.
+bool DetectRunningCrashService(int timeout_ms) {
+ // Wait for the crash_service.exe to be ready for clients.
+ base::Time start = base::Time::Now();
+ ScopedHandle new_pipe;
+
+ while (true) {
+ new_pipe.Set(::CreateFile(kCrashServicePipeName,
+ kCrashServicePipeDesiredAccess,
+ 0, // dwShareMode
+ NULL, // lpSecurityAttributes
+ OPEN_EXISTING,
+ kCrashServicePipeFlagsAndAttributes,
+ NULL)); // hTemplateFile
+
+ if (new_pipe.IsValid()) {
+ return true;
+ }
+
+ switch (::GetLastError()) {
+ case ERROR_PIPE_BUSY:
+ // OK, it exists, let's assume that clients will eventually be able to
+ // connect to it.
+ return true;
+ case ERROR_FILE_NOT_FOUND:
+ // Wait a bit longer
+ break;
+ default:
+ DLOG(WARNING) << "Unexpected error while checking crash_service.exe's "
+ << "pipe: " << win_util::FormatLastWin32Error();
+ // Go ahead and wait in case it clears up.
+ break;
+ }
+
+ if (timeout_ms == 0) {
+ return false;
+ } else if (timeout_ms > 0) {
+ base::TimeDelta duration = base::Time::Now() - start;
+ if (duration.InMilliseconds() > timeout_ms) {
+ return false;
+ }
+ }
+
+ Sleep(10);
+ }
+}
+
base::ProcessHandle StartCrashService() {
+ if (DetectRunningCrashService(kCrashServiceStartupTimeoutMs)) {
+ DLOG(INFO) << "crash_service.exe is already running. We will use the "
+ << "existing process and leave it running after tests complete.";
+ return NULL;
+ }
+
FilePath exe_dir;
if (!PathService::Get(base::DIR_EXE, &exe_dir)) {
DCHECK(false);
@@ -498,6 +564,8 @@ base::ProcessHandle StartCrashService() {
base::ProcessHandle crash_service = NULL;
+ DLOG(INFO) << "Starting crash_service.exe so you know if a test crashes!";
+
FilePath crash_service_path = exe_dir.AppendASCII("crash_service.exe");
if (!base::LaunchApp(crash_service_path.value(), false, false,
&crash_service)) {
@@ -505,11 +573,24 @@ base::ProcessHandle StartCrashService() {
return NULL;
}
- DLOG(INFO) << "Started crash_service.exe so you know if a test crashes!";
- // This sleep is to ensure that the crash service is done initializing, i.e
- // the pipe creation, etc.
- Sleep(500);
- return crash_service;
+ base::Time start = base::Time::Now();
+
+ if (DetectRunningCrashService(kCrashServiceStartupTimeoutMs)) {
+ DLOG(INFO) << "crash_service.exe is ready for clients in "
+ << (base::Time::Now() - start).InMilliseconds() << "ms.";
+ return crash_service;
+ } else {
+ DLOG(ERROR) << "crash_service.exe failed to accept client connections "
+ << "within " << kCrashServiceStartupTimeoutMs << "ms. "
+ << "Terminating it now.";
+
+ // First check to see if it's even still running just to minimize the
+ // likelihood of spurious error messages from KillProcess.
+ if (WAIT_OBJECT_0 != ::WaitForSingleObject(crash_service, 0)) {
+ base::KillProcess(crash_service, 0, false);
+ }
+ return NULL;
+ }
}
} // namespace chrome_frame_test