mirror of
https://github.com/reactos/reactos.git
synced 2024-09-09 20:30:04 +00:00
![Colin Finck](/assets/img/avatar_default.png)
This can be useful for giving more information about the used build for the test. The necessary changes in testman will follow later :-P svn path=/trunk/; revision=39698
465 lines
12 KiB
C
465 lines
12 KiB
C
/*
|
|
* 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@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";
|
|
|
|
BOOL ReturnValue = FALSE;
|
|
HINTERNET hHTTP = NULL;
|
|
HINTERNET hHTTPRequest = NULL;
|
|
HINTERNET hInet = NULL;
|
|
|
|
/* 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");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hHTTP = InternetConnectW(hInet, SERVER_HOSTNAME, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
|
|
|
|
if(!hHTTP)
|
|
{
|
|
StringOut("InternetConnectW failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
/* 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");
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(!HttpSendRequestW(hHTTPRequest, Headers, wcslen(Headers), *Data, *DataLength))
|
|
{
|
|
StringOut("HttpSendRequestW failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
HeapFree(hProcessHeap, 0, *Data);
|
|
*Data = NULL;
|
|
|
|
/* Get the response */
|
|
if(!InternetQueryDataAvailable(hHTTPRequest, DataLength, 0, 0))
|
|
{
|
|
StringOut("InternetQueryDataAvailable failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
*Data = HeapAlloc(hProcessHeap, 0, *DataLength + 1);
|
|
|
|
if(!InternetReadFile(hHTTPRequest, *Data, *DataLength, DataLength))
|
|
{
|
|
StringOut("InternetReadFile failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
(*Data)[*DataLength] = 0;
|
|
ReturnValue = TRUE;
|
|
|
|
Cleanup:
|
|
if(hHTTPRequest)
|
|
InternetCloseHandle(hHTTPRequest);
|
|
|
|
if(hHTTP)
|
|
InternetCloseHandle(hHTTP);
|
|
|
|
if(hInet)
|
|
InternetCloseHandle(hInet);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* The caller needs to HeapFree the returned pointer in case of success.
|
|
*/
|
|
PCHAR
|
|
GetTestID(TESTTYPES TestType)
|
|
{
|
|
const CHAR GetTestIDAction[] = "gettestid";
|
|
const CHAR CommentProp[] = "&comment=";
|
|
|
|
DWORD DataLength;
|
|
PCHAR Data;
|
|
PCHAR ReturnValue = NULL;
|
|
|
|
/* Build the full request string */
|
|
DataLength = sizeof(ActionProp) - 1 + sizeof(GetTestIDAction) - 1;
|
|
DataLength += strlen(AuthenticationRequestString) + strlen(SystemInfoRequestString);
|
|
|
|
if(AppOptions.Comment)
|
|
DataLength += sizeof(CommentProp) - 1 + strlen(AppOptions.Comment);
|
|
|
|
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);
|
|
|
|
if(AppOptions.Comment)
|
|
{
|
|
strcat(Data, CommentProp);
|
|
strcat(Data, AppOptions.Comment);
|
|
}
|
|
|
|
strcat(Data, TestTypeProp);
|
|
|
|
switch(TestType)
|
|
{
|
|
case WineTest:
|
|
strcat(Data, WineTestType);
|
|
break;
|
|
}
|
|
|
|
if(!IntDoRequest(&Data, &DataLength))
|
|
goto Cleanup;
|
|
|
|
/* Verify that this is really a number */
|
|
if(!IsNumber(Data))
|
|
{
|
|
StringOut("Expected Test ID, but received:\n");
|
|
StringOut(Data);
|
|
StringOut("\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
ReturnValue = Data;
|
|
|
|
Cleanup:
|
|
if(Data && ReturnValue != Data)
|
|
HeapFree(hProcessHeap, 0, Data);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* The caller needs to HeapFree the returned pointer in case of success.
|
|
*/
|
|
PCHAR
|
|
GetSuiteID(TESTTYPES TestType, const PVOID TestData)
|
|
{
|
|
const CHAR GetSuiteIDAction[] = "getsuiteid";
|
|
const CHAR ModuleProp[] = "&module=";
|
|
const CHAR TestProp[] = "&test=";
|
|
|
|
DWORD DataLength;
|
|
PCHAR Data;
|
|
PCHAR ReturnValue = NULL;
|
|
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))
|
|
goto Cleanup;
|
|
|
|
/* Verify that this is really a number */
|
|
if(!IsNumber(Data))
|
|
{
|
|
StringOut("Expected Suite ID, but received:\n");
|
|
StringOut(Data);
|
|
StringOut("\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
ReturnValue = Data;
|
|
|
|
Cleanup:
|
|
if(Data && ReturnValue != Data)
|
|
HeapFree(hProcessHeap, 0, Data);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
/**
|
|
* 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=";
|
|
|
|
BOOL ReturnValue = FALSE;
|
|
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))
|
|
goto Cleanup;
|
|
|
|
/* Output the response */
|
|
StringOut("The server responded:\n");
|
|
StringOut(Data);
|
|
StringOut("\n");
|
|
|
|
if(!strcmp(Data, "OK"))
|
|
ReturnValue = TRUE;
|
|
|
|
Cleanup:
|
|
if(Data)
|
|
HeapFree(hProcessHeap, 0, Data);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
/**
|
|
* 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";
|
|
|
|
BOOL ReturnValue = FALSE;
|
|
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))
|
|
goto Cleanup;
|
|
|
|
if(!strcmp(Data, "OK"))
|
|
ReturnValue = TRUE;
|
|
|
|
Cleanup:
|
|
if(Data)
|
|
HeapFree(hProcessHeap, 0, Data);
|
|
|
|
return ReturnValue;
|
|
}
|