1 /* 2 * PROJECT: ReactOS Automatic Testing Utility 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Class implementing the interface to the "testman" Web Service 5 * COPYRIGHT: Copyright 2009-2015 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 static const WCHAR szHostname[] = L"reactos.org"; 11 static const WCHAR szServerFile[] = L"testman/webservice/"; 12 13 /** 14 * Constructs a CWebService object and immediately establishes a connection to the "testman" Web Service. 15 */ 16 CWebService::CWebService() 17 { 18 /* Zero-initialize variables */ 19 m_hHTTP = NULL; 20 m_hHTTPRequest = NULL; 21 m_TestID = NULL; 22 23 /* Establish an internet connection to the "testman" server */ 24 m_hInet = InternetOpenW(L"rosautotest", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 25 26 if(!m_hInet) 27 FATAL("InternetOpenW failed\n"); 28 29 m_hHTTP = InternetConnectW(m_hInet, szHostname, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 30 31 if(!m_hHTTP) 32 FATAL("InternetConnectW failed\n"); 33 } 34 35 /** 36 * Destructs a CWebService object and closes all connections to the Web Service. 37 */ 38 CWebService::~CWebService() 39 { 40 if(m_hInet) 41 InternetCloseHandle(m_hInet); 42 43 if(m_hHTTP) 44 InternetCloseHandle(m_hHTTP); 45 46 if(m_hHTTPRequest) 47 InternetCloseHandle(m_hHTTPRequest); 48 49 if(m_TestID) 50 delete m_TestID; 51 } 52 53 /** 54 * Sends data to the Web Service. 55 * 56 * @param InputData 57 * A std::string containing all the data, which is going to be submitted as HTTP POST data. 58 * 59 * @return 60 * Returns a pointer to a char array containing the data received from the Web Service. 61 * The caller needs to free that pointer. 62 */ 63 PCHAR 64 CWebService::DoRequest(const string& InputData) 65 { 66 const WCHAR szHeaders[] = L"Content-Type: application/x-www-form-urlencoded"; 67 68 auto_array_ptr<char> Data; 69 DWORD DataLength; 70 71 /* Post our test results to the web service */ 72 m_hHTTPRequest = HttpOpenRequestW(m_hHTTP, L"POST", szServerFile, NULL, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0); 73 74 if(!m_hHTTPRequest) 75 FATAL("HttpOpenRequestW failed\n"); 76 77 Data.reset(new char[InputData.size() + 1]); 78 strcpy(Data, InputData.c_str()); 79 80 if(!HttpSendRequestW(m_hHTTPRequest, szHeaders, wcslen(szHeaders), Data, InputData.size())) 81 FATAL("HttpSendRequestW failed\n"); 82 83 /* Get the response */ 84 if(!InternetQueryDataAvailable(m_hHTTPRequest, &DataLength, 0, 0)) 85 FATAL("InternetQueryDataAvailable failed\n"); 86 87 Data.reset(new char[DataLength + 1]); 88 89 if(!InternetReadFile(m_hHTTPRequest, Data, DataLength, &DataLength)) 90 FATAL("InternetReadFile failed\n"); 91 92 Data[DataLength] = 0; 93 94 return Data.release(); 95 } 96 97 /** 98 * Interface to other classes for finishing this test run 99 * 100 * @param TestType 101 * Constant pointer to a char array containing the test type to be run (i.e. "wine") 102 */ 103 void 104 CWebService::Finish(const char* TestType) 105 { 106 auto_array_ptr<char> Response; 107 string Data; 108 stringstream ss; 109 110 if (!m_TestID) 111 EXCEPTION("CWebService::Finish was called, but not a single result had been submitted!\n"); 112 113 Data = "action=finish"; 114 Data += Configuration.GetAuthenticationRequestString(); 115 Data += "&testtype="; 116 Data += TestType; 117 Data += "&testid="; 118 Data += m_TestID; 119 120 Response.reset(DoRequest(Data)); 121 122 if (strcmp(Response, "OK")) 123 { 124 ss << "When finishing the test run, the server responded:" << endl << Response << endl; 125 SSEXCEPTION; 126 } 127 } 128 129 /** 130 * Requests a Test ID from the Web Service for our test run. 131 * 132 * @param TestType 133 * Constant pointer to a char array containing the test type to be run (i.e. "wine") 134 */ 135 void 136 CWebService::GetTestID(const char* TestType) 137 { 138 string Data; 139 140 Data = "action=gettestid"; 141 Data += Configuration.GetAuthenticationRequestString(); 142 Data += Configuration.GetSystemInfoRequestString(); 143 Data += "&testtype="; 144 Data += TestType; 145 146 if(!Configuration.GetComment().empty()) 147 { 148 Data += "&comment="; 149 Data += Configuration.GetComment(); 150 } 151 152 m_TestID = DoRequest(Data); 153 154 /* Verify that this is really a number */ 155 if(!IsNumber(m_TestID)) 156 { 157 stringstream ss; 158 159 ss << "Expected Test ID, but received:" << endl << m_TestID << endl; 160 SSEXCEPTION; 161 } 162 } 163 164 /** 165 * Gets a Suite ID from the Web Service for this module/test combination. 166 * 167 * @param TestType 168 * Constant pointer to a char array containing the test type to be run (i.e. "wine") 169 * 170 * @param TestInfo 171 * Pointer to a CTestInfo object containing information about the test 172 * 173 * @return 174 * Returns a pointer to a char array containing the Suite ID received from the Web Service. 175 * The caller needs to free that pointer. 176 */ 177 PCHAR 178 CWebService::GetSuiteID(const char* TestType, CTestInfo* TestInfo) 179 { 180 auto_array_ptr<char> SuiteID; 181 string Data; 182 183 Data = "action=getsuiteid"; 184 Data += Configuration.GetAuthenticationRequestString(); 185 Data += "&testtype="; 186 Data += TestType; 187 Data += "&module="; 188 Data += TestInfo->Module; 189 Data += "&test="; 190 Data += TestInfo->Test; 191 192 SuiteID.reset(DoRequest(Data)); 193 194 /* Verify that this is really a number */ 195 if(!IsNumber(SuiteID)) 196 { 197 stringstream ss; 198 199 ss << "Expected Suite ID, but received:" << endl << SuiteID << endl; 200 SSEXCEPTION; 201 } 202 203 return SuiteID.release(); 204 } 205 206 /** 207 * Interface to other classes for submitting a result of one test 208 * 209 * @param TestType 210 * Constant pointer to a char array containing the test type to be run (i.e. "wine") 211 * 212 * @param TestInfo 213 * Pointer to a CTestInfo object containing information about the test 214 */ 215 void 216 CWebService::Submit(const char* TestType, CTestInfo* TestInfo) 217 { 218 auto_array_ptr<char> Response; 219 auto_array_ptr<char> SuiteID; 220 string Data; 221 stringstream ss; 222 223 if(!m_TestID) 224 GetTestID(TestType); 225 226 SuiteID.reset(GetSuiteID(TestType, TestInfo)); 227 228 Data = "action=submit"; 229 Data += Configuration.GetAuthenticationRequestString(); 230 Data += "&testtype="; 231 Data += TestType; 232 Data += "&testid="; 233 Data += m_TestID; 234 Data += "&suiteid="; 235 Data += SuiteID; 236 Data += "&log="; 237 Data += EscapeString(TestInfo->Log); 238 239 Response.reset(DoRequest(Data)); 240 241 if (strcmp(Response, "OK")) 242 { 243 ss << "When submitting the result, the server responded:" << endl << Response << endl; 244 SSEXCEPTION; 245 } 246 } 247