[Box Backup-commit] COMMIT r1387 - in box/chris/merge: lib/common test/backupstore test/backupstorefix test/backupstorepatch test/basicserver test/bbackupd

boxbackup-dev at fluffy.co.uk boxbackup-dev at fluffy.co.uk
Sat Mar 10 16:12:02 GMT 2007


Author: chris
Date: 2007-03-10 16:12:01 +0000 (Sat, 10 Mar 2007)
New Revision: 1387

Added:
   box/chris/merge/lib/common/ServerControl.h
Modified:
   box/chris/merge/lib/common/Test.h
   box/chris/merge/test/backupstore/testbackupstore.cpp
   box/chris/merge/test/backupstorefix/testbackupstorefix.cpp
   box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp
   box/chris/merge/test/basicserver/testbasicserver.cpp
   box/chris/merge/test/bbackupd/testbbackupd.cpp
Log:
Moved SendCommands(), HUPServer(), KillServer() to lib/server/ServerCommands.h.
All of these use lib/server/WinNamedPipeStream on Win32, so they don't
belong in lib/common.

Made LaunchServer() work on Win32.

Added constants for paths to executables, for use in tests, removing the
need for #ifdefs and clumsy DIRECTORY_SEPARATORs in paths.

Added terminate_bbackupd() and wait_for_operation() functions.

Update unit tests to #include "ServerControl.h" if they need it.

(refs #3)


Copied: box/chris/merge/lib/common/ServerControl.h (from rev 1372, box/chris/general/lib/server/ServerControl.h)
===================================================================
--- box/chris/merge/lib/common/ServerControl.h	                        (rev 0)
+++ box/chris/merge/lib/common/ServerControl.h	2007-03-10 16:12:01 UTC (rev 1387)
@@ -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

Modified: box/chris/merge/lib/common/Test.h
===================================================================
--- box/chris/merge/lib/common/Test.h	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/lib/common/Test.h	2007-03-10 16:12:01 UTC (rev 1387)
@@ -92,7 +92,7 @@
 	return -1;
 }
 
-inline int RunCommand(const char *pCommandLine)
+inline std::string ConvertPaths(const char *pCommandLine)
 {
 #ifdef WIN32
 	// convert UNIX paths to native
@@ -114,9 +114,39 @@
 	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)
 {
 	if(!TestFileExists(pidFile))
@@ -141,192 +171,136 @@
 
 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)
-	{
-		// helps with debugging:
-		printf("Server: %s (pidfile %s)\n", pCommandLine, pidFile);
-	}
+	PROCESS_INFORMATION procInfo;
 
-	return pid;
-}
+	STARTUPINFO startInfo;
+	startInfo.cb = sizeof(startInfo);
+	startInfo.lpReserved = NULL;
+	startInfo.lpDesktop  = NULL;
+	startInfo.lpTitle    = NULL;
+	startInfo.dwFlags = 0;
+	startInfo.cbReserved2 = 0;
+	startInfo.lpReserved2 = NULL;
 
-#ifdef WIN32
+	std::string cmd = ConvertPaths(pCommandLine);
+	CHAR* tempCmd = strdup(cmd.c_str());
 
-#include "WinNamedPipeStream.h"
-#include "IOStreamGetLine.h"
-#include "BoxPortsAndFiles.h"
+	DWORD result = CreateProcess
+	(
+		NULL,        // lpApplicationName, naughty!
+		tempCmd,     // lpCommandLine
+		NULL,        // lpProcessAttributes
+		NULL,        // lpThreadAttributes
+		false,       // bInheritHandles
+		0,           // dwCreationFlags
+		NULL,        // lpEnvironment
+		NULL,        // lpCurrentDirectory
+		&startInfo,  // lpStartupInfo
+		&procInfo    // lpProcessInformation
+	);
 
-bool SendCommands(const std::string& rCmd)
-{
-	WinNamedPipeStream connection;
+	free(tempCmd);
 
-	try
+	if (result == 0)
 	{
-		connection.Connect(BOX_NAMED_PIPE_NAME);
+		DWORD err = GetLastError();
+		printf("Launch failed: %s: error %d\n", pCommandLine, (int)err);
+		return -1;
 	}
-	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;
-	}
+	CloseHandle(procInfo.hProcess);
+	CloseHandle(procInfo.hThread);
 
-	// Was the connection rejected by the server?
-	if(getLine.IsEOF())
-	{
-		printf("Server rejected the connection.\n");
-		return false;
-	}
+#else // !WIN32
 
-	// Decode it
-	int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait;
-	if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", 
-			&autoBackup, &updateStoreInterval, 
-			&minimumFileAge, &maxUploadWait) != 4)
+	if(RunCommand(pCommandLine) != 0)
 	{
-		printf("Config summary didn't decode\n");
-		return false;
+		printf("Server: %s\n", pCommandLine);
+		TEST_FAIL_WITH_MESSAGE("Couldn't start server");
+		return -1;
 	}
 
