Author: cfinck
Date: Mon Jan 5 06:41:34 2009
New Revision: 38580
URL:
http://svn.reactos.org/svn/reactos?rev=38580&view=rev
Log:
Introducing the "ReactOS Automatic Testing Utility", superseding our current
syssetup/cmd/dbgprint hack for running automatic regression tests.
Without any parameters, it mostly works the same as our current solution, but all in a
standalone application.
Adding the /w parameter will submit all results to the web service committed in my
previous commit.
The application would also make it possible to run Wine Tests regularly on a Windows
machine and submitting the results.
This would make sure that all Wine tests also pass under Windows.
Added:
trunk/rostests/rosautotest/ (with props)
trunk/rostests/rosautotest/main.c (with props)
trunk/rostests/rosautotest/precomp.h (with props)
trunk/rostests/rosautotest/rosautotest.rbuild (with props)
trunk/rostests/rosautotest/shutdown.c (with props)
trunk/rostests/rosautotest/tools.c (with props)
trunk/rostests/rosautotest/webservice.c (with props)
trunk/rostests/rosautotest/winetests.c (with props)
Modified:
trunk/rostests/directory.rbuild
Modified: trunk/rostests/directory.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/directory.rbuild?rev=3858…
==============================================================================
--- trunk/rostests/directory.rbuild [iso-8859-1] (original)
+++ trunk/rostests/directory.rbuild [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -13,6 +13,9 @@
<directory name="regtests_by_casper">
<xi:include href="regtests_by_casper/directory.rbuild" />
</directory>
+ <directory name="rosautotest">
+ <xi:include href="rosautotest/rosautotest.rbuild" />
+ </directory>
<directory name="tests">
<xi:include href="tests/directory.rbuild" />
</directory>
Propchange: trunk/rostests/rosautotest/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Jan 5 06:41:34 2009
@@ -1,0 +1,7 @@
+GNUmakefile
+*.vcproj
+*.user
+*.cbp
+*.ncb
+*.suo
+*.sln
Added: trunk/rostests/rosautotest/main.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/main.c?rev=38…
==============================================================================
--- trunk/rostests/rosautotest/main.c (added)
+++ trunk/rostests/rosautotest/main.c [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,326 @@
+/*
+ * PROJECT: ReactOS Automatic Testing Utility
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Main implementation file
+ * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+typedef void (WINAPI *GETSYSINFO)(LPSYSTEM_INFO);
+
+APP_OPTIONS AppOptions = {0};
+HANDLE hProcessHeap;
+PCHAR AuthenticationRequestString = NULL;
+PCHAR SystemInfoRequestString = NULL;
+
+/**
+ * Gets a value from a specified INI file and returns it converted to ASCII.
+ *
+ * @param AppName
+ * The INI section to look in (lpAppName parameter passed to GetPrivateProfileStringW)
+ *
+ * @param KeyName
+ * The key to look for in the specified section (lpKeyName parameter passed to
GetPrivateProfileStringW)
+ *
+ * @param FileName
+ * The path to the INI file
+ *
+ * @param ReturnedValue
+ * Pointer to a CHAR pointer, which will receive the read and converted value.
+ * The caller needs to HeapFree that value manually.
+ *
+ * @return
+ * Returns the string length of the read value (in characters) or zero if we didn't
get any value.
+ */
+static DWORD
+IntGetINIValueA(PCWCH AppName, PCWCH KeyName, PCWCH FileName, char** ReturnedValue)
+{
+ DWORD Length;
+ WCHAR Buffer[2048];
+
+ /* Load the value into a temporary Unicode buffer */
+ Length = GetPrivateProfileStringW(AppName, KeyName, NULL, Buffer, sizeof(Buffer) /
sizeof(WCHAR), FileName);
+
+ if(!Length)
+ return 0;
+
+ /* Convert the string to ANSI charset */
+ *ReturnedValue = HeapAlloc(hProcessHeap, 0, Length + 1);
+ WideCharToMultiByte(CP_ACP, 0, Buffer, Length + 1, *ReturnedValue, Length + 1, NULL,
NULL);
+
+ return Length;
+}
+
+/**
+ * Gets the username and password hash from the "rosautotest.ini" file if the
user enabled submitting the results to the web service.
+ * The "rosautotest.ini" file should look like this:
+ *
+ * [Login]
+ * UserName=TestMan
+ * PasswordHash=1234567890abcdef1234567890abcdef
+ */
+static BOOL
+IntGetConfigurationValues()
+{
+ const CHAR PasswordHashProp[] = "&passwordhash=";
+ const CHAR UserNameProp[] = "&username=";
+
+ DWORD DataLength;
+ DWORD Length;
+ PCHAR PasswordHash;
+ PCHAR UserName;
+ WCHAR ConfigFile[MAX_PATH];
+
+ /* We only need this if the results are going to be submitted */
+ if(!AppOptions.Submit)
+ return TRUE;
+
+ /* Build the path to the configuration file */
+ Length = GetWindowsDirectoryW(ConfigFile, MAX_PATH);
+ wcscpy(&ConfigFile[Length], L"\\rosautotest.ini");
+
+ /* Check if it exists */
+ if(GetFileAttributesW(ConfigFile) == INVALID_FILE_ATTRIBUTES)
+ return FALSE;
+
+ /* Get the required length of the authentication request string */
+ DataLength = sizeof(UserNameProp) - 1;
+ Length = IntGetINIValueA(L"Login", L"UserName", ConfigFile,
&UserName);
+
+ if(!Length)
+ {
+ StringOut("UserName is missing in the configuration file\n");
+ return FALSE;
+ }
+
+ /* Some characters might need to be escaped and an escaped character takes 3 bytes
*/
+ DataLength += 3 * Length;
+
+ DataLength += sizeof(PasswordHashProp) - 1;
+ Length = IntGetINIValueA(L"Login", L"PasswordHash", ConfigFile,
&PasswordHash);
+
+ if(!Length)
+ {
+ StringOut("PasswordHash is missing in the configuration file\n");
+ return FALSE;
+ }
+
+ DataLength += 3 * Length;
+
+ /* Build the string */
+ AuthenticationRequestString = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+
+ strcpy(AuthenticationRequestString, UserNameProp);
+ EscapeString(&AuthenticationRequestString[strlen(AuthenticationRequestString)],
UserName);
+
+ strcat(AuthenticationRequestString, PasswordHashProp);
+ EscapeString(&AuthenticationRequestString[strlen(AuthenticationRequestString)],
PasswordHash);
+
+ return TRUE;
+}
+
+/**
+ * Determines on which platform we're running on.
+ * Prepares the appropriate request strings needed if we want to submit test results to
the web service.
+ */
+static BOOL
+IntGetBuildAndPlatform()
+{
+ const CHAR PlatformProp[] = "&platform=";
+ const CHAR RevisionProp[] = "&revision=";
+
+ CHAR BuildNo[BUILDNO_LENGTH];
+ CHAR Platform[PLATFORM_LENGTH];
+ CHAR PlatformArchitecture[3];
+ CHAR ProductType;
+ DWORD DataLength;
+ GETSYSINFO GetSysInfo;
+ HANDLE hKernel32;
+ OSVERSIONINFOEXW os;
+ SYSTEM_INFO si;
+ WCHAR WindowsDirectory[MAX_PATH];
+
+ /* Get the build from the define */
+ _ultoa(KERNEL_VERSION_BUILD_HEX, BuildNo, 10);
+
+ /* Check if we are running under ReactOS from the SystemRoot directory */
+ GetWindowsDirectoryW(WindowsDirectory, MAX_PATH);
+
+ if(!_wcsnicmp(&WindowsDirectory[3], L"reactos", 7))
+ {
+ /* Yes, we are most-probably under ReactOS */
+ strcpy(Platform, "reactos");
+ }
+ else
+ {
+ /* No, then use the info from GetVersionExW */
+ os.dwOSVersionInfoSize = sizeof(os);
+
+ if(!GetVersionExW((LPOSVERSIONINFOW)&os))
+ {
+ StringOut("GetVersionExW failed\n");
+ return FALSE;
+ }
+
+ if(os.dwMajorVersion < 5)
+ {
+ StringOut("Application requires at least Windows 2000!\n");
+ return FALSE;
+ }
+
+ if(os.wProductType == VER_NT_WORKSTATION)
+ ProductType = 'w';
+ else
+ ProductType = 's';
+
+ /* Print all necessary identification information into the Platform string */
+ sprintf(Platform, "%lu.%lu.%lu.%u.%u.%c", os.dwMajorVersion,
os.dwMinorVersion, os.dwBuildNumber, os.wServicePackMajor, os.wServicePackMinor,
ProductType);
+ }
+
+ /* We also need to know about the processor architecture.
+ To retrieve this information accurately, check whether
"GetNativeSystemInfo" is exported and use it then, otherwise fall back to
"GetSystemInfo". */
+ hKernel32 = GetModuleHandleW(L"KERNEL32.DLL");
+ GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetNativeSystemInfo");
+
+ if(!GetSysInfo)
+ GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetSystemInfo");
+
+ GetSysInfo(&si);
+
+ PlatformArchitecture[0] = '.';
+ _ultoa(si.wProcessorArchitecture, &PlatformArchitecture[1], 10);
+ PlatformArchitecture[2] = 0;
+ strcat(Platform, PlatformArchitecture);
+
+ /* Get the required length of the system info request string */
+ DataLength = sizeof(RevisionProp) - 1;
+ DataLength += strlen(BuildNo);
+ DataLength += sizeof(PlatformProp) - 1;
+ DataLength += strlen(Platform);
+
+ /* Now build the string */
+ SystemInfoRequestString = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+ strcpy(SystemInfoRequestString, RevisionProp);
+ strcat(SystemInfoRequestString, BuildNo);
+ strcat(SystemInfoRequestString, PlatformProp);
+ strcat(SystemInfoRequestString, Platform);
+
+ return TRUE;
+}
+
+/**
+ * Prints the application usage.
+ */
+static VOID
+IntPrintUsage()
+{
+ printf("rosautotest - ReactOS Automatic Testing Utility\n");
+ printf("Usage: rosautotest [options] [module] [test]\n");
+ printf(" options:\n");
+ printf(" /? - Shows this help\n");
+ printf(" /s - Shut down the system after finishing the tests\n");
+ printf(" /w - Submit the results to the webservice\n");
+ printf(" Requires a \"rosautotest.ini\" with valid login
data.\n");
+ printf("\n");
+ printf(" module:\n");
+ printf(" The module to be tested (i.e. \"advapi32\")\n");
+ printf(" If this parameter is specified without any test
parameter,\n");
+ printf(" all tests of the specified module are run.\n");
+ printf("\n");
+ printf(" test:\n");
+ printf(" The test to be run. Needs to be a test of the specified
module.\n");
+}
+
+/**
+ * Main entry point
+ */
+int
+wmain(int argc, wchar_t* argv[])
+{
+ int Result = 0;
+ UINT i;
+
+ hProcessHeap = GetProcessHeap();
+
+ /* Parse the command line arguments */
+ for(i = 1; i < (UINT)argc; i++)
+ {
+ if(argv[i][0] == '-' || argv[i][0] == '/')
+ {
+ switch(argv[i][1])
+ {
+ case 's':
+ AppOptions.Shutdown = TRUE;
+ break;
+
+ case 'w':
+ AppOptions.Submit = TRUE;
+ break;
+
+ default:
+ Result = 1;
+ /* Fall through */
+
+ case '?':
+ IntPrintUsage();
+ goto End;
+ }
+ }
+ else
+ {
+ size_t Length;
+
+ /* Which parameter is this? */
+ if(!AppOptions.Module)
+ {
+ /* Copy the parameter */
+ Length = (wcslen(argv[i]) + 1) * sizeof(WCHAR);
+ AppOptions.Module = HeapAlloc(hProcessHeap, 0, Length);
+ memcpy(AppOptions.Module, argv[i], Length);
+ }
+ else if(!AppOptions.Test)
+ {
+ /* Copy the parameter converted to ASCII */
+ Length = WideCharToMultiByte(CP_ACP, 0, argv[i], -1, NULL, 0, NULL,
NULL);
+ AppOptions.Test = HeapAlloc(hProcessHeap, 0, Length);
+ WideCharToMultiByte(CP_ACP, 0, argv[i], -1, AppOptions.Test, Length,
NULL, NULL);
+ }
+ else
+ {
+ Result = 1;
+ IntPrintUsage();
+ goto End;
+ }
+ }
+ }
+
+ if(!IntGetConfigurationValues() || !IntGetBuildAndPlatform() || !RunWineTests())
+ {
+ Result = 1;
+ goto End;
+ }
+
+ /* For sysreg */
+ OutputDebugStringA("SYSREG_CHECKPOINT:THIRDBOOT_COMPLETE\n");
+
+End:
+ /* Cleanup */
+ if(AppOptions.Module)
+ HeapFree(hProcessHeap, 0, AppOptions.Module);
+
+ if(AppOptions.Test)
+ HeapFree(hProcessHeap, 0, AppOptions.Test);
+
+ if(AuthenticationRequestString)
+ HeapFree(hProcessHeap, 0, AuthenticationRequestString);
+
+ if(SystemInfoRequestString)
+ HeapFree(hProcessHeap, 0, SystemInfoRequestString);
+
+ /* Shut down the system if requested */
+ if(AppOptions.Shutdown && !ShutdownSystem())
+ Result = 1;
+
+ return Result;
+}
Propchange: trunk/rostests/rosautotest/main.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/precomp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/precomp.h?rev…
==============================================================================
--- trunk/rostests/rosautotest/precomp.h (added)
+++ trunk/rostests/rosautotest/precomp.h [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,81 @@
+/* Includes */
+#include <stdio.h>
+
+#include <windows.h>
+#include <reason.h>
+#include <wininet.h>
+
+#include <reactos/buildno.h>
+
+/* Defines */
+#define BUFFER_BLOCKSIZE 2048
+#define BUILDNO_LENGTH 10
+#define PLATFORM_LENGTH 25
+#define SERVER_HOSTNAME L"localhost"
+#define SERVER_FILE L"testman/webservice/"
+
+/* Enums */
+typedef enum _TESTTYPES
+{
+ WineTest
+}
+TESTTYPES;
+
+/* Structs */
+typedef struct _APP_OPTIONS
+{
+ BOOL Shutdown;
+ BOOL Submit;
+ PWSTR Module;
+ PCHAR Test;
+}
+APP_OPTIONS, *PAPP_OPTIONS;
+
+typedef struct _WINE_GETSUITEID_DATA
+{
+ PCHAR Module;
+ PCHAR Test;
+}
+WINE_GETSUITEID_DATA, *PWINE_GETSUITEID_DATA;
+
+typedef struct _GENERAL_SUBMIT_DATA
+{
+ PCHAR TestID;
+ PCHAR SuiteID;
+}
+GENERAL_SUBMIT_DATA, *PGENERAL_SUBMIT_DATA;
+
+typedef struct _WINE_SUBMIT_DATA
+{
+ GENERAL_SUBMIT_DATA General;
+ PCHAR Log;
+}
+WINE_SUBMIT_DATA, *PWINE_SUBMIT_DATA;
+
+typedef struct _GENERAL_FINISH_DATA
+{
+ PCHAR TestID;
+}
+GENERAL_FINISH_DATA, *PGENERAL_FINISH_DATA;
+
+/* main.c */
+extern APP_OPTIONS AppOptions;
+extern HANDLE hProcessHeap;
+extern PCHAR AuthenticationRequestString;
+extern PCHAR SystemInfoRequestString;
+
+/* shutdown.c */
+BOOL ShutdownSystem();
+
+/* tools.c */
+VOID EscapeString(PCHAR Output, PCHAR Input);
+VOID StringOut(PCHAR String);
+
+/* webservice.c */
+PCHAR GetTestID(TESTTYPES TestType);
+PCHAR GetSuiteID(TESTTYPES TestType, const PVOID TestData);
+BOOL Submit(TESTTYPES TestType, const PVOID TestData);
+BOOL Finish(TESTTYPES TestType, const PVOID TestData);
+
+/* winetests.c */
+BOOL RunWineTests();
Propchange: trunk/rostests/rosautotest/precomp.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/rosautotest.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/rosautotest.r…
==============================================================================
--- trunk/rostests/rosautotest/rosautotest.rbuild (added)
+++ trunk/rostests/rosautotest/rosautotest.rbuild [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="rosautotest" type="win32cui"
installbase="system32" installname="rosautotest.exe"
unicode="yes">
+ <include base="rosautotest">.</include>
+ <library>advapi32</library>
+ <library>kernel32</library>
+ <library>user32</library>
+ <library>wininet</library>
+ <file>main.c</file>
+ <file>shutdown.c</file>
+ <file>tools.c</file>
+ <file>webservice.c</file>
+ <file>winetests.c</file>
+ <pch>precomp.h</pch>
+</module>
Propchange: trunk/rostests/rosautotest/rosautotest.rbuild
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/shutdown.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/shutdown.c?re…
==============================================================================
--- trunk/rostests/rosautotest/shutdown.c (added)
+++ trunk/rostests/rosautotest/shutdown.c [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,52 @@
+/*
+ * PROJECT: ReactOS Automatic Testing Utility
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Helper function for shutting down the system
+ * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * Shuts down the system.
+ *
+ * @return
+ * TRUE if everything went well, FALSE if there was a problem while trying to shut down
the system.
+ */
+BOOL ShutdownSystem()
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES Privileges;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+ {
+ StringOut("OpenProcessToken failed\n");
+ return FALSE;
+ }
+
+ /* Get the LUID for the Shutdown privilege */
+ if (!LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME,
&Privileges.Privileges[0].Luid))
+ {
+ StringOut("LookupPrivilegeValue failed\n");
+ return FALSE;
+ }
+
+ /* Assign the Shutdown privilege to our process */
+ Privileges.PrivilegeCount = 1;
+ Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL))
+ {
+ StringOut("AdjustTokenPrivileges failed\n");
+ return FALSE;
+ }
+
+ /* Finally shut down the system */
+ if(!ExitWindowsEx(EWX_POWEROFF, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER |
SHTDN_REASON_FLAG_PLANNED))
+ {
+ StringOut("ExitWindowsEx failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
Propchange: trunk/rostests/rosautotest/shutdown.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/tools.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/tools.c?rev=3…
==============================================================================
--- trunk/rostests/rosautotest/tools.c (added)
+++ trunk/rostests/rosautotest/tools.c [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,57 @@
+/*
+ * PROJECT: ReactOS Automatic Testing Utility
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Various helper functions
+ * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * Escapes a string according to RFC 1738.
+ * Required for passing parameters to the web service.
+ *
+ * @param Output
+ * Pointer to a CHAR array, which will receive the escaped string.
+ * The output buffer must be large enough to hold the full escaped string. You're on
the safe side
+ * if you make the output buffer three times as large as the input buffer.
+ *
+ * @param Input
+ * Pointer to a CHAR array, which contains the input buffer to escape.
+ */
+VOID
+EscapeString(PCHAR Output, PCHAR Input)
+{
+ const CHAR HexCharacters[] = "0123456789ABCDEF";
+
+ do
+ {
+
if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~",
*Input) )
+ {
+ /* It's a character we don't need to escape, just add it to the
output string */
+ *Output++ = *Input;
+ }
+ else
+ {
+ /* We need to escape this character */
+ *Output++ = '%';
+ *Output++ = HexCharacters[((UCHAR)*Input >> 4) % 16];
+ *Output++ = HexCharacters[(UCHAR)*Input % 16];
+ }
+ } while(*++Input);
+
+ *Output = 0;
+}
+
+/**
+ * Outputs a string through the standard output and the debug output.
+ *
+ * @param String
+ * The string to output
+ */
+VOID
+StringOut(PCHAR String)
+{
+ printf(String);
+ OutputDebugStringA(String);
+}
Propchange: trunk/rostests/rosautotest/tools.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/webservice.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/webservice.c?…
==============================================================================
--- trunk/rostests/rosautotest/webservice.c (added)
+++ trunk/rostests/rosautotest/webservice.c [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,417 @@
+/*
+ * PROJECT: ReactOS Automatic Testing Utility
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Submitting test results to the Web Service
+ * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+static const CHAR ActionProp[] = "action=";
+static const CHAR TestIDProp[] = "&testid=";
+static const CHAR TestTypeProp[] = "&testtype=";
+static const CHAR WineTestType[] = "wine";
+
+/**
+ * Sends data to the ReactOS Web Test Manager web service.
+ *
+ * @param Data
+ * Pointer to a CHAR pointer, which contains the data to submit as HTTP POST data.
+ * The buffer behind this pointer had to be allocated with HeapAlloc.
+ * Returns the data received by the web service after the call.
+ *
+ * @param DataLength
+ * Pointer to a DWORD, which contains the length of the data to submit (in bytes).
+ * Returns the length of the data received by the web service after the call (in bytes).
+ *
+ * @return
+ * TRUE if everything went well, FALSE if an error occured while submitting the request.
+ * In case of an error, the function will output an appropriate error message through
StringOut.
+ */
+static BOOL
+IntDoRequest(char** Data, PDWORD DataLength)
+{
+ const WCHAR Headers[] = L"Content-Type:
application/x-www-form-urlencoded";
+
+ HINTERNET hHTTP;
+ HINTERNET hHTTPRequest;
+ HINTERNET hInet;
+
+ /* Establish an internet connection to the "testman" server */
+ hInet = InternetOpenW(L"rosautotest", INTERNET_OPEN_TYPE_PRECONFIG, NULL,
NULL, 0);
+
+ if(!hInet)
+ {
+ StringOut("InternetOpenW failed\n");
+ return FALSE;
+ }
+
+ hHTTP = InternetConnectW(hInet, SERVER_HOSTNAME, INTERNET_DEFAULT_HTTP_PORT, NULL,
NULL, INTERNET_SERVICE_HTTP, 0, 0);
+
+ if(!hHTTP)
+ {
+ StringOut("InternetConnectW failed\n");
+ return FALSE;
+ }
+
+ /* Post our test results to the web service */
+ hHTTPRequest = HttpOpenRequestW(hHTTP, L"POST", SERVER_FILE, NULL, NULL,
NULL, INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
+
+ if(!hHTTPRequest)
+ {
+ StringOut("HttpOpenRequestW failed\n");
+ return FALSE;
+ }
+
+ if(!HttpSendRequestW(hHTTPRequest, Headers, wcslen(Headers), *Data, *DataLength))
+ {
+ StringOut("HttpSendRequestW failed\n");
+ return FALSE;
+ }
+
+ HeapFree(hProcessHeap, 0, *Data);
+
+ /* Get the response */
+ if(!InternetQueryDataAvailable(hHTTPRequest, DataLength, 0, 0))
+ {
+ StringOut("InternetQueryDataAvailable failed\n");
+ return FALSE;
+ }
+
+ *Data = HeapAlloc(hProcessHeap, 0, *DataLength + 1);
+
+ if(!InternetReadFile(hHTTPRequest, *Data, *DataLength, DataLength))
+ {
+ StringOut("InternetReadFile failed\n");
+ return FALSE;
+ }
+
+ (*Data)[*DataLength] = 0;
+
+ InternetCloseHandle(hHTTPRequest);
+ InternetCloseHandle(hHTTP);
+ InternetCloseHandle(hInet);
+
+ return TRUE;
+}
+
+/**
+ * Determines whether a string contains entirely numeric values.
+ *
+ * @param Input
+ * The string to check.
+ *
+ * @return
+ * TRUE if the string is entirely numeric, FALSE otherwise.
+ */
+static BOOL
+IsNumber(PCHAR Input)
+{
+ do
+ {
+ if(!isdigit(*Input))
+ return FALSE;
+
+ ++Input;
+ }
+ while(*Input);
+
+ return TRUE;
+}
+
+/**
+ * Requests a Test ID from the web service for our test run.
+ *
+ * @param TestType
+ * Value from the TESTTYPES enum indicating the type of test we are about to submit.
+ *
+ * @return
+ * Returns the Test ID as a CHAR array if successful or NULL otherwise.
+ */
+PCHAR
+GetTestID(TESTTYPES TestType)
+{
+ const CHAR GetTestIDAction[] = "gettestid";
+
+ DWORD DataLength;
+ PCHAR Data;
+
+ /* Build the full request string */
+ DataLength = sizeof(ActionProp) - 1 + sizeof(GetTestIDAction) - 1;
+ DataLength += strlen(AuthenticationRequestString) + strlen(SystemInfoRequestString);
+ DataLength += sizeof(TestTypeProp) - 1;
+
+ switch(TestType)
+ {
+ case WineTest:
+ DataLength += sizeof(WineTestType) - 1;
+ break;
+ }
+
+ Data = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+ strcpy(Data, ActionProp);
+ strcat(Data, GetTestIDAction);
+ strcat(Data, AuthenticationRequestString);
+ strcat(Data, SystemInfoRequestString);
+ strcat(Data, TestTypeProp);
+
+ switch(TestType)
+ {
+ case WineTest:
+ strcat(Data, WineTestType);
+ break;
+ }
+
+ if(!IntDoRequest(&Data, &DataLength))
+ return NULL;
+
+ /* Verify that this is really a number */
+ if(!IsNumber(Data))
+ {
+ StringOut("Expected Test ID, but received:\n");
+ StringOut(Data);
+ HeapFree(hProcessHeap, 0, Data);
+ return NULL;
+ }
+
+ return Data;
+}
+
+/**
+ * Requests a Suite ID from the web service for our module/test combination.
+ *
+ * @param TestType
+ * Value from the TESTTYPES enum indicating the type of test we are about to submit.
+ *
+ * @param TestData
+ * Pointer to a *_GETSUITEID_DATA structure appropriate for our selected test type.
+ * Contains other input information for this request.
+ *
+ * @return
+ * Returns the Suite ID as a CHAR array if successful or NULL otherwise.
+ */
+PCHAR
+GetSuiteID(TESTTYPES TestType, const PVOID TestData)
+{
+ const CHAR GetSuiteIDAction[] = "getsuiteid";
+ const CHAR ModuleProp[] = "&module=";
+ const CHAR TestProp[] = "&test=";
+
+ DWORD DataLength;
+ PCHAR Data;
+ PWINE_GETSUITEID_DATA WineData;
+
+ DataLength = sizeof(ActionProp) - 1 + sizeof(GetSuiteIDAction) - 1;
+ DataLength += strlen(AuthenticationRequestString);
+ DataLength += sizeof(TestTypeProp) - 1;
+
+ switch(TestType)
+ {
+ case WineTest:
+ DataLength += sizeof(WineTestType) - 1;
+
+ WineData = (PWINE_GETSUITEID_DATA)TestData;
+ DataLength += sizeof(ModuleProp) - 1;
+ DataLength += strlen(WineData->Module);
+ DataLength += sizeof(TestProp) - 1;
+ DataLength += strlen(WineData->Test);
+
+ break;
+ }
+
+ Data = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+ strcpy(Data, ActionProp);
+ strcat(Data, GetSuiteIDAction);
+ strcat(Data, AuthenticationRequestString);
+ strcat(Data, TestTypeProp);
+
+ switch(TestType)
+ {
+ case WineTest:
+ strcat(Data, WineTestType);
+
+ /* Stupid GCC and MSVC: WineData is already initialized above, still it's
reported as a potentially uninitialized variable :-( */
+ WineData = (PWINE_GETSUITEID_DATA)TestData;
+ strcat(Data, ModuleProp);
+ strcat(Data, WineData->Module);
+ strcat(Data, TestProp);
+ strcat(Data, WineData->Test);
+
+ break;
+ }
+
+ if(!IntDoRequest(&Data, &DataLength))
+ return NULL;
+
+ /* Verify that this is really a number */
+ if(!IsNumber(Data))
+ {
+ StringOut("Expected Suite ID, but received:\n");
+ StringOut(Data);
+ HeapFree(hProcessHeap, 0, Data);
+ return NULL;
+ }
+
+ return Data;
+}
+
+/**
+ * Submits the result of one test call to the web service.
+ *
+ * @param TestType
+ * Value from the TESTTYPES enum indicating the type of test we are about to submit.
+ *
+ * @param TestData
+ * Pointer to a *_SUBMIT_DATA structure appropriate for our selected test type.
+ * Contains other input information for this request.
+ *
+ * @return
+ * TRUE if everything went well, FALSE otherwise.
+ */
+BOOL
+Submit(TESTTYPES TestType, const PVOID TestData)
+{
+ const CHAR SubmitAction[] = "submit";
+ const CHAR SuiteIDProp[] = "&suiteid=";
+ const CHAR LogProp[] = "&log=";
+
+ DWORD DataLength;
+ PCHAR Data;
+ PCHAR pData;
+ PGENERAL_SUBMIT_DATA GeneralData;
+ PWINE_SUBMIT_DATA WineData;
+
+ /* Compute the full length of the POST data */
+ DataLength = sizeof(ActionProp) - 1 + sizeof(SubmitAction) - 1;
+ DataLength += strlen(AuthenticationRequestString);
+
+ GeneralData = (PGENERAL_SUBMIT_DATA)TestData;
+ DataLength += sizeof(TestIDProp) - 1;
+ DataLength += strlen(GeneralData->TestID);
+ DataLength += sizeof(SuiteIDProp) - 1;
+ DataLength += strlen(GeneralData->SuiteID);
+
+ /* The rest of the POST data depends on the test type */
+ DataLength += sizeof(TestTypeProp) - 1;
+
+ switch(TestType)
+ {
+ case WineTest:
+ DataLength += sizeof(WineTestType) - 1;
+
+ WineData = (PWINE_SUBMIT_DATA)TestData;
+ DataLength += sizeof(LogProp) - 1;
+ DataLength += 3 * strlen(WineData->Log);
+
+ break;
+ }
+
+ /* Now collect all the POST data */
+ Data = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+ strcpy(Data, ActionProp);
+ strcat(Data, SubmitAction);
+ strcat(Data, AuthenticationRequestString);
+
+ strcat(Data, TestIDProp);
+ strcat(Data, GeneralData->TestID);
+ strcat(Data, SuiteIDProp);
+ strcat(Data, GeneralData->SuiteID);
+
+ strcat(Data, TestTypeProp);
+
+ switch(TestType)
+ {
+ case WineTest:
+ strcat(Data, WineTestType);
+
+ /* Stupid GCC and MSVC: WineData is already initialized above, still it's
reported as a potentially uninitialized variable :-( */
+ WineData = (PWINE_SUBMIT_DATA)TestData;
+
+ strcat(Data, LogProp);
+ pData = Data + strlen(Data);
+ EscapeString(pData, WineData->Log);
+
+ break;
+ }
+
+ /* DataLength still contains the maximum length of the buffer, but not the actual
data length we need for the request.
+ Determine that one now. */
+ DataLength = strlen(Data);
+
+ /* Send all the stuff */
+ if(!IntDoRequest(&Data, &DataLength))
+ return FALSE;
+
+ /* Output the response */
+ StringOut("The server responded:\n");
+ StringOut(Data);
+ StringOut("\n");
+
+ if(!strcmp(Data, "OK"))
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Finishes a test run for the web service.
+ *
+ * @param TestType
+ * Value from the TESTTYPES enum indicating the type of test we are about to submit.
+ *
+ * @param TestData
+ * Pointer to a *_FINISH_DATA structure appropriate for our selected test type.
+ * Contains other input information for this request.
+ *
+ * @return
+ * TRUE if everything went well, FALSE otherwise.
+ */
+BOOL
+Finish(TESTTYPES TestType, const PVOID TestData)
+{
+ const CHAR FinishAction[] = "finish";
+
+ DWORD DataLength;
+ PCHAR Data;
+ PGENERAL_FINISH_DATA GeneralData;
+
+ /* Build the full request string */
+ DataLength = sizeof(ActionProp) - 1 + sizeof(FinishAction) - 1;
+ DataLength += strlen(AuthenticationRequestString);
+
+ GeneralData = (PGENERAL_FINISH_DATA)TestData;
+ DataLength += sizeof(TestIDProp) - 1;
+ DataLength += strlen(GeneralData->TestID);
+
+ DataLength += sizeof(TestTypeProp) - 1;
+
+ switch(TestType)
+ {
+ case WineTest:
+ DataLength += sizeof(WineTestType) - 1;
+ break;
+ }
+
+ Data = HeapAlloc(hProcessHeap, 0, DataLength + 1);
+ strcpy(Data, ActionProp);
+ strcat(Data, FinishAction);
+ strcat(Data, AuthenticationRequestString);
+ strcat(Data, TestIDProp);
+ strcat(Data, GeneralData->TestID);
+ strcat(Data, TestTypeProp);
+
+ switch(TestType)
+ {
+ case WineTest:
+ strcat(Data, WineTestType);
+ break;
+ }
+
+ if(!IntDoRequest(&Data, &DataLength))
+ return FALSE;
+
+ if(!strcmp(Data, "OK"))
+ return TRUE;
+
+ return FALSE;
+}
Propchange: trunk/rostests/rosautotest/webservice.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/rosautotest/winetests.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/rosautotest/winetests.c?r…
==============================================================================
--- trunk/rostests/rosautotest/winetests.c (added)
+++ trunk/rostests/rosautotest/winetests.c [iso-8859-1] Mon Jan 5 06:41:34 2009
@@ -1,0 +1,374 @@
+/*
+ * PROJECT: ReactOS Automatic Testing Utility
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Running Wine Tests automatically
+ * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * Runs a specific test for a specific module.
+ * If we get results for a test, they are submitted to the Web Service.
+ *
+ * @param CommandLine
+ * Command line to run (should be the path to a module's test suite together with a
parameter for the specified test)
+ *
+ * @param hReadPipe
+ * Handle to the Read Pipe set up in RunWineTests.
+ *
+ * @param StartupInfo
+ * Pointer to the StartupInfo structure set up in RunWineTests.
+ *
+ * @param GetSuiteIDData
+ * Pointer to the GetSuiteIDData structure set up in IntRunModuleTests.
+ *
+ * @param SubmitData
+ * Pointer to the SubmitData structure set up in RunWineTests.
+ *
+ * @return
+ * TRUE if everything went well, FALSE otherwise.
+ */
+static BOOL
+IntRunTest(PWSTR CommandLine, HANDLE hReadPipe, LPSTARTUPINFOW StartupInfo,
PWINE_GETSUITEID_DATA GetSuiteIDData, PWINE_SUBMIT_DATA SubmitData)
+{
+ BOOL BreakLoop = FALSE;
+ DWORD BytesAvailable;
+ DWORD LogAvailable = 0;
+ DWORD LogLength = 0;
+ DWORD LogPosition = 0;
+ DWORD Temp;
+ PCHAR Buffer;
+ PROCESS_INFORMATION ProcessInfo;
+
+ if(AppOptions.Submit)
+ {
+ /* Allocate one block for the log */
+ SubmitData->Log = HeapAlloc(hProcessHeap, 0, BUFFER_BLOCKSIZE);
+ LogAvailable = BUFFER_BLOCKSIZE;
+ LogLength = BUFFER_BLOCKSIZE;
+ }
+
+ /* Execute the test */
+ StringOut("Running Wine Test, Module: ");
+ StringOut(GetSuiteIDData->Module);
+ StringOut(", Test: ");
+ StringOut(GetSuiteIDData->Test);
+ StringOut("\n");
+
+ if(!CreateProcessW(NULL, CommandLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL,
NULL, StartupInfo, &ProcessInfo))
+ {
+ StringOut("CreateProcessW for running the test failed\n");
+ return FALSE;
+ }
+
+ /* Receive all the data from the pipe */
+ do
+ {
+ /* When the application finished, make sure that we peek the pipe one more time,
so that we get all data.
+ If the following condition would be the while() condition, we might hit a race
condition:
+ - We check for data with PeekNamedPipe -> no data available
+ - The application outputs its data and finishes
+ - WaitForSingleObject reports that the application has finished and we
break the loop without receiving any data
+ */
+ if(WaitForSingleObject(ProcessInfo.hProcess, 0) == WAIT_OBJECT_0)
+ BreakLoop = TRUE;
+
+ if(!PeekNamedPipe(hReadPipe, NULL, 0, NULL, &BytesAvailable, NULL))
+ {
+ StringOut("PeekNamedPipe failed for the test run\n");
+ return FALSE;
+ }
+
+ if(BytesAvailable)
+ {
+ /* There is data, so get it and output it */
+ Buffer = HeapAlloc(hProcessHeap, 0, BytesAvailable + 1);
+
+ if(!ReadFile(hReadPipe, Buffer, BytesAvailable, &Temp, NULL))
+ {
+ StringOut("ReadFile failed for the test run\n");
+ return FALSE;
+ }
+
+ /* Output all test output through StringOut, even while the test is still
running */
+ Buffer[BytesAvailable] = 0;
+ StringOut(Buffer);
+
+ if(AppOptions.Submit)
+ {
+ /* Also store it in the buffer */
+ if(BytesAvailable > LogAvailable)
+ {
+ /* Allocate enough new blocks to hold all available data */
+ Temp = ((BytesAvailable - LogAvailable) / BUFFER_BLOCKSIZE + 1) *
BUFFER_BLOCKSIZE;
+ LogAvailable += Temp;
+ LogLength += Temp;
+ SubmitData->Log = HeapReAlloc(hProcessHeap, 0, SubmitData->Log,
LogLength);
+ }
+
+ memcpy(&SubmitData->Log[LogPosition], Buffer, BytesAvailable);
+ LogPosition += BytesAvailable;
+ LogAvailable -= BytesAvailable;
+ }
+
+ HeapFree(hProcessHeap, 0, Buffer);
+ }
+ }
+ while(!BreakLoop);
+
+ if(AppOptions.Submit)
+ {
+ SubmitData->Log[LogLength - LogAvailable] = 0;
+
+ /* If we got any output, submit it to the web service */
+ if(*SubmitData->Log)
+ {
+ /* We don't want to waste any ID's, so only request them if we can be
sure that we have results to submit. */
+
+ /* Get a Test ID if we don't have one yet */
+ if(!SubmitData->General.TestID)
+ {
+ SubmitData->General.TestID = GetTestID(WineTest);
+
+ if(!SubmitData->General.TestID)
+ return FALSE;
+ }
+
+ /* Get a Suite ID for this combination */
+ SubmitData->General.SuiteID = GetSuiteID(WineTest, GetSuiteIDData);
+
+ if(!SubmitData->General.SuiteID)
+ return FALSE;
+
+ /* Submit the stuff */
+ Submit(WineTest, SubmitData);
+
+ /* Cleanup */
+ HeapFree(hProcessHeap, 0, SubmitData->General.SuiteID);
+ }
+
+ /* Cleanup */
+ HeapFree(hProcessHeap, 0, SubmitData->Log);
+ }
+
+ StringOut("\n\n");
+
+ return TRUE;
+}
+
+/**
+ * Runs the desired tests for a specified module.
+ *
+ * @param File
+ * The file name of the module's test suite.
+ *
+ * @param FilePath
+ * The full path to the file of the module's test suite.
+ *
+ * @param hReadPipe
+ * Handle to the Read Pipe set up in RunWineTests.
+ *
+ * @param StartupInfo
+ * Pointer to the StartupInfo structure set up in RunWineTests.
+ *
+ * @param SubmitData
+ * Pointer to the SubmitData structure set up in RunWineTests.
+ *
+ * @return
+ * TRUE if everything went well, FALSE otherwise.
+ */
+static BOOL
+IntRunModuleTests(PWSTR File, PWSTR FilePath, HANDLE hReadPipe, LPSTARTUPINFOW
StartupInfo, PWINE_SUBMIT_DATA SubmitData)
+{
+ DWORD BytesAvailable;
+ DWORD Length;
+ DWORD Temp;
+ PCHAR Buffer;
+ PCHAR pStart;
+ PCHAR pEnd;
+ PROCESS_INFORMATION ProcessInfo;
+ size_t FilePosition;
+ WINE_GETSUITEID_DATA GetSuiteIDData;
+
+ /* Build the full command line */
+ FilePosition = wcslen(FilePath);
+ FilePath[FilePosition++] = ' ';
+ FilePath[FilePosition] = 0;
+ wcscat(FilePath, L"--list");
+
+ /* Store the tested module name */
+ Length = wcschr(File, L'_') - File;
+ GetSuiteIDData.Module = HeapAlloc(hProcessHeap, 0, Length + 1);
+ WideCharToMultiByte(CP_ACP, 0, File, Length, GetSuiteIDData.Module, Length, NULL,
NULL);
+ GetSuiteIDData.Module[Length] = 0;
+
+ /* Start the process for getting all available tests */
+ if(!CreateProcessW(NULL, FilePath, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL,
NULL, StartupInfo, &ProcessInfo))
+ {
+ StringOut("CreateProcessW for getting the available tests failed\n");
+ return FALSE;
+ }
+
+ /* Wait till this process ended */
+ if(WaitForSingleObject(ProcessInfo.hProcess, INFINITE) == WAIT_FAILED)
+ {
+ StringOut("WaitForSingleObject failed for the test list\n");
+ return FALSE;
+ }
+
+ /* Read the output data into a buffer */
+ if(!PeekNamedPipe(hReadPipe, NULL, 0, NULL, &BytesAvailable, NULL))
+ {
+ StringOut("PeekNamedPipe failed for the test list\n");
+ return FALSE;
+ }
+
+ Buffer = HeapAlloc(hProcessHeap, 0, BytesAvailable);
+
+ if(!ReadFile(hReadPipe, Buffer, BytesAvailable, &Temp, NULL))
+ {
+ StringOut("ReadFile failed\n");
+ return FALSE;
+ }
+
+ /* Jump to the first available test */
+ pStart = strchr(Buffer, '\n');
+ pStart += 5;
+
+ while(pStart < (Buffer + BytesAvailable))
+ {
+ /* Get start and end of this test name */
+ pEnd = pStart;
+
+ while(*pEnd != '\r')
+ ++pEnd;
+
+ /* Store the test name */
+ GetSuiteIDData.Test = HeapAlloc(hProcessHeap, 0, pEnd - pStart + 1);
+ memcpy(GetSuiteIDData.Test, pStart, pEnd - pStart);
+ GetSuiteIDData.Test[pEnd - pStart] = 0;
+
+ /* If the user gave us a test to run, we check whether the module's test
suite really provides this test. */
+ if(!AppOptions.Test || (AppOptions.Test && !strcmp(AppOptions.Test,
GetSuiteIDData.Test)))
+ {
+ /* Build the command line for this test */
+ Length = MultiByteToWideChar(CP_ACP, 0, pStart, pEnd - pStart, NULL, 0);
+ MultiByteToWideChar(CP_ACP, 0, pStart, pEnd - pStart,
&FilePath[FilePosition], Length * sizeof(WCHAR));
+ FilePath[FilePosition + Length] = 0;
+
+ if(!IntRunTest(FilePath, hReadPipe, StartupInfo, &GetSuiteIDData,
SubmitData))
+ return FALSE;
+ }
+
+ /* Cleanup */
+ HeapFree(hProcessHeap, 0, GetSuiteIDData.Test);
+
+ /* Move to the next test */
+ pStart = pEnd + 6;
+ }
+
+ /* Cleanup */
+ HeapFree(hProcessHeap, 0, GetSuiteIDData.Module);
+ HeapFree(hProcessHeap, 0, Buffer);
+
+ return TRUE;
+}
+
+/**
+ * Runs the Wine tests according to the options specified by the parameters.
+ *
+ * @return
+ * TRUE if everything went well, FALSE otherwise.
+ */
+BOOL
+RunWineTests()
+{
+ GENERAL_FINISH_DATA FinishData;
+ HANDLE hFind;
+ HANDLE hReadPipe;
+ HANDLE hWritePipe;
+ SECURITY_ATTRIBUTES SecurityAttributes;
+ STARTUPINFOW StartupInfo = {0};
+ size_t PathPosition;
+ WCHAR FilePath[MAX_PATH];
+ WIN32_FIND_DATAW fd;
+ WINE_SUBMIT_DATA SubmitData = { {0} };
+
+ /* Create a pipe for getting the output of the tests */
+ SecurityAttributes.nLength = sizeof(SecurityAttributes);
+ SecurityAttributes.bInheritHandle = TRUE;
+ SecurityAttributes.lpSecurityDescriptor = NULL;
+
+ if(!CreatePipe(&hReadPipe, &hWritePipe, &SecurityAttributes, 0))
+ {
+ StringOut("CreatePipe failed\n");
+ return FALSE;
+ }
+
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+ StartupInfo.hStdOutput = hWritePipe;
+
+ /* Build the path for finding the tests */
+ if(GetWindowsDirectoryW(FilePath, MAX_PATH) > MAX_PATH - 60)
+ {
+ StringOut("Windows directory path is too long\n");
+ return FALSE;
+ }
+
+ wcscat(FilePath, L"\\bin\\");
+ PathPosition = wcslen(FilePath);
+
+ if(AppOptions.Module)
+ {
+ /* Find a test belonging to this module */
+ wcscat(FilePath, AppOptions.Module);
+ wcscat(FilePath, L"_*.exe");
+ }
+ else
+ {
+ /* Find all tests */
+ wcscat(FilePath, L"*.exe");
+ }
+
+ hFind = FindFirstFileW(FilePath, &fd);
+
+ if(hFind == INVALID_HANDLE_VALUE)
+ {
+ StringOut("FindFirstFileW failed\n");
+ return FALSE;
+ }
+
+ /* Run the tests */
+ do
+ {
+ /* Build the full path to the test suite */
+ wcscpy(&FilePath[PathPosition], fd.cFileName);
+
+ /* Run it */
+ if(!IntRunModuleTests(fd.cFileName, FilePath, hReadPipe, &StartupInfo,
&SubmitData))
+ return FALSE;
+ }
+ while(FindNextFileW(hFind, &fd));
+
+ /* Cleanup */
+ FindClose(hFind);
+
+ if(AppOptions.Submit && SubmitData.General.TestID)
+ {
+ /* We're done with the tests, so close this test run */
+ FinishData.TestID = SubmitData.General.TestID;
+
+ if(!Finish(WineTest, &FinishData))
+ return FALSE;
+
+ /* Cleanup */
+ HeapFree(hProcessHeap, 0, FinishData.TestID);
+ }
+
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+
+ return TRUE;
+}
Propchange: trunk/rostests/rosautotest/winetests.c
------------------------------------------------------------------------------
svn:eol-style = native