summaryrefslogtreecommitdiff
path: root/lib/common/Test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common/Test.cpp')
-rw-r--r--lib/common/Test.cpp351
1 files changed, 267 insertions, 84 deletions
diff --git a/lib/common/Test.cpp b/lib/common/Test.cpp
index de87c465..2c51cd61 100644
--- a/lib/common/Test.cpp
+++ b/lib/common/Test.cpp
@@ -22,7 +22,236 @@
#endif
#include "BoxTime.h"
+#include "FileStream.h"
#include "Test.h"
+#include "Utils.h"
+
+int num_tests_selected = 0;
+int num_failures = 0;
+int old_failure_count = 0;
+int first_fail_line;
+std::string original_working_dir;
+std::string first_fail_file;
+std::string current_test_name;
+std::list<std::string> run_only_named_tests;
+std::map<std::string, std::string> s_test_status;
+
+bool setUp(const char* function_name)
+{
+ current_test_name = function_name;
+
+ if (!run_only_named_tests.empty())
+ {
+ bool run_this_test = false;
+
+ for (std::list<std::string>::iterator
+ i = run_only_named_tests.begin();
+ i != run_only_named_tests.end(); i++)
+ {
+ if (*i == current_test_name)
+ {
+ run_this_test = true;
+ break;
+ }
+ }
+
+ if (!run_this_test)
+ {
+ // not in the list, so don't run it.
+ return false;
+ }
+ }
+
+ printf("\n\n== %s ==\n", function_name);
+ num_tests_selected++;
+ old_failure_count = num_failures;
+
+ if (original_working_dir == "")
+ {
+ char buf[1024];
+ if (getcwd(buf, sizeof(buf)) == NULL)
+ {
+ BOX_LOG_SYS_ERROR("getcwd");
+ }
+ original_working_dir = buf;
+ }
+ else
+ {
+ if (chdir(original_working_dir.c_str()) != 0)
+ {
+ BOX_LOG_SYS_ERROR("chdir");
+ }
+ }
+
+#ifdef _MSC_VER
+ DIR* pDir = opendir("testfiles");
+ if(!pDir)
+ {
+ THROW_SYS_FILE_ERROR("Failed to open test temporary directory",
+ "testfiles", CommonException, Internal);
+ }
+ struct dirent* pEntry;
+ for(pEntry = readdir(pDir); pEntry; pEntry = readdir(pDir))
+ {
+ std::string filename = pEntry->d_name;
+ if(StartsWith("TestDir", filename) ||
+ StartsWith("0_", filename) ||
+ filename == "accounts.txt" ||
+ StartsWith("file", filename) ||
+ StartsWith("notifyran", filename) ||
+ StartsWith("notifyscript.tag", filename) ||
+ StartsWith("restore", filename) ||
+ filename == "bbackupd-data" ||
+ filename == "syncallowscript.control" ||
+ StartsWith("syncallowscript.notifyran.", filename) ||
+ filename == "test2.downloaded" ||
+ EndsWith("testfile", filename))
+ {
+ std::string filepath = std::string("testfiles\\") + filename;
+
+ int filetype = ObjectExists(filepath);
+ if(filetype == ObjectExists_File)
+ {
+ if(::unlink(filepath.c_str()) != 0)
+ {
+ TEST_FAIL_WITH_MESSAGE(BOX_SYS_ERROR_MESSAGE("Failed to delete "
+ "test fixture file: unlink(\"" << filepath << "\")"));
+ }
+ }
+ else if(filetype == ObjectExists_Dir)
+ {
+ std::string cmd = "cmd /c rd /s /q " + filepath;
+ WCHAR* wide_cmd = ConvertUtf8ToWideString(cmd.c_str());
+ if(wide_cmd == NULL)
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to convert string "
+ "to wide string: " << cmd);
+ continue;
+ }
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ BOOL result = CreateProcessW(
+ NULL, // lpApplicationName
+ wide_cmd, // lpCommandLine
+ NULL, // lpProcessAttributes
+ NULL, // lpThreadAttributes
+ TRUE, // bInheritHandles
+ 0, // dwCreationFlags
+ NULL, // lpEnvironment
+ NULL, // lpCurrentDirectory
+ &si, // lpStartupInfo
+ &pi // lpProcessInformation
+ );
+ delete [] wide_cmd;
+
+ if(result == FALSE)
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to delete test "
+ "fixture file: failed to execute command "
+ "'" << cmd << "': " <<
+ GetErrorMessage(GetLastError()));
+ continue;
+ }
+
+ // Wait until child process exits.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ DWORD exit_code;
+ result = GetExitCodeProcess(pi.hProcess, &exit_code);
+
+ if(result == FALSE)
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to delete "
+ "test fixture file: failed to get "
+ "command exit status: '" <<
+ cmd << "': " <<
+ GetErrorMessage(GetLastError()));
+ }
+ else if(exit_code != 0)
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to delete test "
+ "fixture file: command '" << cmd << "' "
+ "exited with status " << exit_code);
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ TEST_FAIL_WITH_MESSAGE("Don't know how to delete file " << filepath <<
+ " of type " << filetype);
+ }
+ }
+ }
+ closedir(pDir);
+ FileStream touch("testfiles/accounts.txt", O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+#else
+ TEST_THAT_THROWONFAIL(system(
+ "rm -rf testfiles/TestDir* testfiles/0_0 testfiles/0_1 "
+ "testfiles/0_2 testfiles/accounts.txt " // testfiles/test* .tgz!
+ "testfiles/file* testfiles/notifyran testfiles/notifyran.* "
+ "testfiles/notifyscript.tag* "
+ "testfiles/restore* testfiles/bbackupd-data "
+ "testfiles/syncallowscript.control "
+ "testfiles/syncallowscript.notifyran.* "
+ "testfiles/test2.downloaded"
+ ) == 0);
+ TEST_THAT_THROWONFAIL(system("touch testfiles/accounts.txt") == 0);
+#endif
+ TEST_THAT_THROWONFAIL(mkdir("testfiles/0_0", 0755) == 0);
+ TEST_THAT_THROWONFAIL(mkdir("testfiles/0_1", 0755) == 0);
+ TEST_THAT_THROWONFAIL(mkdir("testfiles/0_2", 0755) == 0);
+ TEST_THAT_THROWONFAIL(mkdir("testfiles/bbackupd-data", 0755) == 0);
+
+ return true;
+}
+
+bool tearDown()
+{
+ if (num_failures == old_failure_count)
+ {
+ BOX_NOTICE(current_test_name << " passed");
+ s_test_status[current_test_name] = "passed";
+ return true;
+ }
+ else
+ {
+ BOX_NOTICE(current_test_name << " failed"); \
+ s_test_status[current_test_name] = "FAILED";
+ return false;
+ }
+}
+
+bool fail()
+{
+ num_failures++;
+ return tearDown();
+}
+
+int finish_test_suite()
+{
+ printf("\n");
+ printf("Test results:\n");
+
+ typedef std::map<std::string, std::string>::iterator s_test_status_iterator;
+ for(s_test_status_iterator i = s_test_status.begin();
+ i != s_test_status.end(); i++)
+ {
+ BOX_NOTICE("test result: " << i->second << ": " << i->first);
+ }
+
+ TEST_LINE(num_tests_selected > 0, "No tests matched the patterns "
+ "specified on the command line");
+
+ return (num_failures == 0 && num_tests_selected > 0) ? 0 : 1;
+}
bool TestFileExists(const char *Filename)
{
@@ -136,7 +365,7 @@ int ReadPidFile(const char *pidFile)
if(!TestFileNotEmpty(pidFile))
{
TEST_FAIL_WITH_MESSAGE("Server didn't save PID file "
- "(perhaps one was already running?)");
+ "(perhaps one was already running?)");
return -1;
}
@@ -145,7 +374,7 @@ int ReadPidFile(const char *pidFile)
FILE *f = fopen(pidFile, "r");
if(f == NULL || fscanf(f, "%d", &pid) != 1)
{
- TEST_FAIL_WITH_MESSAGE("Couldn't read PID file");
+ TEST_FAIL_WITH_MESSAGE("Couldn't read PID file");
return -1;
}
fclose(f);
@@ -155,7 +384,7 @@ int ReadPidFile(const char *pidFile)
int LaunchServer(const std::string& rCommandLine, const char *pidFile)
{
- ::fprintf(stdout, "Starting server: %s\n", rCommandLine.c_str());
+ BOX_INFO("Starting server: " << rCommandLine);
#ifdef WIN32
@@ -189,14 +418,10 @@ int LaunchServer(const std::string& rCommandLine, const char *pidFile)
free(tempCmd);
- if (result == 0)
- {
- DWORD err = GetLastError();
- printf("Launch failed: %s: error %d\n", rCommandLine.c_str(),
- (int)err);
- TEST_FAIL_WITH_MESSAGE("Couldn't start server");
+ TEST_THAT_OR(result != 0,
+ BOX_LOG_WIN_ERROR("Launch failed: " << rCommandLine);
return -1;
- }
+ );
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
@@ -205,11 +430,10 @@ int LaunchServer(const std::string& rCommandLine, const char *pidFile)
#else // !WIN32
- if(RunCommand(rCommandLine) != 0)
- {
- TEST_FAIL_WITH_MESSAGE("Couldn't start server");
+ TEST_THAT_OR(RunCommand(rCommandLine) == 0,
+ TEST_FAIL_WITH_MESSAGE("Failed to start server: " << rCommandLine);
return -1;
- }
+ )
return WaitForServerStartup(pidFile, 0);
@@ -230,18 +454,11 @@ int WaitForServerStartup(const char *pidFile, int pidIfKnown)
#endif
// time for it to start up
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_TRACE("Waiting for server to start");
- }
- else
- {
- ::fprintf(stdout, "Waiting for server to start: ");
- }
+ BOX_TRACE("Waiting for server to start");
for (int i = 0; i < 15; i++)
{
- if (TestFileNotEmpty(pidFile))
+ if (TestFileNotEmpty(pidFile))
{
break;
}
@@ -251,12 +468,6 @@ int WaitForServerStartup(const char *pidFile, int pidIfKnown)
break;
}
- if (Logging::GetGlobalLevel() < Log::TRACE)
- {
- ::fprintf(stdout, ".");
- ::fflush(stdout);
- }
-
::sleep(1);
}
@@ -265,42 +476,17 @@ int WaitForServerStartup(const char *pidFile, int pidIfKnown)
if (pidIfKnown && !ServerIsAlive(pidIfKnown))
{
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_ERROR("server died!");
- }
- else
- {
- ::fprintf(stdout, " server died!\n");
- }
-
- TEST_FAIL_WITH_MESSAGE("Server died!");
+ TEST_FAIL_WITH_MESSAGE("Server died!");
return -1;
}
if (!TestFileNotEmpty(pidFile))
{
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_ERROR("timed out!");
- }
- else
- {
- ::fprintf(stdout, " timed out!\n");
- }
-
- TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
+ TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
return -1;
}
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_TRACE("Server started");
- }
- else
- {
- ::fprintf(stdout, " done.\n");
- }
+ BOX_TRACE("Server started");
// wait a second for the pid to be written to the file
::sleep(1);
@@ -330,12 +516,12 @@ void TestRemoteProcessMemLeaksFunc(const char *filename,
// Does the file exist?
if(!TestFileExists(filename))
{
- if (failures == 0)
+ if (num_failures == 0)
{
first_fail_file = file;
first_fail_line = line;
}
- ++failures;
+ ++num_failures;
printf("FAILURE: MemLeak report not available (file %s) "
"at %s:%d\n", filename, file, line);
}
@@ -344,12 +530,12 @@ void TestRemoteProcessMemLeaksFunc(const char *filename,
// Is it empty?
if(TestGetFileSize(filename) > 0)
{
- if (failures == 0)
+ if (num_failures == 0)
{
first_fail_file = file;
first_fail_line = line;
}
- ++failures;
+ ++num_failures;
printf("FAILURE: Memory leaks found in other process "
"(file %s) at %s:%d\n==========\n",
filename, file, line);
@@ -378,23 +564,29 @@ void force_sync()
void wait_for_sync_start()
{
+ BOX_TRACE("Waiting for sync to start...");
TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
"wait-for-sync") == 0);
TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+ BOX_TRACE("Backup daemon reported that sync has started.");
}
void wait_for_sync_end()
{
+ BOX_TRACE("Waiting for sync to finish...");
TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
"wait-for-end") == 0);
TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+ BOX_TRACE("Backup daemon reported that sync has finished.");
}
void sync_and_wait()
{
+ BOX_TRACE("Starting a sync and waiting for it to finish...");
TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
"sync-and-wait") == 0);
TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+ BOX_TRACE("Backup daemon reported that sync has finished.");
}
void terminate_bbackupd(int pid)
@@ -419,35 +611,14 @@ void terminate_bbackupd(int pid)
// Wait a given number of seconds for something to complete
void wait_for_operation(int seconds, const char* message)
{
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_TRACE("Waiting " << seconds << " seconds for " << message);
- }
- else
- {
- printf("Waiting for %s: ", message);
- fflush(stdout);
- }
+ BOX_INFO("Waiting " << seconds << " seconds for " << message);
for(int l = 0; l < seconds; ++l)
{
sleep(1);
- if (Logging::GetGlobalLevel() < Log::TRACE)
- {
- printf(".");
- fflush(stdout);
- }
}
- if (Logging::GetGlobalLevel() >= Log::TRACE)
- {
- BOX_TRACE("Finished waiting for " << message);
- }
- else
- {
- printf(" done.\n");
- fflush(stdout);
- }
+ BOX_TRACE("Finished waiting for " << message);
}
void safe_sleep(int seconds)
@@ -455,3 +626,15 @@ void safe_sleep(int seconds)
ShortSleep(SecondsToBoxTime(seconds), true);
}
+std::auto_ptr<Configuration> load_config_file(const std::string& config_file,
+ const ConfigurationVerify& verify)
+{
+ std::string errs;
+ std::auto_ptr<Configuration> config(
+ Configuration::LoadAndVerify(config_file, &verify, errs));
+ TEST_EQUAL_LINE(0, errs.size(), "Failed to load configuration file: " + config_file +
+ ": " + errs);
+ TEST_EQUAL_OR(0, errs.size(), config.reset());
+ return config;
+}
+