This moves running and waiting for the test executable out of main().
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/src/TestLauncher/TestLauncher.c | 162 +++++++++++++----------- 1 file changed, 85 insertions(+), 77 deletions(-)
diff --git a/testbot/src/TestLauncher/TestLauncher.c b/testbot/src/TestLauncher/TestLauncher.c index b024714ac..022f25c98 100644 --- a/testbot/src/TestLauncher/TestLauncher.c +++ b/testbot/src/TestLauncher/TestLauncher.c @@ -208,6 +208,86 @@ BOOL CALLBACK DetectCriticalErrorDialog(HWND TopWnd, LPARAM lParam) return TRUE; }
+DWORD Start; + +DWORD RunTest(char *TestExeFileName, char* CommandLine, DWORD TimeOut, DWORD *Pid) +{ + STARTUPINFOA StartupInfo; + PROCESS_INFORMATION ProcessInformation; + DWORD ExitCode, WaitTimeOut; + + StartupInfo.cb = sizeof(STARTUPINFOA); + GetStartupInfoA(&StartupInfo); + StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + /* Unlike WineTest we do not have the luxury of first running the test with + * a --list argument. This means we cannot use SetErrorMode() to check + * whether there are missing dependencies as it could modify the test + * results... + */ + if (! CreateProcessA(NULL, CommandLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &StartupInfo, &ProcessInformation)) + { + Error("CreateProcess failed (error %lu)\n", GetLastError()); + ExitProcess(1); + } + CloseHandle(ProcessInformation.hThread); + *Pid = ProcessInformation.dwProcessId; + + WaitTimeOut = 100; + ExitCode = WAIT_TIMEOUT; + while (ExitCode == WAIT_TIMEOUT) + { + DWORD Elapsed, Remaining; + + ExitCode = WaitForSingleObject(ProcessInformation.hProcess, WaitTimeOut); + Elapsed = GetTickCount() - Start; + if (ExitCode != WAIT_TIMEOUT || Elapsed > TimeOut) + break; + + /* ...instead detect the critical error dialog that pops up */ + EnumWindows(DetectCriticalErrorDialog, (LPARAM)TestExeFileName); + if (Skips) + { + ExitCode = WAIT_OBJECT_0; + break; + } + + Remaining = TimeOut == INFINITE ? TimeOut : TimeOut - Elapsed; + WaitTimeOut = (Elapsed > 3000) ? Remaining : + (2 * WaitTimeOut < Remaining) ? 2 * WaitTimeOut : + Remaining; + } + + if (ExitCode != WAIT_OBJECT_0) + { + switch (ExitCode) + { + case WAIT_FAILED: + Error("Wait for child failed (error %lu)\n", GetLastError()); + break; + + case WAIT_TIMEOUT: + /* The 'exit code' on the done line identifies timeouts */ + break; + + default: + Error("Unexpected return value %lu from wait for child\n", ExitCode); + break; + } + if (!TerminateProcess(ProcessInformation.hProcess, 257)) + Error("TerminateProcess failed (error %lu)\n", GetLastError()); + } + else if (!Skips && !GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode)) + { + Error("Could not get the child exit code (error %lu)\n", GetLastError()); + ExitCode = 259; + } + CloseHandle(ProcessInformation.hProcess); + return ExitCode; +}
/* * Command line parsing and test running. @@ -216,7 +296,7 @@ BOOL CALLBACK DetectCriticalErrorDialog(HWND TopWnd, LPARAM lParam) int main(int argc, char *argv[]) { int Arg; - DWORD Start, TimeOut, WaitTimeOut; + DWORD TimeOut; BOOL UsageError; char TestExeFullName[MAX_PATH]; char *TestExeFileName; @@ -225,9 +305,7 @@ int main(int argc, char *argv[]) int TestArg; char *CommandLine, *p; int CommandLen; - STARTUPINFOA StartupInfo; - PROCESS_INFORMATION ProcessInformation; - DWORD ExitCode; + DWORD Pid, ExitCode;
Name0 = p = argv[0]; while (*p != '\0') @@ -340,82 +418,12 @@ int main(int argc, char *argv[]) printf("%s:%s start -\n", TestName, Subtest); fflush(stdout);
- StartupInfo.cb = sizeof(STARTUPINFOA); - GetStartupInfoA(&StartupInfo); - StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - - /* Unlike WineTest we do not have the luxury of first running the test with - * a --list argument. This means we cannot use SetErrorMode() to check - * whether there are missing dependencies as it could modify the test - * results... - */ - if (! CreateProcessA(NULL, CommandLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &StartupInfo, &ProcessInformation)) - { - Error("CreateProcess failed (error %lu)\n", GetLastError()); - return 1; - } - CloseHandle(ProcessInformation.hThread); - - WaitTimeOut = 100; - ExitCode = WAIT_TIMEOUT; - while (ExitCode == WAIT_TIMEOUT) - { - DWORD Elapsed, Remaining; - - ExitCode = WaitForSingleObject(ProcessInformation.hProcess, WaitTimeOut); - Elapsed = GetTickCount() - Start; - if (ExitCode != WAIT_TIMEOUT || Elapsed > TimeOut) - break; - - /* ...instead detect the critical error dialog that pops up */ - EnumWindows(DetectCriticalErrorDialog, (LPARAM)TestExeFileName); - if (Skips) - { - ExitCode = WAIT_OBJECT_0; - break; - } - - Remaining = TimeOut == INFINITE ? TimeOut : TimeOut - Elapsed; - WaitTimeOut = (Elapsed > 3000) ? Remaining : - (2 * WaitTimeOut < Remaining) ? 2 * WaitTimeOut : - Remaining; - } - - if (ExitCode != WAIT_OBJECT_0) - { - switch (ExitCode) - { - case WAIT_FAILED: - Error("Wait for child failed (error %lu)\n", GetLastError()); - break; - - case WAIT_TIMEOUT: - /* The 'exit code' on the done line identifies timeouts */ - break; - - default: - Error("Unexpected return value %lu from wait for child\n", ExitCode); - break; - } - if (!TerminateProcess(ProcessInformation.hProcess, 257)) - Error("TerminateProcess failed (error %lu)\n", GetLastError()); - } - else if (!Skips && !GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode)) - { - Error("Could not get the child exit code (error %lu)\n", GetLastError()); - ExitCode = 259; - } - CloseHandle(ProcessInformation.hProcess); - + ExitCode = RunTest(TestExeFileName, CommandLine, TimeOut, &Pid); if (Skips) - printf("%04lx:%s: 0 tests executed (0 marked as todo, 0 failures), %u skipped.\n", ProcessInformation.dwProcessId, Subtest, Skips); + printf("%04lx:%s: 0 tests executed (0 marked as todo, 0 failures), %u skipped.\n", Pid, Subtest, Skips);
printf("%s:%s:%04lx done (%ld) in %lds\n", TestName, Subtest, - ProcessInformation.dwProcessId, ExitCode, - (GetTickCount() - Start) / 1000); + Pid, ExitCode, (GetTickCount() - Start) / 1000);
return 0; }
These happen for side-by-side dlls when the test executable has no manifest and should be reported as a failure.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/src/TestLauncher/TestLauncher.c | 30 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/testbot/src/TestLauncher/TestLauncher.c b/testbot/src/TestLauncher/TestLauncher.c index 022f25c98..9f4cdf9f4 100644 --- a/testbot/src/TestLauncher/TestLauncher.c +++ b/testbot/src/TestLauncher/TestLauncher.c @@ -139,6 +139,7 @@ static BOOL running_on_visible_desktop (void) */
const char *Subtest; +static unsigned Failures = 0; static unsigned Skips = 0;
BOOL CALLBACK DumpCriticalErrorDescription(HWND hWnd, LPARAM lParam) @@ -164,6 +165,7 @@ BOOL CALLBACK DetectCriticalErrorDialog(HWND TopWnd, LPARAM lParam) const char* TestFileName = (char*)lParam; int Count, TestFileLen; char Buffer[512]; + BOOL IsSkip = TRUE; const char* Reason;
/* The window pid does not match the CreateProcess() one so it cannot be @@ -183,22 +185,31 @@ BOOL CALLBACK DetectCriticalErrorDialog(HWND TopWnd, LPARAM lParam) Reason = NULL; if (strcmp(Buffer + TestFileLen, " - System Error") == 0) Reason = "missing dll"; + else if (strcmp(Buffer + TestFileLen, " - Unable To Locate Component") == 0) + { + /* Sadly Windows >= 7 reports this as "System Error" */ + Reason = "missing manifest for side-by-side dll"; + IsSkip = FALSE; + } else if (strcmp(Buffer + TestFileLen, " - Entry Point Not Found") == 0) Reason = "missing entry point"; else if (strcmp(Buffer + TestFileLen, " - Ordinal Not Found") == 0) Reason = "missing ordinal"; else if (strncmp(Buffer + TestFileLen, " - ", 3) == 0) - /* Old Windows version used to translate the dialog */ + /* Old Windows versions used to translate the dialog so treat any + * unrecognized critical error as a skip. + */ Reason = "unrecognized critical error";
if (Reason) { - Skips++; + IsSkip ? Skips++ : Failures++; /* An empty test unit name is allowed on the start, summary and done * lines, but not on individual failure / skip lines. */ - printf("%s.c:0: Tests skipped: %s (details below)\n", - (*Subtest ? Subtest : "testlauncher"), Reason); + printf("%s.c:0: %s: %s (details below)\n", + (*Subtest ? Subtest : "testlauncher"), + (IsSkip ? "Tests skipped" : "Test failed"), Reason); printf("| %s\n", Buffer); EnumChildWindows(TopWnd, DumpCriticalErrorDescription, (LPARAM)TopWnd); /* Leave the dialog open so it appears on screenshots */ @@ -249,9 +260,9 @@ DWORD RunTest(char *TestExeFileName, char* CommandLine, DWORD TimeOut, DWORD *Pi
/* ...instead detect the critical error dialog that pops up */ EnumWindows(DetectCriticalErrorDialog, (LPARAM)TestExeFileName); - if (Skips) + if (Skips || Failures) { - ExitCode = WAIT_OBJECT_0; + ExitCode = Failures ? Failures : WAIT_OBJECT_0; break; }
@@ -280,7 +291,8 @@ DWORD RunTest(char *TestExeFileName, char* CommandLine, DWORD TimeOut, DWORD *Pi if (!TerminateProcess(ProcessInformation.hProcess, 257)) Error("TerminateProcess failed (error %lu)\n", GetLastError()); } - else if (!Skips && !GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode)) + else if (!Skips && !Failures && + !GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode)) { Error("Could not get the child exit code (error %lu)\n", GetLastError()); ExitCode = 259; @@ -419,8 +431,8 @@ int main(int argc, char *argv[]) fflush(stdout);
ExitCode = RunTest(TestExeFileName, CommandLine, TimeOut, &Pid); - if (Skips) - printf("%04lx:%s: 0 tests executed (0 marked as todo, 0 failures), %u skipped.\n", Pid, Subtest, Skips); + if (Failures || Skips) + printf("%04lx:%s: %u tests executed (0 marked as todo, %u failures), %u skipped.\n", Pid, Subtest, Failures, Failures, Skips);
printf("%s:%s:%04lx done (%ld) in %lds\n", TestName, Subtest, Pid, ExitCode, (GetTickCount() - Start) / 1000);
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/src/TestLauncher/TestLauncher.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/testbot/src/TestLauncher/TestLauncher.c b/testbot/src/TestLauncher/TestLauncher.c index 9f4cdf9f4..5f05aeb77 100644 --- a/testbot/src/TestLauncher/TestLauncher.c +++ b/testbot/src/TestLauncher/TestLauncher.c @@ -241,6 +241,14 @@ DWORD RunTest(char *TestExeFileName, char* CommandLine, DWORD TimeOut, DWORD *Pi */ if (! CreateProcessA(NULL, CommandLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &StartupInfo, &ProcessInformation)) { + if (GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) + { + Skips++; + printf("%s.c:0: Tests skipped: Side-by-side dll version not found\n", + (*Subtest ? Subtest : "testlauncher")); + *Pid = 0; + return 0; + } Error("CreateProcess failed (error %lu)\n", GetLastError()); ExitProcess(1); }