summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/common/ServerControl.h177
-rw-r--r--lib/common/Test.h331
-rw-r--r--test/backupstore/testbackupstore.cpp1
-rw-r--r--test/backupstorefix/testbackupstorefix.cpp15
-rw-r--r--test/backupstorepatch/testbackupstorepatch.cpp1
-rw-r--r--test/basicserver/testbasicserver.cpp1
-rw-r--r--test/bbackupd/testbbackupd.cpp1
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"