[Box Backup-commit] COMMIT r1343 - box/chris/general/test/bbackupd
boxbackup-dev at fluffy.co.uk
boxbackup-dev at fluffy.co.uk
Sun Mar 4 00:22:51 GMT 2007
Author: chris
Date: 2007-03-04 00:22:51 +0000 (Sun, 04 Mar 2007)
New Revision: 1343
Modified:
box/chris/general/test/bbackupd/testbbackupd.cpp
Log:
Use predefined paths from Test.h to remove some #ifdefs.
Merge keepalive tests, although they don't work on win32 yet due to lack
of fork() and intercepts.
Use predefined paths in Test.h to remove some #ifdefs.
(from chris/merge)
Modified: box/chris/general/test/bbackupd/testbbackupd.cpp
===================================================================
--- box/chris/general/test/bbackupd/testbbackupd.cpp 2007-03-04 00:18:30 UTC (rev 1342)
+++ box/chris/general/test/bbackupd/testbbackupd.cpp 2007-03-04 00:22:51 UTC (rev 1343)
@@ -9,6 +9,13 @@
#include "Box.h"
+// do not include MinGW's dirent.h on Win32,
+// as we override some of it in lib/win32.
+
+#ifndef WIN32
+ #include <dirent.h>
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -27,6 +34,10 @@
#include <map>
+#ifdef HAVE_SYSCALL
+ #include <sys/syscall.h>
+#endif
+
#include "Test.h"
#include "BackupClientFileAttributes.h"
#include "CommonException.h"
@@ -52,6 +63,9 @@
#include "IOStreamGetLine.h"
#include "FileStream.h"
#include "LocalProcessStream.h"
+#include "BackupDaemon.h"
+#include "Timer.h"
+#include "intercept.h"
#include "MemLeakFindOn.h"
@@ -402,23 +416,19 @@
int test_setupaccount()
{
-#ifdef WIN32
- TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
-#else
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
-#endif
return 0;
}
int test_run_bbstored()
{
-#ifdef WIN32
- bbstored_pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
-#else
- bbstored_pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
-#endif
+ bbstored_pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
+
TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0);
+
if(bbstored_pid > 0)
{
::sleep(1);
@@ -580,6 +590,10 @@
return success;
}
+void intercept_setup_delay(const char *filename, unsigned int delay_after,
+ int delay_ms, int syscall_to_delay);
+bool intercept_triggered();
+
int64_t SearchDir(BackupStoreDirectory& rDir,
const std::string& rChildName)
{
@@ -593,10 +607,150 @@
return id;
}
+int start_internal_daemon()
+{
+ // ensure that no child processes end up running tests!
+ int own_pid = getpid();
+
+ BackupDaemon daemon;
+ const char* fake_argv[] = { "bbackupd", "testfiles/bbackupd.conf" };
+
+ int result = daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, 2,
+ fake_argv);
+
+ TEST_THAT(result == 0);
+ if (result != 0)
+ {
+ printf("Daemon exited with code %d\n", result);
+ }
+
+ // ensure that no child processes end up running tests!
+ TEST_THAT(getpid() == own_pid);
+ if (getpid() != own_pid)
+ {
+ // abort!
+ _exit(1);
+ }
+
+ TEST_THAT(TestFileExists("testfiles/bbackupd.pid"));
+
+ printf("Waiting for daemon to start");
+ int pid = -1;
+
+ for (int i = 0; i < 30; i++)
+ {
+ printf(".");
+ fflush(stdout);
+ sleep(1);
+
+ pid = ReadPidFile("testfiles/bbackupd.pid");
+ if (pid > 0)
+ {
+ break;
+ }
+ }
+
+ printf("\n");
+
+ TEST_THAT(pid > 0);
+ return pid;
+}
+
+void stop_internal_daemon(int pid)
+{
+ TEST_THAT(KillServer(pid));
+
+ /*
+ int status;
+ TEST_THAT(waitpid(pid, &status, 0) == pid);
+ TEST_THAT(WIFEXITED(status));
+
+ if (WIFEXITED(status))
+ {
+ TEST_THAT(WEXITSTATUS(status) == 0);
+ }
+ */
+}
+
+static struct dirent readdir_test_dirent;
+static int readdir_test_counter = 0;
+static int readdir_stop_time = 0;
+static char stat_hook_filename[512];
+
+// First test hook, during the directory scanning stage, returns empty.
+// This will not match the directory on the store, so a sync will start.
+// We set up the next intercept for the same directory by passing NULL.
+
+struct dirent *readdir_test_hook_2(DIR *dir);
+
+#ifdef LINUX_WEIRD_LSTAT
+int lstat_test_hook(int ver, const char *file_name, struct stat *buf);
+#else
+int lstat_test_hook(const char *file_name, struct stat *buf);
+#endif
+
+struct dirent *readdir_test_hook_1(DIR *dir)
+{
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_readdir_hook(NULL, readdir_test_hook_2);
+#endif
+ return NULL;
+}
+
+// Second test hook, during the directory sync stage, keeps returning
+// new filenames until the timer expires, then disables the intercept.
+
+struct dirent *readdir_test_hook_2(DIR *dir)
+{
+ if (time(NULL) >= readdir_stop_time)
+ {
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_readdir_hook(NULL, NULL);
+ intercept_setup_lstat_hook (NULL, NULL);
+#endif
+ // we will not be called again.
+ }
+
+ // fill in the struct dirent appropriately
+ memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent));
+
+#ifdef HAVE_STRUCT_DIRENT_D_INO
+ readdir_test_dirent.d_ino = ++readdir_test_counter;
+#endif
+
+ snprintf(readdir_test_dirent.d_name,
+ sizeof(readdir_test_dirent.d_name),
+ "test.%d", readdir_test_counter);
+
+ // ensure that when bbackupd stats the file, it gets the
+ // right answer
+ snprintf(stat_hook_filename, sizeof(stat_hook_filename),
+ "testfiles/TestDir1/spacetest/d1/test.%d",
+ readdir_test_counter);
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook);
+#endif
+
+ return &readdir_test_dirent;
+}
+
+#ifdef LINUX_WEIRD_LSTAT
+int lstat_test_hook(int ver, const char *file_name, struct stat *buf)
+#else
+int lstat_test_hook(const char *file_name, struct stat *buf)
+#endif
+{
+ // TRACE1("lstat hook triggered for %s", file_name);
+ memset(buf, 0, sizeof(*buf));
+ buf->st_mode = S_IFREG;
+ return 0;
+}
+
int test_bbackupd()
{
-// // First, wait for a normal period to make sure the last changes attributes are within a normal backup timeframe.
-// wait_for_backup_operation();
+ // First, wait for a normal period to make sure the last changes
+ // attributes are within a normal backup timeframe.
+ // wait_for_backup_operation();
// Connection gubbins
TLSContext context;
@@ -608,18 +762,290 @@
// unpack the files for the initial test
TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0);
TEST_THAT(::mkdir("testfiles/TestDir1", 0) == 0);
+
#ifdef WIN32
TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz -C testfiles/TestDir1") == 0);
#else
TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0);
#endif
+
+#ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ printf("Skipping intercept-based KeepAlive tests on this platform.\n");
+#else
+ {
+ #ifdef WIN32
+ #error TODO: implement threads on Win32, or this test \
+ will not finish properly
+ #endif
-#ifdef WIN32
- int pid = LaunchServer("..\\..\\bin\\bbackupd\\bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
-#else
- int pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
-#endif
+ // bbackupd daemon will try to initialise timers itself
+ Timers::Cleanup();
+
+ // something to diff against (empty file doesn't work)
+ int fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ char buffer[10000];
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ int pid = start_internal_daemon();
+ wait_for_backup_operation();
+ stop_internal_daemon(pid);
+
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 2000, SYS_read, 1);
+ TEST_THAT(unlink("testfiles/bbackupd.log") == 0);
+
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ stop_internal_daemon(pid);
+
+ // check that keepalive was written to logs, and
+ // diff was not aborted, i.e. upload was a diff
+ FileStream fs("testfiles/bbackupd.log", O_RDONLY);
+ IOStreamGetLine reader(fs);
+ bool found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive Success(0xe)");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 124");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Send StoreFile(0x3,";
+ TEST_THAT(line.substr(0, comp.size()) == comp);
+ comp = ",0xe,\"f1\")";
+ TEST_THAT(line.substr(line.size() - comp.size())
+ == comp);
+ }
+
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 4000, SYS_read, 1);
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ stop_internal_daemon(pid);
+
+ // check that the diff was aborted, i.e. upload was not a diff
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive Success(0xf)");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 124");
+
+ // delaying for 4 seconds in one step means that
+ // the diff timer and the keepalive timer will
+ // both expire, and the diff timer is honoured first,
+ // so there will be no keepalives.
+
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Send StoreFile(0x3,";
+ TEST_THAT(line.substr(0, comp.size()) == comp);
+ comp = ",0x0,\"f1\")";
+ TEST_THAT(line.substr(line.size() - comp.size())
+ == comp);
+ }
+
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 1000, SYS_read, 3);
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ stop_internal_daemon(pid);
+
+ // check that the diff was aborted, i.e. upload was not a diff
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive Success(0x10)");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 124");
+
+ // delaying for 3 seconds in steps of 1 second
+ // means that the keepalive timer will expire 3 times,
+ // and on the 3rd time the diff timer will expire too.
+ // The diff timer is honoured first, so there will be
+ // only two keepalives.
+
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Send StoreFile(0x3,";
+ TEST_THAT(line.substr(0, comp.size()) == comp);
+ comp = ",0x0,\"f1\")";
+ TEST_THAT(line.substr(line.size() - comp.size())
+ == comp);
+ }
+
+ intercept_setup_readdir_hook("testfiles/TestDir1/spacetest/d1",
+ readdir_test_hook_1);
+
+ // time for at least two keepalives
+ readdir_stop_time = time(NULL) + 12 + 2;
+
+ pid = start_internal_daemon();
+
+ std::string touchfile =
+ "testfiles/TestDir1/spacetest/d1/touch-me";
+
+ fd = open(touchfile.c_str(), O_CREAT | O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ stop_internal_daemon(pid);
+
+ // check that keepalives were sent during the dir search
+ found1 = false;
+
+ // skip to next login
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)")
+ {
+ found1 = true;
+ break;
+ }
+ }
+ }
+
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive Success(0x3)");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 425");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+ }
+
+ TEST_THAT(unlink(touchfile.c_str()) == 0);
+
+ // restore timers for rest of tests
+ Timers::Init();
+ }
+#endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+
+ int pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf",
+ "testfiles/bbackupd.pid");
+
TEST_THAT(pid != -1 && pid != 0);
+
if(pid > 0)
{
::sleep(1);
@@ -627,16 +1053,14 @@
// First, check storage space handling -- wait for file to be uploaded
wait_for_backup_operation();
- //TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf info 01234567") == 0);
+
// Set limit to something very small
// About 28 blocks will be used at this point. bbackupd will only pause if the size used is
// greater than soft limit + 1/3 of (hard - soft). Set small values for limits accordingly.
-#ifdef WIN32
- TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 40B") == 0);
-#else
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 40B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf setlimit 01234567 10B 40B")
+ == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
-#endif
// Unpack some more files
#ifdef WIN32
@@ -644,6 +1068,7 @@
#else
TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0);
#endif
+
// Delete a file and a directory
TEST_THAT(::unlink("testfiles/TestDir1/spacetest/d1/f3") == 0);
TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d3/d4") == 0);
@@ -655,12 +1080,10 @@
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
// Put the limit back
-#ifdef WIN32
- TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 1000B 2000B") == 0);
-#else
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 1000B 2000B") == 0);
- testRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
-#endif
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf setlimit 01234567 "
+ "1000B 2000B") == 0);
+ TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Check that the notify script was run
TEST_THAT(TestFileExists("testfiles/notifyran.store-full.1"));
@@ -679,7 +1102,9 @@
// Check that the contents of the store are the same as the contents
// of the disc (-a = all, -c = give result in return code)
- compareReturnValue = ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf -l testfiles/query1.log \"compare -ac\" quit");
+ compareReturnValue = ::system(BBACKUPQUERY " -q -c "
+ "testfiles/bbackupd.conf -l testfiles/query1.log "
+ "\"compare -ac\" quit");
TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
@@ -708,7 +1133,7 @@
//
// In ISO-8859-1 (Danish locale) they are three Danish
// accented characters, which are supported in code page
- // 850.
+ // 850. Depending on your locale, YYMV (your yak may vomit).
std::string foreignCharsNative("\x91\x9b\x86");
std::string foreignCharsUnicode;
@@ -1759,9 +2184,11 @@
terminate_bbackupd(pid);
// Start it again
- pid = LaunchServer("../../bin/bbackupd/bbackupd "
- "testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
+ pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf",
+ "testfiles/bbackupd.pid");
+
TEST_THAT(pid != -1 && pid != 0);
+
if(pid != -1 && pid != 0)
{
// Wait and compare
More information about the Boxbackup-commit
mailing list