Changeset 2273 for box/chris/general/lib/common/Test.h
- Timestamp:
- 06/09/2008 11:52:56 (4 years ago)
- File:
-
- 1 edited
-
box/chris/general/lib/common/Test.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
box/chris/general/lib/common/Test.h
r2005 r2273 11 11 #define TEST__H 12 12 13 #include <errno.h> 14 #include <signal.h> 15 #include <stdio.h> 16 #include <stdlib.h> 13 #include <string> 17 14 18 #include <sys/stat.h> 19 #include <sys/types.h> 20 21 #ifdef HAVE_UNISTD_H 22 #include <unistd.h> 23 #endif 24 25 #include <string> 15 #include "Logging.h" 26 16 27 17 #ifdef WIN32 … … 54 44 } \ 55 45 failures++; \ 56 printf("FAILURE: " msg " at " __FILE__ "(%d)\n",__LINE__); \46 BOX_ERROR("FAILURE: " msg " at " __FILE__ ":" << __LINE__); \ 57 47 } 58 48 … … 63 53 64 54 // NOTE: The 0- bit is to allow this to work with stuff which has negative constants for flags (eg ConnectionException) 65 #define TEST_CHECK_THROWS(statement, excepttype, subtype) \66 { \67 bool didthrow = false; \68 try \69 { \70 statement; \71 } \72 catch(excepttype &e) \73 { \74 if(e.GetSubType() != ((unsigned int)excepttype::subtype) \75 && e.GetSubType() != (unsigned int)(0-excepttype::subtype)) \76 { \77 throw; \78 } \79 didthrow = true; \80 } \81 catch(...) \82 { \83 throw; \84 } \85 if(!didthrow) \86 { \87 TEST_FAIL_WITH_MESSAGE("Didn't throw exception " #excepttype "(" #subtype ")") \88 } \55 #define TEST_CHECK_THROWS(statement, excepttype, subtype) \ 56 { \ 57 bool didthrow = false; \ 58 try \ 59 { \ 60 statement; \ 61 } \ 62 catch(excepttype &e) \ 63 { \ 64 if(e.GetSubType() != ((unsigned int)excepttype::subtype) \ 65 && e.GetSubType() != (unsigned int)(0-excepttype::subtype)) \ 66 { \ 67 throw; \ 68 } \ 69 didthrow = true; \ 70 } \ 71 catch(...) \ 72 { \ 73 throw; \ 74 } \ 75 if(!didthrow) \ 76 { \ 77 TEST_FAIL_WITH_MESSAGE("Didn't throw exception " #excepttype "(" #subtype ")") \ 78 } \ 89 79 } 90 80 91 inline bool TestFileExists(const char *Filename) 92 { 93 struct stat st; 94 return ::stat(Filename, &st) == 0 && (st.st_mode & S_IFDIR) == 0; 95 } 81 bool TestFileExists(const char *Filename); 82 bool TestDirExists(const char *Filename); 96 83 97 inline bool TestDirExists(const char *Filename) 98 { 99 struct stat st; 100 return ::stat(Filename, &st) == 0 && (st.st_mode & S_IFDIR) == S_IFDIR; 101 } 102 103 // -1 if doesn't exist 104 inline int TestGetFileSize(const char *Filename) 105 { 106 struct stat st; 107 if(::stat(Filename, &st) == 0) 108 { 109 return st.st_size; 110 } 111 return -1; 112 } 113 114 inline std::string ConvertPaths(const std::string& rOriginal) 115 { 116 #ifdef WIN32 117 // convert UNIX paths to native 118 119 std::string converted; 120 for (size_t i = 0; i < rOriginal.size(); i++) 121 { 122 if (rOriginal[i] == '/') 123 { 124 converted += '\\'; 125 } 126 else 127 { 128 converted += rOriginal[i]; 129 } 130 } 131 return converted; 132 133 #else // !WIN32 134 return rOriginal; 135 #endif 136 } 137 138 inline int RunCommand(const std::string& rCommandLine) 139 { 140 return ::system(ConvertPaths(rCommandLine).c_str()); 141 } 142 143 #ifdef WIN32 144 #include <windows.h> 145 #endif 146 147 inline bool ServerIsAlive(int pid) 148 { 149 #ifdef WIN32 150 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid); 151 if (hProcess == NULL) 152 { 153 if (GetLastError() != ERROR_INVALID_PARAMETER) 154 { 155 printf("Failed to open process %d: error %d\n", 156 pid, (int)GetLastError()); 157 } 158 return false; 159 } 160 CloseHandle(hProcess); 161 return true; 162 #else // !WIN32 163 if(pid == 0) return false; 164 return ::kill(pid, 0) != -1; 165 #endif // WIN32 166 } 167 168 inline int ReadPidFile(const char *pidFile) 169 { 170 if(!TestFileExists(pidFile)) 171 { 172 TEST_FAIL_WITH_MESSAGE("Server didn't save PID file " 173 "(perhaps one was already running?)"); 174 return -1; 175 } 176 177 int pid = -1; 178 179 FILE *f = fopen(pidFile, "r"); 180 if(f == NULL || fscanf(f, "%d", &pid) != 1) 181 { 182 TEST_FAIL_WITH_MESSAGE("Couldn't read PID file"); 183 return -1; 184 } 185 fclose(f); 186 187 return pid; 188 } 189 190 inline int LaunchServer(const std::string& rCommandLine, const char *pidFile) 191 { 192 #ifdef WIN32 193 194 PROCESS_INFORMATION procInfo; 195 196 STARTUPINFO startInfo; 197 startInfo.cb = sizeof(startInfo); 198 startInfo.lpReserved = NULL; 199 startInfo.lpDesktop = NULL; 200 startInfo.lpTitle = NULL; 201 startInfo.dwFlags = 0; 202 startInfo.cbReserved2 = 0; 203 startInfo.lpReserved2 = NULL; 204 205 std::string cmd = ConvertPaths(rCommandLine); 206 CHAR* tempCmd = strdup(cmd.c_str()); 207 208 DWORD result = CreateProcess 209 ( 210 NULL, // lpApplicationName, naughty! 211 tempCmd, // lpCommandLine 212 NULL, // lpProcessAttributes 213 NULL, // lpThreadAttributes 214 false, // bInheritHandles 215 0, // dwCreationFlags 216 NULL, // lpEnvironment 217 NULL, // lpCurrentDirectory 218 &startInfo, // lpStartupInfo 219 &procInfo // lpProcessInformation 220 ); 221 222 free(tempCmd); 223 224 if (result == 0) 225 { 226 DWORD err = GetLastError(); 227 printf("Launch failed: %s: error %d\n", rCommandLine.c_str(), 228 (int)err); 229 return -1; 230 } 231 232 CloseHandle(procInfo.hProcess); 233 CloseHandle(procInfo.hThread); 234 235 #else // !WIN32 236 237 if(RunCommand(rCommandLine) != 0) 238 { 239 printf("Server: %s\n", rCommandLine.c_str()); 240 TEST_FAIL_WITH_MESSAGE("Couldn't start server"); 241 return -1; 242 } 243 244 #endif // WIN32 245 246 #ifdef WIN32 247 // on other platforms there is no other way to get 248 // the PID, so a NULL pidFile doesn't make sense. 249 250 if (pidFile == NULL) 251 { 252 return (int)procInfo.dwProcessId; 253 } 254 #endif 255 256 // time for it to start up 257 ::fprintf(stdout, "Starting server: %s\n", rCommandLine.c_str()); 258 ::fprintf(stdout, "Waiting for server to start: "); 259 260 for (int i = 0; i < 15; i++) 261 { 262 if (TestFileExists(pidFile)) 263 { 264 break; 265 } 266 267 #ifdef WIN32 268 if (!ServerIsAlive((int)procInfo.dwProcessId)) 269 { 270 break; 271 } 272 #endif 273 274 ::fprintf(stdout, "."); 275 ::fflush(stdout); 276 ::sleep(1); 277 } 278 279 #ifdef WIN32 280 // on Win32 we can check whether the process is alive 281 // without even checking the PID file 282 283 if (!ServerIsAlive((int)procInfo.dwProcessId)) 284 { 285 ::fprintf(stdout, "server died!\n"); 286 TEST_FAIL_WITH_MESSAGE("Server died!"); 287 return -1; 288 } 289 #endif 290 291 if (!TestFileExists(pidFile)) 292 { 293 ::fprintf(stdout, "timed out!\n"); 294 TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); 295 return -1; 296 } 297 298 ::fprintf(stdout, "done.\n"); 299 300 // wait a second for the pid to be written to the file 301 ::sleep(1); 302 303 // read pid file 304 int pid = ReadPidFile(pidFile); 305 306 #ifdef WIN32 307 // On Win32 we can check whether the PID in the pidFile matches 308 // the one returned by the system, which it always should. 309 310 if (pid != (int)procInfo.dwProcessId) 311 { 312 printf("Server wrote wrong pid to file (%s): expected %d " 313 "but found %d\n", pidFile, 314 (int)procInfo.dwProcessId, pid); 315 TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file"); 316 return -1; 317 } 318 #endif 319 320 return pid; 321 } 84 // TestGetFileSize() returns -1 if the file doesn't exist 85 int TestGetFileSize(const char *Filename); 86 std::string ConvertPaths(const std::string& rOriginal); 87 int RunCommand(const std::string& rCommandLine); 88 bool ServerIsAlive(int pid); 89 int ReadPidFile(const char *pidFile); 90 int LaunchServer(const std::string& rCommandLine, const char *pidFile); 322 91 323 92 #define TestRemoteProcessMemLeaks(filename) \ 324 93 TestRemoteProcessMemLeaksFunc(filename, __FILE__, __LINE__) 325 94 326 inline void TestRemoteProcessMemLeaksFunc(const char *filename, 327 const char* file, int line) 328 { 329 #ifdef BOX_MEMORY_LEAK_TESTING 330 // Does the file exist? 331 if(!TestFileExists(filename)) 332 { 333 if (failures == 0) 334 { 335 first_fail_file = file; 336 first_fail_line = line; 337 } 338 ++failures; 339 printf("FAILURE: MemLeak report not available (file %s) " 340 "at %s:%d\n", filename, file, line); 341 } 342 else 343 { 344 // Is it empty? 345 if(TestGetFileSize(filename) > 0) 346 { 347 if (failures == 0) 348 { 349 first_fail_file = file; 350 first_fail_line = line; 351 } 352 ++failures; 353 printf("FAILURE: Memory leaks found in other process " 354 "(file %s) at %s:%d\n==========\n", 355 filename, file, line); 356 FILE *f = fopen(filename, "r"); 357 char linebuf[512]; 358 while(::fgets(linebuf, sizeof(linebuf), f) != 0) 359 { 360 printf("%s", linebuf); 361 } 362 fclose(f); 363 printf("==========\n"); 364 } 365 366 // Delete it 367 ::unlink(filename); 368 } 369 #endif 370 } 95 void TestRemoteProcessMemLeaksFunc(const char *filename, 96 const char* file, int line); 371 97 372 inline void force_sync() 373 { 374 TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " 375 "force-sync") == 0); 376 TestRemoteProcessMemLeaks("bbackupctl.memleaks"); 377 } 378 379 inline void wait_for_sync_start() 380 { 381 TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " 382 "wait-for-sync") == 0); 383 TestRemoteProcessMemLeaks("bbackupctl.memleaks"); 384 } 385 386 inline void wait_for_sync_end() 387 { 388 TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " 389 "wait-for-end") == 0); 390 TestRemoteProcessMemLeaks("bbackupctl.memleaks"); 391 } 392 393 inline void sync_and_wait() 394 { 395 TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " 396 "sync-and-wait") == 0); 397 TestRemoteProcessMemLeaks("bbackupctl.memleaks"); 398 } 399 400 inline void terminate_bbackupd(int pid) 401 { 402 TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " 403 "terminate") == 0); 404 TestRemoteProcessMemLeaks("bbackupctl.memleaks"); 405 406 for (int i = 0; i < 20; i++) 407 { 408 if (!ServerIsAlive(pid)) break; 409 fprintf(stdout, "."); 410 fflush(stdout); 411 sleep(1); 412 } 413 414 TEST_THAT(!ServerIsAlive(pid)); 415 TestRemoteProcessMemLeaks("bbackupd.memleaks"); 416 } 417 98 // functions to send commands to bbackupd 99 void force_sync(); 100 void wait_for_sync_start(); 101 void wait_for_sync_end(); 102 void sync_and_wait(); 103 void terminate_bbackupd(int pid); 418 104 419 105 // Wait a given number of seconds for something to complete 420 inline void wait_for_operation(int seconds) 421 { 422 printf("Waiting: "); 423 fflush(stdout); 424 for(int l = 0; l < seconds; ++l) 425 { 426 sleep(1); 427 printf("."); 428 fflush(stdout); 429 } 430 printf(" done.\n"); 431 fflush(stdout); 432 } 106 void wait_for_operation(int seconds); 433 107 434 inline void safe_sleep(int seconds) 435 { 436 #ifdef WIN32 437 Sleep(seconds * 1000); 438 #else 439 struct timespec ts; 440 memset(&ts, 0, sizeof(ts)); 441 ts.tv_sec = seconds; 442 ts.tv_nsec = 0; 443 BOX_TRACE("sleeping for " << seconds << " seconds"); 444 while (nanosleep(&ts, &ts) == -1 && errno == EINTR) 445 { 446 BOX_TRACE("safe_sleep interrupted with " << 447 ts.tv_sec << "." << ts.tv_nsec << 448 " secs remaining, sleeping again"); 449 /* sleep again */ 450 } 451 #endif 452 } 108 // Sleep without interruption on Unix (resleep if interrupted) 109 void safe_sleep(int seconds); 453 110 454 111 #endif // TEST__H
Note: See TracChangeset
for help on using the changeset viewer.
