summaryrefslogtreecommitdiff
path: root/lib/server/ServerControl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/server/ServerControl.cpp')
-rw-r--r--lib/server/ServerControl.cpp171
1 files changed, 168 insertions, 3 deletions
diff --git a/lib/server/ServerControl.cpp b/lib/server/ServerControl.cpp
index f1a718df..b6cadab3 100644
--- a/lib/server/ServerControl.cpp
+++ b/lib/server/ServerControl.cpp
@@ -18,7 +18,9 @@
#include "BoxTime.h"
#include "IOStreamGetLine.h"
#include "ServerControl.h"
+#include "SocketStream.h"
#include "Test.h"
+#include "autogen_ServerException.h"
#ifdef WIN32
@@ -227,7 +229,7 @@ bool KillServer(int pid, bool WaitForProcess)
return !ServerIsAlive(pid);
}
-bool KillServer(std::string pid_file, bool WaitForProcess)
+bool KillServer(const std::string& pid_file, bool WaitForProcess)
{
FileStream fs(pid_file);
IOStreamGetLine getline(fs);
@@ -251,11 +253,174 @@ bool KillServer(std::string pid_file, bool WaitForProcess)
return status;
}
-int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file)
+int LaunchServer(const std::string& rCommandLine, const char *pidFile, int port,
+ const std::string& socket_path)
+{
+ BOX_INFO("Starting server: " << rCommandLine);
+
+#ifdef WIN32
+
+ // Use a Windows "Job Object" as a container for all our child
+ // processes. The test runner will create this job object when
+ // it starts, and close the handle (killing any running daemons)
+ // when it exits. This is the best way to avoid daemons hanging
+ // around and causing subsequent tests to fail, and/or the test
+ // runner to hang waiting for a daemon that will never terminate.
+
+ 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(rCommandLine);
+ 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);
+
+ TEST_THAT_OR(result != 0,
+ BOX_LOG_WIN_ERROR("Failed to CreateProcess: " << rCommandLine);
+ return -1;
+ );
+
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
+
+ return WaitForServerStartup(pidFile, (int)procInfo.dwProcessId, port, socket_path);
+
+#else // !WIN32
+
+ TEST_THAT_OR(RunCommand(rCommandLine) == 0,
+ TEST_FAIL_WITH_MESSAGE("Failed to start server: " << rCommandLine);
+ return -1;
+ )
+
+ return WaitForServerStartup(pidFile, 0, port, socket_path);
+
+#endif // WIN32
+}
+
+int WaitForServerStartup(const char *pidFile, int pidIfKnown, int port,
+ const std::string& socket_path)
+{
+#ifdef WIN32
+ if(pidFile == NULL && port == 0 && socket_path == "")
+ {
+ return pidIfKnown;
+ }
+#else
+ // On other platforms there is no other way to get the PID, so a NULL pidFile doesn't
+ // make sense.
+ ASSERT(pidFile != NULL);
+#endif
+
+ // time for it to start up
+ BOX_TRACE("Waiting for server to start");
+
+ for (int i = 150; i >= 0; i--)
+ {
+ if(i == 0)
+ {
+ // ran out of time waiting
+ TEST_FAIL_WITH_MESSAGE("Server didn't start within expected time");
+ return -1;
+ }
+
+ ShortSleep(MilliSecondsToBoxTime(100), false);
+
+ if(!TestFileNotEmpty(pidFile))
+ {
+ // Hasn't written a complete PID file yet, go round again
+ continue;
+ }
+
+ // Once we know what PID the process has/had, we can check if it has died during or
+ // shortly after startup:
+ if (pidIfKnown && !ServerIsAlive(pidIfKnown))
+ {
+ TEST_FAIL_WITH_MESSAGE("Server died!");
+ return -1;
+ }
+
+ if(port != 0 || socket_path != "")
+ {
+ try
+ {
+ if(port != 0)
+ {
+ SocketStream conn;
+ conn.Open(Socket::TypeINET, "localhost", port);
+ }
+
+ if(socket_path != "")
+ {
+ SocketStream conn;
+ conn.Open(Socket::TypeUNIX, socket_path);
+ }
+ }
+ catch(ServerException &e)
+ {
+ if(EXCEPTION_IS_TYPE(e, ServerException, SocketOpenError))
+ {
+ // not listening on port, go round again
+ continue;
+ }
+ else
+ {
+ // something bad happened, break
+ throw;
+ }
+ }
+ }
+
+ // All tests that we can do have passed, looks good!
+ break;
+ }
+
+ BOX_TRACE("Server started");
+
+ // read pid file
+ int pid = ReadPidFile(pidFile);
+
+ // On Win32 we can check whether the PID in the pidFile matches
+ // the one returned by the system, which it always should.
+ if (pidIfKnown && pid != pidIfKnown)
+ {
+ BOX_ERROR("Server wrote wrong pid to file (" << pidFile <<
+ "): expected " << pidIfKnown << " but found " <<
+ pid);
+ TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file");
+ return -1;
+ }
+
+ return pid;
+}
+
+int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file, int port,
+ const std::string& socket_path)
{
TEST_THAT_OR(current_pid == 0, return 0);
- int new_pid = LaunchServer(cmd_line, pid_file);
+ int new_pid = LaunchServer(cmd_line, pid_file, port, socket_path);
TEST_THAT_OR(new_pid != -1 && new_pid != 0, return 0);
::sleep(1);