summaryrefslogtreecommitdiff
path: root/infrastructure/buildenv-testmain-template.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure/buildenv-testmain-template.cpp')
-rw-r--r--infrastructure/buildenv-testmain-template.cpp337
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");
}