-	std::string cmds;
-	bool expectResponse;
+#endif // WIN32
 
-	if (rCmd != "")
+	#ifdef WIN32
+	// on other platforms there is no other way to get 
+	// the PID, so a NULL pidFile doesn't make sense.
+
+	if (pidFile == NULL)
 	{
-		cmds = rCmd;
-		cmds += "\nquit\n";
-		expectResponse = true;
+		return (int)procInfo.dwProcessId;
 	}
-	else
-	{
-		cmds = "quit\n";
-		expectResponse = false;
-	}
-	
-	connection.Write(cmds.c_str(), cmds.size());
-	
-	// Read the response
-	std::string line;
-	bool statusOk = !expectResponse;
+	#endif
 
-	while (expectResponse && !getLine.IsEOF() && getLine.GetLine(line))
+	// time for it to start up
+	::fprintf(stdout, "Starting server: %s\n", pCommandLine);
+	::fprintf(stdout, "Waiting for server to start: ");
+
+	for (int i = 0; i < 15; i++)
 	{
-		// Is this an OK or error line?
-		if (line == "ok")
+		if (TestFileExists(pidFile))	
 		{
-			statusOk = true;
+			break;
 		}
-		else if (line == "error")
+
+		#ifdef WIN32
+		if (!ServerIsAlive((int)procInfo.dwProcessId))
 		{
-			printf("ERROR (%s)\n", rCmd.c_str());
 			break;
 		}
-		else
-		{
-			printf("WARNING: Unexpected response to command '%s': "
-				"%s", rCmd.c_str(), line.c_str());
-		}
+		#endif
+
+		::fprintf(stdout, ".");
+		::fflush(stdout);
+		::sleep(1);
 	}
-	
-	return statusOk;
-}
 
-inline bool ServerIsAlive(int pid)
-{
-	return SendCommands("");
-}
+	#ifdef WIN32
+	// on Win32 we can check whether the process is alive
+	// without even checking the PID file
 
-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;
-}
-
-#endif // WIN32
-
-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 @@
 #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

Modified: box/chris/merge/test/backupstore/testbackupstore.cpp
===================================================================
--- box/chris/merge/test/backupstore/testbackupstore.cpp	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/test/backupstore/testbackupstore.cpp	2007-03-10 16:12:01 UTC (rev 1387)
@@ -33,6 +33,7 @@
 #include "MemBlockStream.h"
 #include "BackupClientFileAttributes.h"
 #include "BackupClientCryptoKeys.h"
+#include "ServerControl.h"
 
 #include "MemLeakFindOn.h"
 

Modified: box/chris/merge/test/backupstorefix/testbackupstorefix.cpp
===================================================================
--- box/chris/merge/test/backupstorefix/testbackupstorefix.cpp	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/test/backupstorefix/testbackupstorefix.cpp	2007-03-10 16:12:01 UTC (rev 1387)
@@ -29,6 +29,7 @@
 #include "RaidFileException.h"
 #include "StoreStructure.h"
 #include "BackupStoreFileWire.h"
+#include "ServerControl.h"
 
 #include "MemLeakFindOn.h"
 
@@ -68,20 +69,6 @@
 	::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)
 {

Modified: box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp
===================================================================
--- box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp	2007-03-10 16:12:01 UTC (rev 1387)
@@ -35,6 +35,7 @@
 #include "MemBlockStream.h"
 #include "BackupClientFileAttributes.h"
 #include "BackupClientCryptoKeys.h"
+#include "ServerControl.h"
 
 #include "MemLeakFindOn.h"
 

Modified: box/chris/merge/test/basicserver/testbasicserver.cpp
===================================================================
--- box/chris/merge/test/basicserver/testbasicserver.cpp	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/test/basicserver/testbasicserver.cpp	2007-03-10 16:12:01 UTC (rev 1387)
@@ -28,6 +28,7 @@
 #include "TestContext.h"
 #include "autogen_TestProtocolClient.h"
 #include "autogen_TestProtocolServer.h"
+#include "ServerControl.h"
 
 #include "MemLeakFindOn.h"
 

Modified: box/chris/merge/test/bbackupd/testbbackupd.cpp
===================================================================
--- box/chris/merge/test/bbackupd/testbbackupd.cpp	2007-03-10 15:31:25 UTC (rev 1386)
+++ box/chris/merge/test/bbackupd/testbbackupd.cpp	2007-03-10 16:12:01 UTC (rev 1387)
@@ -51,6 +51,7 @@
 #include "FileStream.h"
 #include "IOStreamGetLine.h"
 #include "intercept.h"
+#include "ServerControl.h"
 
 #include "MemLeakFindOn.h"
 




More information about the Boxbackup-commit mailing list