Bug 860683 - When running tests in immersive mode, connect firefox stdout to a metrotestharness pipe to route test output to mozilla test harnesses. r=bbondy
authorJim Mathies <jmathies@mozilla.com>
Thu, 11 Apr 2013 17:45:29 -0500
changeset 128515 17d705ba2d9bd875559a69cbc7bfc240dcceaeb5
parent 128514 55a6fc3b5f421070b6dff19645f8543fb6cef594
child 128516 3880c0cfd2885dfb0a3324ebcc208228321cb7a7
push id26356
push userjmathies@mozilla.com
push dateThu, 11 Apr 2013 22:45:39 +0000
treeherdermozilla-inbound@3880c0cfd288 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs860683
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 860683 - When running tests in immersive mode, connect firefox stdout to a metrotestharness pipe to route test output to mozilla test harnesses. r=bbondy
browser/app/nsBrowserApp.cpp
browser/metro/shell/testing/metrotestharness.cpp
widget/windows/winrt/MetroUtils.cpp
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -103,36 +103,34 @@ static bool IsArg(const char* arg, const
     return !strcasecmp(++arg, s);
 #endif
 
   return false;
 }
 
 #ifdef XP_WIN
 /*
- * AttachToTestsConsole - Windows helper for when we are running
+ * AttachToTestHarness - Windows helper for when we are running
  * in the immersive environment. Firefox is launched by Windows in
  * response to a request by metrotestharness, which is launched by
  * runtests.py. As such stdout in fx doesn't point to the right
  * stream. This helper touches up stdout such that test output gets
- * routed to the console the tests are run in.
+ * routed to a named pipe metrotestharness creates and dumps to its
+ * stdout.
  */
-static void AttachToTestsConsole(DWORD aProcessId)
+static void AttachToTestHarness()
 {
-  if (!AttachConsole(aProcessId)) {
-    OutputDebugStringW(L"Could not attach to console.\n");
-    return;
-  }
-
-  HANDLE winOut = CreateFileA("CONOUT$",
-                              GENERIC_READ | GENERIC_WRITE,
+  // attach to the metrotestharness named logging pipe
+  HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness",
+                              GENERIC_WRITE,
                               FILE_SHARE_WRITE, 0,
                               OPEN_EXISTING, 0, 0);
+  
   if (winOut == INVALID_HANDLE_VALUE) {
-    OutputDebugStringW(L"Could not attach to console.\n");
+    OutputDebugStringW(L"Could not create named logging pipe.\n");
     return;
   }
 
   // Set the c runtime handle
   int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND);
   if (stdOut == -1) {
     OutputDebugStringW(L"Could not open c-runtime handle.\n");
     return;
@@ -350,33 +348,28 @@ static int do_main(int argc, char* argv[
       char* ptr = buffer;
       newArgv[0] = ptr;
       while (*ptr != NULL &&
              (ptr - buffer) < sizeof(buffer) &&
              newArgc < ARRAYSIZE(newArgv)) {
         if (isspace(*ptr)) {
           *ptr = '\0';
           ptr++;
-          // Check for the console id the metrotestharness passes in, we need
-          // to connect up to this so test output goes to the right place.
-          if (ptr && !strncmp(ptr, kMetroConsoleIdParam, strlen(kMetroConsoleIdParam))) {
-            DWORD processId = strtol(ptr + strlen(kMetroConsoleIdParam), nullptr, 10);
-            if (processId > 0) {
-              AttachToTestsConsole(processId);
-            }
-            continue;
-          }
           newArgv[newArgc] = ptr;
           newArgc++;
           continue;
         }
         ptr++;
       }
       if (ptr == newArgv[newArgc-1])
         newArgc--;
+
+      // attach browser stdout to metrotestharness stdout
+      AttachToTestHarness();
+
       int result = XRE_main(newArgc, newArgv, appData, mainFlags);
       XRE_FreeAppData(appData);
       return result;
     }
   }
 #endif
 
   int result = XRE_main(argc, argv, appData, mainFlags);
--- a/browser/metro/shell/testing/metrotestharness.cpp
+++ b/browser/metro/shell/testing/metrotestharness.cpp
@@ -23,16 +23,22 @@
 #include <strsafe.h>
 #include <io.h>
 #include <shellapi.h>
 
 static const WCHAR* kFirefoxExe = L"firefox.exe";
 static const WCHAR* kDefaultMetroBrowserIDPathKey = L"FirefoxURL";
 static const WCHAR* kDemoMetroBrowserIDPathKey = L"Mozilla.Firefox.URL";
 
+// Logging pipe handle
+HANDLE gTestOutputPipe = INVALID_HANDLE_VALUE;
+// Logging pipe read buffer
+#define PIPE_BUFFER_SIZE 4096
+char buffer[PIPE_BUFFER_SIZE + 1];
+
 CString sAppParams;
 CString sFirefoxPath;
 
 // The tests file we write out for firefox.exe which contains test
 // startup command line paramters.
 #define kMetroTestFile "tests.ini"
 
 static void Log(const wchar_t *fmt, ...)
@@ -151,22 +157,46 @@ public:
   ~DeleteTestFileHelper() {
     if (mTestFile.GetLength()) {
       Log(L"Deleting %s", CStringW(mTestFile));
       DeleteFileA(mTestFile);
     }
   }
 };
 
