diff options
Diffstat (limited to 'lib/common/Test.cpp')
-rw-r--r-- | lib/common/Test.cpp | 351 |
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; +} + |