diff options
-rw-r--r-- | lib/common/ServerControl.h | 177 | ||||
-rw-r--r-- | lib/common/Test.h | 331 | ||||
-rw-r--r-- | test/backupstore/testbackupstore.cpp | 1 | ||||
-rw-r--r-- | test/backupstorefix/testbackupstorefix.cpp | 15 | ||||
-rw-r--r-- | test/backupstorepatch/testbackupstorepatch.cpp | 1 | ||||
-rw-r--r-- | test/basicserver/testbasicserver.cpp | 1 | ||||
-rw-r--r-- | test/bbackupd/testbbackupd.cpp | 1 |
7 files changed, 359 insertions, 168 deletions
diff --git a/lib/common/ServerControl.h b/lib/common/ServerControl.h new file mode 100644 index 00000000..a8477900 --- /dev/null +++ b/lib/common/ServerControl.h @@ -0,0 +1,177 @@ +#ifndef SERVER_CONTROL_H +#define SERVER_CONTROL_H + +#ifdef WIN32 + +#include "WinNamedPipeStream.h" +#include "IOStreamGetLine.h" +#include "BoxPortsAndFiles.h" +#include "Test.h" + +static bool SendCommands(const std::string& rCmd) +{ + WinNamedPipeStream connection; + + try + { + connection.Connect(BOX_NAMED_PIPE_NAME); + } + catch(...) + { + printf("Failed to connect to daemon control socket.\n"); + return false; + } + + // For receiving data + IOStreamGetLine getLine(connection); + + // Wait for the configuration summary + std::string configSummary; + if(!getLine.GetLine(configSummary)) + { + printf("Failed to receive configuration summary from daemon\n"); + return false; + } + + // Was the connection rejected by the server? + if(getLine.IsEOF()) + { + printf("Server rejected the connection.\n"); + return false; + } + + // Decode it + int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; + if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", + &autoBackup, &updateStoreInterval, + &minimumFileAge, &maxUploadWait) != 4) + { + printf("Config summary didn't decode\n"); + return false; + } + + std::string cmds; + bool expectResponse; + + if (rCmd != "") + { + cmds = rCmd; + cmds += "\nquit\n"; + expectResponse = true; + } + else + { + cmds = "quit\n"; + expectResponse = false; + } + + connection.Write(cmds.c_str(), cmds.size()); + + // Read the response + std::string line; + bool statusOk = !expectResponse; + + while (expectResponse && !getLine.IsEOF() && getLine.GetLine(line)) + { + // Is this an OK or error line? + if (line == "ok") + { + statusOk = true; + } + else if (line == "error") + { + printf("ERROR (%s)\n", rCmd.c_str()); + break; + } + else + { + printf("WARNING: Unexpected response to command '%s': " + "%s", rCmd.c_str(), line.c_str()); + } + } + + return statusOk; +} + +inline bool HUPServer(int pid) +{ + return SendCommands("reload"); +} + +inline bool KillServerInternal(int pid) +{ + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, pid); + if (hProcess == NULL) + { + printf("Failed to open process %d: error %d\n", + pid, (int)GetLastError()); + return false; + } + + if (!TerminateProcess(hProcess, 1)) + { + printf("Failed to terminate process %d: error %d\n", + pid, (int)GetLastError()); + CloseHandle(hProcess); + return false; + } + + CloseHandle(hProcess); + return true; +} + +#else // !WIN32 + +inline bool HUPServer(int pid) +{ + if(pid == 0) return false; + return ::kill(pid, SIGHUP) == 0; +} + +inline bool KillServerInternal(int pid) +{ + if(pid == 0 || pid == -1) return false; + bool killed = (::kill(pid, SIGTERM) == 0); + TEST_THAT(killed); + return killed; +} + +#endif // WIN32 + +inline bool KillServer(int pid) +{ + if (!KillServerInternal(pid)) + { + return false; + } + + for (int i = 0; i < 30; i++) + { + if (!ServerIsAlive(pid)) break; + ::sleep(1); + if (!ServerIsAlive(pid)) break; + + if (i == 0) + { + printf("waiting for server to die"); + } + + printf("."); + fflush(stdout); + } + + if (!ServerIsAlive(pid)) + { + printf("done.\n"); + } + else + { + printf("failed!\n"); + } + + fflush(stdout); + + return !ServerIsAlive(pid); +} + +#endif // SERVER_CONTROL_H diff --git a/lib/common/Test.h b/lib/common/Test.h index b7b96c06..6a517b1a 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -92,7 +92,7 @@ inline int TestGetFileSize(const char *Filename) return -1; } -inline int RunCommand(const char *pCommandLine) +inline std::string ConvertPaths(const char *pCommandLine) { #ifdef WIN32 // convert UNIX paths to native @@ -114,7 +114,37 @@ inline int RunCommand(const char *pCommandLine) std::string command = pCommandLine; #endif - return ::system(command.c_str()); + return command; +} + +inline int RunCommand(const char *pCommandLine) +{ + return ::system(ConvertPaths(pCommandLine).c_str()); +} + +#ifdef WIN32 +#include <windows.h> +#endif + +inline bool ServerIsAlive(int pid) +{ +#ifdef WIN32 + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid); + if (hProcess == NULL) + { + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + printf("Failed to open process %d: error %d\n", + pid, (int)GetLastError()); + } + return false; + } + CloseHandle(hProcess); + return true; +#else // !WIN32 + if(pid == 0) return false; + return ::kill(pid, 0) != -1; +#endif // WIN32 } inline int ReadPidFile(const char *pidFile) @@ -141,192 +171,136 @@ inline int ReadPidFile(const char *pidFile) inline int LaunchServer(const char *pCommandLine, const char *pidFile) { - if(RunCommand(pCommandLine) != 0) - { - printf("Server: %s\n", pCommandLine); - TEST_FAIL_WITH_MESSAGE("Couldn't start server"); - return -1; - } - - // give it time to start up - ::sleep(1); - - // read pid file - int pid = ReadPidFile(pidFile); +#ifdef WIN32 - if(pid == -1) + PROCESS_INFORMATION procInfo; + + STARTUPINFO startInfo; + startInfo.cb = sizeof(startInfo); + startInfo.lpReserved = NULL; + startInfo.lpDesktop = NULL; + startInfo.lpTitle = NULL; + startInfo.dwFlags = 0; + startInfo.cbReserved2 = 0; + startInfo.lpReserved2 = NULL; + + std::string cmd = ConvertPaths(pCommandLine); + CHAR* tempCmd = strdup(cmd.c_str()); + + DWORD result = CreateProcess + ( + NULL, // lpApplicationName, naughty! + tempCmd, // lpCommandLine + NULL, // lpProcessAttributes + NULL, // lpThreadAttributes + false, // bInheritHandles + 0, // dwCreationFlags + NULL, // lpEnvironment + NULL, // lpCurrentDirectory + &startInfo, // lpStartupInfo + &procInfo // lpProcessInformation + ); + + free(tempCmd); + + if (result == 0) { - // helps with debugging: - printf("Server: %s (pidfile %s)\n", pCommandLine, pidFile); + DWORD err = GetLastError(); + printf("Launch failed: %s: error %d\n", pCommandLine, (int)err); + return -1; } - return pid; -} - -#ifdef WIN32 - -#include "WinNamedPipeStream.h" -#include "IOStreamGetLine.h" -#include "BoxPortsAndFiles.h" + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); -bool SendCommands(const std::string& rCmd) -{ - WinNamedPipeStream connection; +#else // !WIN32 - try - { - connection.Connect(BOX_NAMED_PIPE_NAME); - } - catch(...) + if(RunCommand(pCommandLine) != 0) { - printf("Failed to connect to daemon control socket.\n"); - return false; + printf("Server: %s\n", pCommandLine); + TEST_FAIL_WITH_MESSAGE("Couldn't start server"); + return -1; } - // For receiving data - IOStreamGetLine getLine(connection); - - // Wait for the configuration summary - std::string configSummary; - if(!getLine.GetLine(configSummary)) - { - printf("Failed to receive configuration summary from daemon\n"); - return false; - } +#endif // WIN32 - // Was the connection rejected by the server? - if(getLine.IsEOF()) - { - printf("Server rejected the connection.\n"); - return false; - } + #ifdef WIN32 + // on other platforms there is no other way to get + // the PID, so a NULL pidFile doesn't make sense. - // Decode it - int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; - if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", - &autoBackup, &updateStoreInterval, - &minimumFileAge, &maxUploadWait) != 4) + if (pidFile == NULL) { - printf("Config summary didn't decode\n"); - return false; + return (int)procInfo.dwProcessId; } + #endif - std::string cmds; - bool expectResponse; - - if (rCmd != "") - { - cmds = rCmd; - cmds += "\nquit\n"; - expectResponse = true; - } - else - { - cmds = "quit\n"; - expectResponse = false; - } - - connection.Write(cmds.c_str(), cmds.size()); - - // Read the response - std::string line; - bool statusOk = !expectResponse; + // time for it to start up + ::fprintf(stdout, "Starting server: %s\n", pCommandLine); + ::fprintf(stdout, "Waiting for server to start: "); - while (expectResponse && !getLine.IsEOF() && getLine.GetLine(line)) + for (int i = 0; i < 15; i++) { - // Is this an OK or error line? - if (line == "ok") - { - statusOk = true; - } - else if (line == "error") + if (TestFileExists(pidFile)) { - printf("ERROR (%s)\n", rCmd.c_str()); break; } - else + + #ifdef WIN32 + if (!ServerIsAlive((int)procInfo.dwProcessId)) { - printf("WARNING: Unexpected response to command '%s': " - "%s", rCmd.c_str(), line.c_str()); + break; } - } - - return statusOk; -} + #endif -inline bool ServerIsAlive(int pid) -{ - return SendCommands(""); -} - -inline bool HUPServer(int pid) -{ - return SendCommands("reload"); -} - -inline bool KillServerInternal(int pid) -{ - bool sent = SendCommands("terminate"); - TEST_THAT(sent); - return sent; -} - -#else // !WIN32 - -inline bool ServerIsAlive(int pid) -{ - if(pid == 0) return false; - return ::kill(pid, 0) != -1; -} - -inline bool HUPServer(int pid) -{ - if(pid == 0) return false; - return ::kill(pid, SIGHUP) != -1; -} - -inline bool KillServerInternal(int pid) -{ - if(pid == 0 || pid == -1) return false; - bool killed = (::kill(pid, SIGTERM) == 0); - TEST_THAT(killed); - return killed; -} + ::fprintf(stdout, "."); + ::fflush(stdout); + ::sleep(1); + } -#endif // WIN32 + #ifdef WIN32 + // on Win32 we can check whether the process is alive + // without even checking the PID file -inline bool KillServer(int pid) -{ - if (!KillServerInternal(pid)) + if (!ServerIsAlive((int)procInfo.dwProcessId)) { - return false; + ::fprintf(stdout, "server died!\n"); + TEST_FAIL_WITH_MESSAGE("Server died!"); + return -1; } + #endif - for (int i = 0; i < 30; i++) + if (!TestFileExists(pidFile)) { - if (!ServerIsAlive(pid)) break; - ::sleep(1); - if (!ServerIsAlive(pid)) break; - - if (i == 0) - { - printf("waiting for server to die"); - } - printf("."); - fflush(stdout); + ::fprintf(stdout, "timed out!\n"); + TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); + return -1; } - - if (!ServerIsAlive(pid)) + else { - printf("done.\n"); + ::fprintf(stdout, "done.\n"); } - else + + // wait a second for the pid to be written to the file + ::sleep(1); + + // read pid file + int pid = ReadPidFile(pidFile); + + #ifdef WIN32 + // On Win32 we can check whether the PID in the pidFile matches + // the one returned by the system, which it always should. + + if (pid != (int)procInfo.dwProcessId) { - printf("failed!\n"); + printf("Server wrote wrong pid to file (%s): expected %d " + "but found %d\n", pidFile, + (int)procInfo.dwProcessId, pid); + TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file"); + return -1; } - fflush(stdout); + #endif - return !ServerIsAlive(pid); + return pid; } inline void TestRemoteProcessMemLeaks(const char *filename) @@ -361,4 +335,53 @@ inline void TestRemoteProcessMemLeaks(const char *filename) #endif } +#ifdef WIN32 +#define BBACKUPCTL "..\\..\\bin\\bbackupctl\\bbackupctl.exe" +#define BBACKUPD "..\\..\\bin\\bbackupd\\bbackupd.exe" +#define BBSTORED "..\\..\\bin\\bbstored\\bbstored.exe" +#define BBACKUPQUERY "..\\..\\bin\\bbackupquery\\bbackupquery.exe" +#define BBSTOREACCOUNTS "..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts.exe" +#define TEST_RETURN(actual, expected) TEST_THAT(actual == expected); +#else +#define BBACKUPCTL "../../bin/bbackupctl/bbackupctl" +#define BBACKUPD "../../bin/bbackupd/bbackupd" +#define BBSTORED "../../bin/bbackupd/bbstored" +#define BBACKUPQUERY "../../bin/bbackupquery/bbackupquery" +#define BBSTOREACCOUNTS "../../bin/bbstoreaccounts/bbstoreaccounts" +#define TEST_RETURN(actual, expected) TEST_THAT(actual == expected*256); +#endif + +inline void terminate_bbackupd(int pid) +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "terminate") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); + + for (int i = 0; i < 20; i++) + { + if (!ServerIsAlive(pid)) break; + fprintf(stdout, "."); + fflush(stdout); + sleep(1); + } + + TEST_THAT(!ServerIsAlive(pid)); + TestRemoteProcessMemLeaks("bbackupd.memleaks"); +} + + +// Wait a given number of seconds for something to complete +inline void wait_for_operation(int seconds) +{ + printf("waiting: "); + fflush(stdout); + for(int l = 0; l < seconds; ++l) + { + sleep(1); + printf("."); + fflush(stdout); + } + printf("\n"); +} + #endif // TEST__H diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 840d004c..da66af60 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -33,6 +33,7 @@ #include "MemBlockStream.h" #include "BackupClientFileAttributes.h" #include "BackupClientCryptoKeys.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 0349b039..dd8251c5 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -29,6 +29,7 @@ #include "RaidFileException.h" #include "StoreStructure.h" #include "BackupStoreFileWire.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" @@ -68,20 +69,6 @@ std::map<int32_t, bool> objectIsDir; ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567"); \ ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567 fix"); -// Wait a given number of seconds for something to complete -void wait_for_operation(int seconds) -{ - printf("waiting: "); - fflush(stdout); - for(int l = 0; l < seconds; ++l) - { - sleep(1); - printf("."); - fflush(stdout); - } - printf("\n"); -} - // Get ID of an object given a filename int32_t getID(const char *name) { diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index b33e8e73..6b93a3aa 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -35,6 +35,7 @@ #include "MemBlockStream.h" #include "BackupClientFileAttributes.h" #include "BackupClientCryptoKeys.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index 3360cd20..c56e6a0b 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -28,6 +28,7 @@ #include "TestContext.h" #include "autogen_TestProtocolClient.h" #include "autogen_TestProtocolServer.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index ea96a220..a99783e8 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -51,6 +51,7 @@ #include "FileStream.h" #include "IOStreamGetLine.h" #include "intercept.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" |