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