-static void AddConsoleIdToParams()
+static bool SetupTestOutputPipe()
 {
-  DWORD dwId = GetCurrentProcessId();
-  CString tmp;
-  tmp.Format(L" testconsoleid=%d", dwId);
-  sAppParams += tmp;
+  SECURITY_ATTRIBUTES saAttr;
+  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+  saAttr.bInheritHandle = TRUE;
+  saAttr.lpSecurityDescriptor = NULL;
+
+  gTestOutputPipe =
+    CreateNamedPipeW(L"\\\\.\\pipe\\metrotestharness",
+                     PIPE_ACCESS_INBOUND,
+                     PIPE_TYPE_BYTE|PIPE_WAIT,
+                     1,
+                     PIPE_BUFFER_SIZE,
+                     PIPE_BUFFER_SIZE, 0, NULL);
+
+  if (gTestOutputPipe == INVALID_HANDLE_VALUE) {
+    Log(L"Failed to create named logging pipe.");
+    return false;
+  }
+  return true;
+}
+
+static void ReadPipe()
+{
+  DWORD numBytesRead;
+  while (ReadFile(gTestOutputPipe, buffer, PIPE_BUFFER_SIZE, &numBytesRead, NULL) &&
+         numBytesRead) {
+    buffer[numBytesRead] = '\0';
+    printf("%s", buffer);
+  }
 }
 
 static bool Launch()
 {
   Log(L"Launching browser...");
 
   DWORD processID;
 
@@ -244,16 +274,22 @@ static bool Launch()
   if (!WriteFile(hTestFile, asciiParams, asciiParams.GetLength(), NULL, 0)) {
     CloseHandle(hTestFile);
     Fail(L"WriteFile errorno=%d", GetLastError());
     return false;
   }
   FlushFileBuffers(hTestFile);
   CloseHandle(hTestFile);
 
+  // Create a named stdout pipe for the browser
+  if (!SetupTestOutputPipe()) {
+    Fail(L"SetupTestOutputPipe failed (errno=%d)", GetLastError());
+    return false;
+  }
+
   // Launch firefox
   hr = activateMgr->ActivateApplication(appModelID, L"", AO_NOERRORUI, &processID);
   if (FAILED(hr)) {
     Fail(L"ActivateApplication result %X", hr);
     return false;
   }
 
   Log(L"Activation succeeded. processid=%d", processID);
@@ -263,23 +299,34 @@ static bool Launch()
     Fail(L"Couldn't find child process. (%d)", GetLastError());
     return false;
   }
 
   Log(L"Waiting on child process...");
 
   MSG msg;
   DWORD waitResult = WAIT_TIMEOUT;
-  while ((waitResult = WaitForSingleObject(child, 10)) != WAIT_OBJECT_0) {
-    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+  HANDLE handles[2] = { child, gTestOutputPipe };
+  while ((waitResult = MsgWaitForMultipleObjects(2, handles, FALSE, INFINITE, QS_ALLINPUT)) != WAIT_OBJECT_0) {
+    if (waitResult == WAIT_FAILED) {
+      Log(L"Wait failed (errno=%d)", GetLastError());
+      break;
+    } else if (waitResult == WAIT_OBJECT_0 + 1) {
+      ReadPipe();
+    } else if (waitResult == WAIT_OBJECT_0 + 2 &&
+               PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
     }
   }
 
+  ReadPipe();
+  CloseHandle(gTestOutputPipe);
+  CloseHandle(child);
+
   Log(L"Exiting.");
   return true;
 }
 
 int wmain(int argc, WCHAR* argv[])
 {
   CoInitialize(NULL);
 
@@ -302,15 +349,14 @@ int wmain(int argc, WCHAR* argv[])
 
     sAppParams.Append(argv[idx]);
     sAppParams.Append(L" ");
   }
   sAppParams.Trim();
   if (sFirefoxPath.GetLength()) {
     Log(L"firefoxpath: '%s'", sFirefoxPath);
   }
-  AddConsoleIdToParams();
   Log(L"args: '%s'", sAppParams);
   Launch();
 
   CoUninitialize();
   return 0;
 }
--- a/widget/windows/winrt/MetroUtils.cpp
+++ b/widget/windows/winrt/MetroUtils.cpp
@@ -79,17 +79,17 @@ void Log(const wchar_t *fmt, ...)
   if(!lstrlenW(szDebugString))
     return;
 
   // MSVC, including remote debug sessions
   OutputDebugStringW(szDebugString);
   OutputDebugStringW(L"\n");
 
   // desktop console
-  wprintf(L"%s\n", szDebugString);
+  //wprintf(L"%s\n", szDebugString);
 
 #ifdef PR_LOGGING
   NS_ASSERTION(metroWidgetLog, "Called MetroUtils Log() but MetroWidget "
                                "log module doesn't exist!");
   int len = wcslen(szDebugString);
   if (len) {
     char* utf8 = new char[len+1];
     memset(utf8, 0, sizeof(utf8));