diff options
Diffstat (limited to 'infrastructure/buildenv-testmain-template.cpp')
-rw-r--r-- | infrastructure/buildenv-testmain-template.cpp | 337 |
1 files changed, 151 insertions, 186 deletions
diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index e5b1360d..d946c25d 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -23,10 +23,9 @@ #include <stdarg.h> #include <stdlib.h> #include <stdio.h> -#include <unistd.h> -#ifdef HAVE_GETOPT_H - #include <getopt.h> +#ifdef HAVE_NETDB_H +# include <netdb.h> #endif #ifdef HAVE_SYS_SOCKET_H @@ -41,8 +40,12 @@ #endif #include <exception> +#include <iostream> +#include <list> #include <string> +#include "box_getopt.h" +#include "depot.h" #include "Logging.h" #include "Test.h" #include "Timer.h" @@ -57,10 +60,6 @@ int test(int argc, const char *argv[]); #define MODE_TEXT "debug" #endif -int failures = 0; -int first_fail_line; -std::string first_fail_file; - #ifdef WIN32 #define QUIET_PROCESS "-Q" #else @@ -72,13 +71,13 @@ std::string bbackupd_args = QUIET_PROCESS, bbackupquery_args, test_args; -int filedes_open_at_beginning = -1; +bool filedes_initialised = false; #ifdef WIN32 // any way to check for open file descriptors on Win32? -inline bool check_filedes(bool x) { return 0; } -inline bool checkfilesleftopen() { return false; } +inline bool check_filedes(bool x) { return true; } +inline bool checkfilesleftopen() { return true; } #else // !WIN32 @@ -88,7 +87,9 @@ typedef enum { OPEN, CLOSED, - SYSLOG + SYSLOG, + STILLOPEN, + LEAKED, } filedes_t; @@ -98,23 +99,60 @@ bool check_filedes(bool report) { bool allOk = true; - // See how many file descriptors there are with values < 256 + // See how many file descriptors there are with values < 256. + // In order to avoid disturbing things, we scan the file descriptors + // first, marking the ones that were OPEN at startup (report == FALSE) + // as STILLOPEN and the ones that were not as LEAKED. Then we run + // through again and print the results. for(int d = 0; d < FILEDES_MAX; ++d) { if(::fcntl(d, F_GETFD) != -1) { // File descriptor obviously exists, but is it /dev/log? - - struct stat st; - bool stat_success = false; - bool is_syslog_socket = false; - - if(fstat(d, &st) == 0) + // Mark it as OPEN for now, and we'll find out later. + if(report) { - stat_success = true; + if(filedes_open[d] == OPEN) + { + filedes_open[d] = STILLOPEN; + } + else + { + filedes_open[d] = LEAKED; + } + } + else + { + filedes_open[d] = OPEN; } + } + else + { + filedes_open[d] = CLOSED; + } + } + + if(!report) + { + filedes_initialised = true; + return true; + } + + // Now loop again, reporting differences. + for(int d = 0; d < FILEDES_MAX; ++d) + { + if(filedes_open[d] != LEAKED) + { + continue; + } + + bool stat_success = false; + struct stat st; + if(fstat(d, &st) == 0) + { + stat_success = true; - if(stat_success && (st.st_mode & S_IFSOCK)) + if(st.st_mode & S_IFSOCK) { char buffer[256]; socklen_t addrlen = sizeof(buffer); @@ -122,7 +160,7 @@ bool check_filedes(bool report) #ifdef HAVE_GETPEERNAME if(getpeername(d, (sockaddr*)buffer, &addrlen) != 0) { - BOX_WARNING("Failed to getpeername(" << + BOX_LOG_SYS_WARNING("Failed to getpeername(" << d << "), cannot identify /dev/log"); } else @@ -132,90 +170,61 @@ bool check_filedes(bool report) if(sa->sun_family == PF_UNIX && !strcmp(sa->sun_path, "/dev/log")) { - is_syslog_socket = true; + // it's a syslog socket, ignore it + filedes_open[d] = SYSLOG; } } #endif // HAVE_GETPEERNAME } + } - if(report && filedes_open[d] != OPEN) - { - if(filedes_open[d] == SYSLOG) - { - // Different libcs have different ideas - // about when to open and close this - // socket, and it's not a leak, so - // ignore it. - } - else if(stat_success) - { - int m = st.st_mode; - #define flag(x) ((m & x) ? #x " " : "") - BOX_FATAL("File descriptor " << d << - " left open (type == " << - flag(S_IFIFO) << - flag(S_IFCHR) << - flag(S_IFDIR) << - flag(S_IFBLK) << - flag(S_IFREG) << - flag(S_IFLNK) << - flag(S_IFSOCK) << - " or " << m << ")"); - allOk = false; - } - else - { - BOX_FATAL("File descriptor " << d << - " left open (and stat failed)"); - allOk = false; - } - } - else if (!report) - { - filedes_open[d] = is_syslog_socket ? SYSLOG : OPEN; - } + if(filedes_open[d] == SYSLOG) + { + // Different libcs have different ideas + // about when to open and close this + // socket, and it's not a leak, so + // ignore it. } - else + else if(stat_success) { - if (report && filedes_open[d] != CLOSED) - { - if (filedes_open[d] == SYSLOG) - { - // Different libcs have different ideas - // about when to open and close this - // socket, and it's not a leak, so - // ignore it. - } - else if(filedes_open[d] == OPEN) - { - BOX_FATAL("File descriptor " << d << - " was open, now closed"); - allOk = false; - } - } - else - { - filedes_open[d] = CLOSED; - } + int m = st.st_mode; + #define flag(x) ((m & x) ? #x " " : "") + BOX_FATAL("File descriptor " << d << + " left open (type == " << + flag(S_IFIFO) << + flag(S_IFCHR) << + flag(S_IFDIR) << + flag(S_IFBLK) << + flag(S_IFREG) << + flag(S_IFLNK) << + flag(S_IFSOCK) << + " or " << m << ")"); + allOk = false; + } + else + { + BOX_FATAL("File descriptor " << d << + " left open (and stat failed)"); + allOk = false; } } if (!report && allOk) { - filedes_open_at_beginning = 0; + filedes_initialised = true; } - return !allOk; + return allOk; } bool checkfilesleftopen() { - if(filedes_open_at_beginning == -1) + if(!filedes_initialised) { // Not used correctly, pretend that there were things // left open so this gets investigated BOX_FATAL("File descriptor test was not initialised"); - return true; + return false; } // Count the file descriptors open @@ -224,6 +233,23 @@ bool checkfilesleftopen() #endif +int Usage(const std::string& ProgramName) +{ + std::cout << + "(built with QDBM " << dpversion << ")\n" + "\n" + "Usage: " << ProgramName << " [options]\n" + "\n" + "Options:\n" + " -c/--bbackupd-args <args> Arguments to pass to bbackupd/BackupDaemon\n" + " -s/--bbstored-args <args> Arguments to pass to bbstored/BackupStoreDaemon\n" + " -d/--test-daemon-args <args> Arguments to pass to TestDaemon\n" + " -e/--execute-only <test> Execute only specific named test, can repeat\n" + " -h/--help Show this command-line help\n" + << Logging::OptionParser::GetUsageString(); + return 0; +} + int main(int argc, char * const * argv) { // Start memory leak testing @@ -231,27 +257,25 @@ int main(int argc, char * const * argv) Logging::SetProgramName(BOX_MODULE); -#ifdef HAVE_GETOPT_H - #ifdef BOX_RELEASE_BUILD - int logLevel = Log::NOTICE; // need an int to do math with - #else - int logLevel = Log::INFO; // need an int to do math with - #endif - struct option longopts[] = { { "bbackupd-args", required_argument, NULL, 'c' }, { "bbstored-args", required_argument, NULL, 's' }, { "test-daemon-args", required_argument, NULL, 'd' }, + { "execute-only", required_argument, NULL, 'e' }, + { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; - - int ch; - - while ((ch = getopt_long(argc, argv, "c:d:qs:t:vPTUVW:", longopts, NULL)) + + int c; + std::string options("c:d:e:hs:"); + options += Logging::OptionParser::GetOptionString(); + Logging::OptionParser LogLevel; + + while ((c = getopt_long(argc, argv, options.c_str(), longopts, NULL)) != -1) { - switch(ch) + switch(c) { case 'c': { @@ -273,106 +297,43 @@ int main(int argc, char * const * argv) } break; - case 's': - { - bbstored_args += " "; - bbstored_args += optarg; - } - break; - - #ifndef WIN32 - case 'P': + case 'e': { - Console::SetShowPID(true); + run_only_named_tests.push_back(optarg); } break; - #endif - case 'q': + case 'h': { - if(logLevel == Log::NOTHING) - { - BOX_FATAL("Too many '-q': " - "Cannot reduce logging " - "level any more"); - return 2; - } - logLevel--; + return Usage(argv[0]); } break; - case 'v': - { - if(logLevel == Log::EVERYTHING) - { - BOX_FATAL("Too many '-v': " - "Cannot increase logging " - "level any more"); - return 2; - } - logLevel++; - } - break; - - case 'V': + case 's': { - logLevel = Log::EVERYTHING; + bbstored_args += " "; + bbstored_args += optarg; } break; - case 'W': + default: { - logLevel = Logging::GetNamedLevel(optarg); - if (logLevel == Log::INVALID) + int ret = LogLevel.ProcessOption(c); + if(ret != 0) { - BOX_FATAL("Invalid logging level: " << optarg); - return 2; + fprintf(stderr, "Unknown option code " + "'%c'\n", c); + exit(2); } } - break; - - case 't': - { - Logging::SetProgramName(optarg); - Console::SetShowTag(true); - } - break; - - case 'T': - { - Console::SetShowTime(true); - } - break; - - case 'U': - { - Console::SetShowTime(true); - Console::SetShowTimeMicros(true); - } - break; - - case '?': - { - fprintf(stderr, "Unknown option: '%c'\n", - optopt); - exit(2); - } - - default: - { - fprintf(stderr, "Unknown option code '%c'\n", - ch); - exit(2); - } } } - Logging::SetGlobalLevel((Log::Level)logLevel); - Logging::FilterConsole((Log::Level)logLevel); + Logging::FilterSyslog(Log::NOTHING); + Logging::FilterConsole(LogLevel.GetCurrentLevel()); argc -= optind - 1; argv += optind - 1; -#endif // HAVE_GETOPT_H // If there is more than one argument, then the test is doing something advanced, so leave it alone bool fulltestmode = (argc == 1); @@ -383,6 +344,14 @@ int main(int argc, char * const * argv) BOX_NOTICE("Running test TEST_NAME in " MODE_TEXT " mode..."); // Count open file descriptors for a very crude "files left open" test + Logging::GetSyslog().Shutdown(); + + // On NetBSD, gethostbyname() appears to open a kqueue socket + // and it's not clear how to close it again. So let's just do + // it once, before counting fds for the first time, so that it's + // already open and doesn't count as a leak. + ::gethostbyname("nonexistent"); + check_filedes(false); #ifdef WIN32 @@ -402,7 +371,7 @@ int main(int argc, char * const * argv) Timers::Init(); int returncode = test(argc, (const char **)argv); - Timers::Cleanup(); + Timers::Cleanup(false); fflush(stdout); fflush(stderr); @@ -411,7 +380,7 @@ int main(int argc, char * const * argv) #ifdef BOX_MEMORY_LEAK_TESTING if(memleakfinder_numleaks() != 0) { - failures++; + num_failures++; printf("FAILURE: Memory leaks detected in test code\n"); printf("==== MEMORY LEAKS =================================\n"); memleakfinder_reportleaks(); @@ -421,20 +390,22 @@ int main(int argc, char * const * argv) if(fulltestmode) { - bool filesleftopen = checkfilesleftopen(); + Logging::GetSyslog().Shutdown(); + + bool filesleftopen = !checkfilesleftopen(); fflush(stdout); fflush(stderr); if(filesleftopen) { - failures++; + num_failures++; printf("IMPLICIT TEST FAILED: Something left files open\n"); } - if(failures > 0) + if(num_failures > 0) { printf("FAILED: %d tests failed (first at " - "%s:%d)\n", failures, + "%s:%d)\n", num_failures, first_fail_file.c_str(), first_fail_line); } @@ -446,12 +417,6 @@ int main(int argc, char * const * argv) return returncode; } - catch(BoxException &e) - { - printf("FAILED: Exception caught: %s: %s\n", e.what(), - e.GetMessage().c_str()); - return 1; - } catch(std::exception &e) { printf("FAILED: Exception caught: %s\n", e.what()); @@ -464,7 +429,7 @@ int main(int argc, char * const * argv) } if(fulltestmode) { - if(checkfilesleftopen()) + if(!checkfilesleftopen()) { printf("WARNING: Files were left open\n"); } |