diff options
author | Chris Wilson <chris+github@qwirx.com> | 2007-09-19 21:58:24 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2007-09-19 21:58:24 +0000 |
commit | 867fbf737760a7764f6095a1b9b7554047c47eb3 (patch) | |
tree | 1bc17e74cfef9352857f62b3ee842fa95a8547a4 /test | |
parent | 41f3230a75e965254ab47e3609f68c8634266d37 (diff) | |
parent | 2ff87143551e6882c90ceaba940a34779b922882 (diff) |
Replace trunk with chris/merge.
Diffstat (limited to 'test')
-rw-r--r-- | test/backupdiff/testbackupdiff.cpp | 16 | ||||
-rw-r--r-- | test/backupstore/testbackupstore.cpp | 72 | ||||
-rw-r--r-- | test/backupstorefix/testbackupstorefix.cpp | 120 | ||||
-rw-r--r-- | test/backupstorepatch/testbackupstorepatch.cpp | 17 | ||||
-rw-r--r-- | test/basicserver/TestCommands.cpp | 2 | ||||
-rw-r--r-- | test/basicserver/testbasicserver.cpp | 180 | ||||
-rw-r--r-- | test/basicserver/testfiles/srv4.conf | 2 | ||||
-rw-r--r-- | test/bbackupd/Makefile.extra | 1 | ||||
-rw-r--r-- | test/bbackupd/testbbackupd.cpp | 2325 | ||||
-rw-r--r-- | test/bbackupd/testfiles/bbackupd.conf.in | 9 | ||||
-rwxr-xr-x | test/bbackupd/testfiles/extcheck1.pl.in | 19 | ||||
-rwxr-xr-x | test/bbackupd/testfiles/extcheck2.pl.in | 20 | ||||
-rwxr-xr-x | test/bbackupd/testfiles/notifyscript.pl.in | 2 | ||||
-rwxr-xr-x | test/bbackupd/testfiles/syncallowscript.pl.in | 2 | ||||
-rw-r--r-- | test/common/testcommon.cpp | 296 | ||||
-rw-r--r-- | test/raidfile/intercept.cpp | 272 | ||||
-rw-r--r-- | test/raidfile/testraidfile.cpp | 126 | ||||
-rw-r--r-- | test/win32/testlibwin32.cpp | 279 |
18 files changed, 3033 insertions, 727 deletions
diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 303861a8..a91d6dfe 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -375,8 +375,10 @@ int test(int argc, const char *argv[]) { // Want to trace out all the details #ifndef NDEBUG + #ifndef WIN32 BackupStoreFile::TraceDetailsOfDiffProcess = true; #endif + #endif // Create all the test files create_test_files(); @@ -509,8 +511,15 @@ int test(int argc, const char *argv[]) // suck up lots of processor time -- because of lots of matches // found. Check this out! + #ifdef WIN32 + ::fprintf(stdout, "Testing diffing two large streams, " + "may take a while!\n"); + ::fflush(stdout); + #endif + make_file_of_zeros("testfiles/zero.0", 20*1024*1024); make_file_of_zeros("testfiles/zero.1", 200*1024*1024); + // Generate a first encoded file { BackupStoreFilenameClear f0name("zero.0"); @@ -530,7 +539,14 @@ int test(int argc, const char *argv[]) 2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite, 0, 0)); encoded->CopyStreamTo(out); + + printf("Time taken: %d seconds\n", (int)(time(0) - beginTime)); + + #ifdef WIN32 + TEST_THAT(time(0) < (beginTime + 300)); + #else TEST_THAT(time(0) < (beginTime + 40)); + #endif } // Remove zero-files to save disk space remove("testfiles/zero.0"); diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 34fc98cd..ca29cdff 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" @@ -1683,7 +1684,10 @@ int test3(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1712,12 +1716,17 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf create 01234567 0 " + "10000B 20000B") == 0); + TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); + TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567")); - TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); // make sure something is written to it + TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); + // make sure something is written to it TEST_THAT(ServerIsAlive(pid)); @@ -1741,13 +1750,18 @@ int test3(int argc, const char *argv[]) TestRemoteProcessMemLeaks("bbstored.memleaks"); #endif - // Set a new limit on the account -- leave the hard limit high to make sure the target for - // freeing space is the soft limit. - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); + // Set a new limit on the account -- leave the hard limit + // high to make sure the target for freeing space is the + // soft limit. + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf setlimit 01234567 " + "10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start things up - pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); + ::sleep(1); TEST_THAT(ServerIsAlive(pid)); @@ -1763,8 +1777,9 @@ int test3(int argc, const char *argv[]) // Count the objects again recursive_count_objects_results after = {0,0,0}; - recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, after); -printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after.deleted, after.old); + recursive_count_objects("localhost", + BackupProtocolClientListDirectory::RootDirectory, + after); // If these tests fail then try increasing the timeout above TEST_THAT(after.objectsNotDel == before.objectsNotDel); @@ -1772,7 +1787,9 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf setlimit 01234567 " + "10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Try to upload a file and create a directory, and check an error is generated @@ -1836,11 +1853,16 @@ int multi_server() printf("Starting server for connection from remote machines...\n"); // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf create 01234567 0 " + "30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); + + int pid = LaunchServer(BBSTORED " testfiles/bbstored_multi.conf", + "testfiles/bbstored.pid"); + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1874,12 +1896,6 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName); int test(int argc, const char *argv[]) { #ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) - // this had better work, or bbstored will die when combining diffs char* file = "foo"; std::string abs = ConvertPathToAbsoluteUnicode(file); @@ -1905,6 +1921,7 @@ int test(int argc, const char *argv[]) CloseHandle(h2); CloseHandle(h1); + delete [] wfile; h1 = openfile("foo", O_CREAT | O_RDWR, 0); TEST_THAT(h1 != INVALID_HANDLE_VALUE); @@ -1932,14 +1949,19 @@ int test(int argc, const char *argv[]) // for seeing what's going on. BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); - // encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised - for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) - { - ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]); - } - for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l) + // encode in some filenames -- can't do static initialisation + // because the key won't be set up when these are initialised { - uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]); + MEMLEAKFINDER_NO_LEAKS + + for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) + { + ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]); + } + for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l) + { + uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]); + } } // Trace errors out diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 92928cc6..97ff70f3 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" @@ -42,7 +43,7 @@ make some BackupDirectoryStore objects, CheckAndFix(), then verify - all old flags delete store info -add suprious file +add spurious file delete directory (should appear again) change container ID of directory delete a file @@ -65,22 +66,8 @@ std::map<std::string, int32_t> nameToID; std::map<int32_t, bool> objectIsDir; #define RUN_CHECK \ - ::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"); -} + ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567"); \ + ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567 fix"); // Get ID of an object given a filename int32_t getID(const char *name) @@ -138,6 +125,7 @@ void CorruptObject(const char *name, int start, const char *rubbish) w.Write(rubbish, rubbish_len); // Copy rest of file r->CopyStreamTo(w); + r->Close(); // Commit w.Commit(true /* convert now */); } @@ -202,9 +190,12 @@ void check_dir_dep(BackupStoreDirectory &dir, checkdepinfoen *ck) void test_dir_fixing() { - fnames[0].SetAsClearFilename("x1"); - fnames[1].SetAsClearFilename("x2"); - fnames[2].SetAsClearFilename("x3"); + { + MEMLEAKFINDER_NO_LEAKS; + fnames[0].SetAsClearFilename("x1"); + fnames[1].SetAsClearFilename("x2"); + fnames[2].SetAsClearFilename("x3"); + } { BackupStoreDirectory dir; @@ -275,7 +266,7 @@ void test_dir_fixing() TEST_THAT(dir.CheckAndFix() == false); check_dir_dep(dir, c1); - // Check that a suprious depends older ref is undone + // Check that a spurious depends older ref is undone e2->SetDependsOlder(1); TEST_THAT(dir.CheckAndFix() == true); TEST_THAT(dir.CheckAndFix() == false); @@ -300,37 +291,52 @@ int test(int argc, const char *argv[]) rcontroller.Initialise("testfiles/raidfile.conf"); // Create an account - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf " + "create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start the bbstored server - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { ::sleep(1); TEST_THAT(ServerIsAlive(pid)); // Run the perl script to create the initial directories - TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl init") == 0); + TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl init") == 0); - int bbackupd_pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); + int bbackupd_pid = LaunchServer(BBACKUPD + " testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + if(bbackupd_pid > 0) { ::sleep(1); TEST_THAT(ServerIsAlive(bbackupd_pid)); // Create a nice store directory - wait_for_operation(30); + wait_for_operation(14); // That'll do nicely, stop the server - TEST_THAT(KillServer(bbackupd_pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + #ifdef WIN32 + terminate_bbackupd(bbackupd_pid); + // implicit check for memory leaks + #else + TEST_THAT(KillServer(bbackupd_pid)); + TestRemoteProcessMemLeaks("bbackupd.memleaks"); + #endif } // Generate a list of all the object IDs - TEST_THAT_ABORTONFAIL(::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit > testfiles/initial-listing.txt") == 0); + TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf \"list -r\" quit " + "> testfiles/initial-listing.txt") == 0); + // And load it in { FILE *f = ::fopen("testfiles/initial-listing.txt", "r"); @@ -341,9 +347,11 @@ int test(int argc, const char *argv[]) char name[256]; while(::fgets(line, sizeof(line), f) != 0) { - TEST_THAT(::sscanf(line, "%x %s %s", &id, flags, name) == 3); + TEST_THAT(::sscanf(line, "%x %s %s", &id, + flags, name) == 3); bool isDir = (::strcmp(flags, "-d---") == 0); //TRACE3("%x,%d,%s\n", id, isDir, name); + MEMLEAKFINDER_NO_LEAKS; nameToID[std::string(name)] = id; objectIsDir[id] = isDir; } @@ -358,19 +366,24 @@ int test(int argc, const char *argv[]) del.Delete(); } { - // Add a suprious file - RaidFileWrite random(discSetNum, storeRoot + "randomfile"); + // Add a spurious file + RaidFileWrite random(discSetNum, + storeRoot + "randomfile"); random.Open(); random.Write("test", 4); random.Commit(true); } + // Fix it RUN_CHECK + // Check everything is as it was - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 0") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 0") == 0); // Check the random file doesn't exist { - TEST_THAT(!RaidFileRead::FileExists(discSetNum, storeRoot + "01/randomfile")); + TEST_THAT(!RaidFileRead::FileExists(discSetNum, + storeRoot + "01/randomfile")); } // ------------------------------------------------------------------------------------------------ @@ -410,6 +423,8 @@ int test(int argc, const char *argv[]) file_BlockIndexEntry e[2]; } h; TEST_THAT(file->Read(&h, sizeof(h)) == sizeof(h)); + file->Close(); + // Modify TEST_THAT(box_ntoh64(h.hdr.mOtherFileID) == 0); TEST_THAT(box_ntoh64(h.hdr.mNumBlocks) >= 2); @@ -425,14 +440,16 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 1") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 1") + == 0); // Check the modified file doesn't exist TEST_THAT(!RaidFileRead::FileExists(discSetNum, fn)); } // ------------------------------------------------------------------------------------------------ - ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, supurious file size, delete file\n"); + ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, spurious file size, delete file\n"); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); @@ -440,7 +457,7 @@ int test(int argc, const char *argv[]) SaveDirectory("Test1/foreomizes/stemptinevidate/ict", dir); } int64_t duplicatedID = 0; - int64_t notSupriousFileSize = 0; + int64_t notSpuriousFileSize = 0; { BackupStoreDirectory dir; LoadDirectory("Test1/cannes/ict/peep", dir); @@ -458,7 +475,7 @@ int test(int argc, const char *argv[]) BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File); TEST_THAT(en != 0); - notSupriousFileSize = en->GetSizeInBlocks(); + notSpuriousFileSize = en->GetSizeInBlocks(); en->SetSizeInBlocks(3473874); TEST_THAT(en->GetSizeInBlocks() == 3473874); } @@ -471,7 +488,8 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is as it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 2") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 2") == 0); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); @@ -497,7 +515,7 @@ int test(int argc, const char *argv[]) BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File); TEST_THAT(en != 0); - TEST_THAT(en->GetSizeInBlocks() == notSupriousFileSize); + TEST_THAT(en->GetSizeInBlocks() == notSpuriousFileSize); } } @@ -527,7 +545,8 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is as it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 3") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 3") == 0); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); @@ -541,18 +560,22 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is where it is predicted to be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 4") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 4") == 0); // ------------------------------------------------------------------------------------------------ ::printf(" === Corrupt file and dir\n"); // File - CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge", 33, "34i729834298349283479233472983sdfhasgs"); + CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge", + 33, "34i729834298349283479233472983sdfhasgs"); // Dir - CorruptObject("Test1/cannes/imulatrougge/foreomizes", 23, "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf"); + CorruptObject("Test1/cannes/imulatrougge/foreomizes",23, + "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf"); // Fix it RUN_CHECK // Check everything is where it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 5") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 5") == 0); // ------------------------------------------------------------------------------------------------ ::printf(" === Overwrite root with a file\n"); @@ -566,13 +589,16 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is where it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl reroot 6") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl reroot 6") == 0); // ------------------------------------------------------------------------------------------------ // Stop server TEST_THAT(KillServer(pid)); - TestRemoteProcessMemLeaks("bbstored.memleaks"); + #ifndef WIN32 + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } return 0; diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 8e2fa5f6..4fbf296a 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" @@ -283,14 +284,6 @@ void test_depends_in_dirs() int test(int argc, const char *argv[]) { -#ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) -#endif - // Allocate a buffer buffer = ::malloc(BUFFER_SIZE); TEST_THAT(buffer != 0); @@ -317,9 +310,8 @@ int test(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // Create an account - TEST_THAT_ABORTONFAIL(RunCommand( - "../../bin/bbstoreaccounts/bbstoreaccounts " - "-c testfiles/bbstored.conf " + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf " "create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); @@ -330,7 +322,8 @@ int test(int argc, const char *argv[]) test_depends_in_dirs(); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { diff --git a/test/basicserver/TestCommands.cpp b/test/basicserver/TestCommands.cpp index b18a3326..657e79ea 100644 --- a/test/basicserver/TestCommands.cpp +++ b/test/basicserver/TestCommands.cpp @@ -1,7 +1,9 @@ #include "Box.h" +#ifdef HAVE_SYSLOG_H #include <syslog.h> +#endif #include "autogen_TestProtocolServer.h" #include "CollectInBufferStream.h" diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index 3360cd20..4b33f555 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" @@ -430,84 +431,139 @@ int test(int argc, const char *argv[]) } } -//printf("SKIPPING TESTS------------------------\n"); -//goto protocolserver; + //printf("SKIPPING TESTS------------------------\n"); + //goto protocolserver; // Launch a basic server { - int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid"); + int pid = LaunchServer("./test srv1 testfiles/srv1.conf", + "testfiles/srv1.pid"); + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Check that it's written the expected file - TEST_THAT(TestFileExists("testfiles/srv1.test1")); + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test1")); TEST_THAT(ServerIsAlive(pid)); + // Move the config file over - TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1); - // Get it to reread the config file - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); - // Check that new file exists - TEST_THAT(TestFileExists("testfiles/srv1.test2")); + #ifdef WIN32 + TEST_THAT(::unlink("testfiles" + DIRECTORY_SEPARATOR "srv1.conf") != -1); + #endif + + TEST_THAT(::rename( + "testfiles" DIRECTORY_SEPARATOR "srv1b.conf", + "testfiles" DIRECTORY_SEPARATOR "srv1.conf") + != -1); + + #ifndef WIN32 + // Get it to reread the config file + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + // Check that new file exists + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test2")); + #endif // !WIN32 + // Kill it off TEST_THAT(KillServer(pid)); - TestRemoteProcessMemLeaks("generic-daemon.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks( + "generic-daemon.memleaks"); + #endif // !WIN32 } } // Launch a test forking server { - int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid"); + int pid = LaunchServer("./test srv2 testfiles/srv2.conf", + "testfiles/srv2.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif // !WIN32 + // Make some connections { SocketStream conn1; conn1.Open(Socket::TypeINET, "localhost", 2003); - SocketStream conn2; - conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock"); - SocketStream conn3; - conn3.Open(Socket::TypeINET, "localhost", 2003); + + #ifndef WIN32 + SocketStream conn2; + conn2.Open(Socket::TypeUNIX, + "testfiles/srv2.sock"); + SocketStream conn3; + conn3.Open(Socket::TypeINET, + "localhost", 2003); + #endif // !WIN32 + // Quick check that reconnections fail - TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen); + TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, + "testfiles/srv2.sock");, + ServerException, SocketAlreadyOpen); + // Stuff some data around std::vector<IOStream *> conns; conns.push_back(&conn1); - conns.push_back(&conn2); - conns.push_back(&conn3); + + #ifndef WIN32 + conns.push_back(&conn2); + conns.push_back(&conn3); + #endif // !WIN32 + Srv2TestConversations(conns); // Implicit close } - // HUP again - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + // HUP again + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif // !WIN32 + // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv2.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv2.memleaks"); + #endif // !WIN32 } } // Launch a test SSL server { - int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid"); + int pid = LaunchServer("./test srv3 testfiles/srv3.conf", + "testfiles/srv3.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif + // Make some connections { // SSL library @@ -522,37 +578,60 @@ int test(int argc, const char *argv[]) SocketStreamTLS conn1; conn1.Open(context, Socket::TypeINET, "localhost", 2003); - SocketStreamTLS conn2; - conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock"); - SocketStreamTLS conn3; - conn3.Open(context, Socket::TypeINET, "localhost", 2003); + #ifndef WIN32 + SocketStreamTLS conn2; + conn2.Open(context, Socket::TypeUNIX, + "testfiles/srv3.sock"); + SocketStreamTLS conn3; + conn3.Open(context, Socket::TypeINET, + "localhost", 2003); + #endif + // Quick check that reconnections fail - TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen); + TEST_CHECK_THROWS(conn1.Open(context, + Socket::TypeUNIX, + "testfiles/srv3.sock");, + ServerException, SocketAlreadyOpen); + // Stuff some data around std::vector<IOStream *> conns; conns.push_back(&conn1); - conns.push_back(&conn2); - conns.push_back(&conn3); + + #ifndef WIN32 + conns.push_back(&conn2); + conns.push_back(&conn3); + #endif + Srv2TestConversations(conns); // Implicit close } - // HUP again - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + // HUP again + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif + // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv3.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv3.memleaks"); + #endif } } //protocolserver: // Launch a test protocol handling server { - int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid"); + int pid = LaunchServer("./test srv4 testfiles/srv4.conf", + "testfiles/srv4.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { ::sleep(1); @@ -560,7 +639,11 @@ int test(int argc, const char *argv[]) // Open a connection to it SocketStream conn; - conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); + #ifdef WIN32 + conn.Open(Socket::TypeINET, "localhost", 2003); + #else + conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); + #endif // Create a protocol TestProtocolClient protocol(conn); @@ -623,7 +706,10 @@ int test(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv4.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv4.memleaks"); + #endif } } diff --git a/test/basicserver/testfiles/srv4.conf b/test/basicserver/testfiles/srv4.conf index b4c5627c..f05dff75 100644 --- a/test/basicserver/testfiles/srv4.conf +++ b/test/basicserver/testfiles/srv4.conf @@ -1,6 +1,6 @@ Server { PidFile = testfiles/srv4.pid - ListenAddresses = unix:testfiles/srv4.sock + ListenAddresses = unix:testfiles/srv4.sock,inet:localhost } diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra new file mode 100644 index 00000000..1d3f5103 --- /dev/null +++ b/test/bbackupd/Makefile.extra @@ -0,0 +1 @@ +link-extra: ../../bin/bbackupd/autogen_ClientException.o ../../bin/bbackupd/BackupClientContext.o ../../bin/bbackupd/BackupClientDeleteList.o ../../bin/bbackupd/BackupClientDirectoryRecord.o ../../bin/bbackupd/Win32BackupService.o ../../bin/bbackupd/BackupClientInodeToIDMap.o ../../bin/bbackupd/Win32ServiceFunctions.o ../../bin/bbackupd/BackupDaemon.o diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 0aedb714..49b7f48a 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -9,38 +9,65 @@ #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> #include <limits.h> #include <string.h> -#include <sys/wait.h> #include <unistd.h> + +#ifdef HAVE_SYS_WAIT_H + #include <sys/wait.h> +#endif + #ifdef HAVE_SYS_XATTR_H -#include <cerrno> -#include <sys/xattr.h> + #include <cerrno> + #include <sys/xattr.h> #endif + #include <map> -#include "Test.h" +#ifdef HAVE_SYSCALL + #include <sys/syscall.h> +#endif + +#include "BackupClientCryptoKeys.h" #include "BackupClientFileAttributes.h" -#include "CommonException.h" +#include "BackupClientRestore.h" +#include "BackupDaemon.h" +#include "BackupDaemonConfigVerify.h" +#include "BackupStoreConstants.h" +#include "BackupStoreDirectory.h" #include "BackupStoreException.h" +#include "BoxPortsAndFiles.h" +#include "BoxTime.h" +#include "BoxTimeToUnix.h" +#include "CollectInBufferStream.h" +#include "CommonException.h" +#include "Configuration.h" #include "FileModificationTime.h" -#include "autogen_BackupProtocolClient.h" +#include "FileStream.h" +#include "IOStreamGetLine.h" +#include "LocalProcessStream.h" #include "SSLLib.h" -#include "TLSContext.h" -#include "SocketStreamTLS.h" -#include "BoxPortsAndFiles.h" -#include "BackupStoreConstants.h" +#include "ServerControl.h" #include "Socket.h" -#include "BackupClientRestore.h" -#include "BackupStoreDirectory.h" -#include "BackupClientCryptoKeys.h" -#include "CollectInBufferStream.h" +#include "SocketStreamTLS.h" +#include "TLSContext.h" +#include "Test.h" +#include "Timer.h" #include "Utils.h" -#include "BoxTime.h" -#include "BoxTimeToUnix.h" + +#include "autogen_BackupProtocolClient.h" +#include "intercept.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" @@ -54,18 +81,11 @@ void wait_for_backup_operation(int seconds = TIME_TO_WAIT_FOR_BACKUP_OPERATION) { - printf("waiting: "); - fflush(stdout); - for(int l = 0; l < seconds; ++l) - { - sleep(1); - printf("."); - fflush(stdout); - } - printf("\n"); + wait_for_operation(seconds); } int bbstored_pid = 0; +int bbackupd_pid = 0; #ifdef HAVE_SYS_XATTR_H bool readxattr_into_map(const char *filename, std::map<std::string,std::string> &rOutput) @@ -252,6 +272,9 @@ bool attrmatch(const char *f1, const char *f2) // if link, just make sure other file is a link too, and that the link to names match if((s1.st_mode & S_IFMT) == S_IFLNK) { +#ifdef WIN32 + TEST_FAIL_WITH_MESSAGE("No symlinks on win32!") +#else if((s2.st_mode & S_IFMT) != S_IFLNK) return false; char p1[PATH_MAX], p2[PATH_MAX]; @@ -262,6 +285,7 @@ bool attrmatch(const char *f1, const char *f2) p1[p1l] = '\0'; p2[p2l] = '\0'; return strcmp(p1, p2) == 0; +#endif } // modification times @@ -280,12 +304,15 @@ int test_basics() BackupClientFileAttributes t1; t1.ReadAttributes("testfiles/test1"); TEST_THAT(!t1.IsSymLink()); + +#ifndef WIN32 BackupClientFileAttributes t2; t2.ReadAttributes("testfiles/test2"); TEST_THAT(t2.IsSymLink()); // Check that it's actually been encrypted (search for symlink name encoded in it) void *te = ::memchr(t2.GetBuffer(), 't', t2.GetSize() - 3); TEST_THAT(te == 0 || ::memcmp(te, "test", 4) != 0); +#endif BackupClientFileAttributes t3; TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"), CommonException, OSFileError); @@ -298,13 +325,20 @@ int test_basics() // Apply attributes to these new files t1.WriteAttributes("testfiles/test1_n"); +#ifdef WIN32 + t1.WriteAttributes("testfiles/test2_n"); +#else t2.WriteAttributes("testfiles/test2_n"); +#endif + +#ifndef WIN32 TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"), CommonException, OSFileError); TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"), BackupStoreException, AttributesNotLoaded); - // Test that atttributes are vaguely similar + // Test that attributes are vaguely similar TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_n")); TEST_THAT(attrmatch("testfiles/test2", "testfiles/test2_n")); +#endif // Check encryption, and recovery from encryption // First, check that two attributes taken from the same thing have different encrypted values (think IV) @@ -377,18 +411,22 @@ int test_basics() int test_setupaccount() { - 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"); return 0; } int test_run_bbstored() { - bbstored_pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + std::string cmd = BBSTORED + bbstored_args + " testfiles/bbstored.conf"; + bbstored_pid = LaunchServer(cmd, "testfiles/bbstored.pid"); + TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0); + if(bbstored_pid > 0) { - ::sleep(1); + ::safe_sleep(1); TEST_THAT(ServerIsAlive(bbstored_pid)); return 0; // success } @@ -399,9 +437,13 @@ int test_run_bbstored() int test_kill_bbstored() { TEST_THAT(KillServer(bbstored_pid)); - ::sleep(1); + ::safe_sleep(1); TEST_THAT(!ServerIsAlive(bbstored_pid)); - TestRemoteProcessMemLeaks("bbstored.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif + return 0; } @@ -437,6 +479,7 @@ void terminate_on_alarm(int sigraised) abort(); } +#ifndef WIN32 void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) { int pid = 0; @@ -499,12 +542,216 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } } } +#endif // !WIN32 + +void force_sync() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "force-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void wait_for_sync_start() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "wait-for-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void wait_for_sync_end() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "wait-for-end") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void sync_and_wait() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "force-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +#ifdef WIN32 +bool set_file_time(const char* filename, FILETIME creationTime, + FILETIME lastModTime, FILETIME lastAccessTime) +{ + HANDLE handle = openfile(filename, O_RDWR, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + if (handle == INVALID_HANDLE_VALUE) return false; + + BOOL success = SetFileTime(handle, &creationTime, &lastAccessTime, + &lastModTime); + TEST_THAT(success); + + TEST_THAT(CloseHandle(handle)); + return success; +} +#endif + +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) +{ + BackupStoreDirectory::Iterator i(rDir); + BackupStoreFilenameClear child(rChildName.c_str()); + BackupStoreDirectory::Entry *en = i.FindMatchingClearName(child); + if (en == 0) return 0; + int64_t id = en->GetObjectID(); + TEST_THAT(id > 0); + TEST_THAT(id != BackupProtocolClientListDirectory::RootDirectory); + return id; +} + +int start_internal_daemon() +{ + // ensure that no child processes end up running tests! + int own_pid = getpid(); + + BackupDaemon daemon; + int result = daemon.Main("testfiles/bbackupd.conf"); + + 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 backup daemon to start: "); + int pid = -1; + + for (int i = 0; i < 30; i++) + { + printf("."); + fflush(stdout); + safe_sleep(1); + + if (TestFileExists("testfiles/bbackupd.pid")) + { + pid = ReadPidFile("testfiles/bbackupd.pid"); + } + + if (pid > 0) + { + break; + } + } + + printf(" done.\n"); + fflush(stdout); + + 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; @@ -515,39 +762,349 @@ int test_bbackupd() // unpack the files for the initial test TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0); - TEST_THAT(::system("mkdir testfiles/TestDir1") == 0); - TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); + TEST_THAT(::mkdir("testfiles/TestDir1", 0777) == 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("\n==== Skipping intercept-based KeepAlive tests " + "on this platform.\n"); +#else + printf("\n==== Testing SSL KeepAlive messages\n"); + + { + #ifdef WIN32 + #error TODO: implement threads on Win32, or this test \ + will not finish properly + #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)); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); + 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)); + comp = "Send StoreFile(0x3,"; + TEST_THAT(line.substr(0, comp.size()) == comp); + comp = ",\"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)); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); + 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)); + 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)); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); + 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)); + comp = "Send StoreFile(0x3,"; + TEST_THAT(line.substr(0, comp.size()) == comp); + comp = ",0x0,\"f1\")"; + TEST_THAT(line.substr(line.size() - comp.size()) + == comp); + } - int pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); - TEST_THAT(pid != -1 && pid != 0); - if(pid > 0) + 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 + + std::string cmd = BBACKUPD + bbackupd_args + " testfiles/bbackupd.conf"; + bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); + + TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + + ::safe_sleep(1); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + if(bbackupd_pid > 0) { - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + printf("\n==== Testing that backup pauses when store is full\n"); - // First, check storage space handling -- wait for file to be uploaded + // wait for files 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. - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 40B") == 0); + // 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. + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 9B 10B") + == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Unpack some more files - TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz " + "-C testfiles/TestDir1") == 0); + #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); wait_for_backup_operation(); // Make sure there are some differences - int compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query0a.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); + int compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query0a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Put the limit back - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 1000B 2000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 " + "1000B 2000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Check that the notify script was run @@ -556,185 +1113,1119 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); // unpack the initial files again - TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test_base.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif // wait for it to do it's stuff wait_for_backup_operation(); - // 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("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query1.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + // 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 -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + + printf("\n==== Check that read-only directories and " + "their contents can be restored.\n"); + + { + #ifdef WIN32 + TEST_THAT(::system("chmod 0555 testfiles/" + "TestDir1/x1") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/x1", + 0555) == 0); + #endif + + wait_for_sync_end(); // too new + wait_for_sync_end(); // should be backed up now + + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1 testfiles/TestDir1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // check that we can restore it + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"restore Test1 testfiles/restore1\" " + "quit"); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // check that it restored properly + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1 testfiles/restore1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // put the permissions back to sensible values + #ifdef WIN32 + TEST_THAT(::system("chmod 0755 testfiles/" + "TestDir1/x1") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/x1", + 0755) == 0); + #endif + + } + +#ifdef WIN32 + printf("\n==== Check that filenames in UTF-8 " + "can be backed up\n"); + + // We have no guarantee that a random Unicode string can be + // represented in the user's character set, so we go the + // other way, taking three random characters from the + // character set and converting them to Unicode. + // + // We hope that these characters are valid in most + // character sets, but they probably are not in multibyte + // character sets such as Shift-JIS, GB2312, etc. This test + // will probably fail if your system locale is set to + // Chinese, Japanese, etc. where one of these character + // sets is used by default. You can check the character + // set for your system in Control Panel -> Regional + // Options -> General -> Language Settings -> Set Default + // (System Locale). Because bbackupquery converts from + // system locale to UTF-8 via the console code page + // (which you can check from the Command Prompt with "chcp") + // they must also be valid in your code page (850 for + // Western Europe). + // + // In ISO-8859-1 (Danish locale) they are three Danish + // accented characters, which are supported in code page + // 850. Depending on your locale, YYMV (your yak may vomit). + + std::string foreignCharsNative("\x91\x9b\x86"); + std::string foreignCharsUnicode; + TEST_THAT(ConvertConsoleToUtf8(foreignCharsNative.c_str(), + foreignCharsUnicode)); + + std::string basedir("testfiles/TestDir1"); + std::string dirname("test" + foreignCharsUnicode + "testdir"); + std::string dirpath(basedir + "/" + dirname); + TEST_THAT(mkdir(dirpath.c_str(), 0) == 0); + + std::string filename("test" + foreignCharsUnicode + "testfile"); + std::string filepath(dirpath + "/" + filename); + + char cwdbuf[1024]; + TEST_THAT(getcwd(cwdbuf, sizeof(cwdbuf)) == cwdbuf); + std::string cwd = cwdbuf; + + // Test that our emulated chdir() works properly + // with relative and absolute paths + TEST_THAT(::chdir(dirpath.c_str()) == 0); + TEST_THAT(::chdir("../../..") == 0); + TEST_THAT(::chdir(cwd.c_str()) == 0); + + // Check that it can be converted to the system encoding + // (which is what is needed on the command line) + std::string systemDirName; + TEST_THAT(ConvertEncoding(dirname.c_str(), CP_UTF8, + systemDirName, CP_ACP)); + + std::string systemFileName; + TEST_THAT(ConvertEncoding(filename.c_str(), CP_UTF8, + systemFileName, CP_ACP)); + + // Check that it can be converted to the console encoding + // (which is what we will see in the output) + std::string consoleDirName; + TEST_THAT(ConvertUtf8ToConsole(dirname.c_str(), + consoleDirName)); + + std::string consoleFileName; + TEST_THAT(ConvertUtf8ToConsole(filename.c_str(), + consoleFileName)); + + // test that bbackupd will let us lcd into the local + // directory using a relative path + std::string command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd testfiles/TestDir1/" + systemDirName + "\" " + "quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and back out again + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd testfiles/TestDir1/" + systemDirName + "\" " + "\"lcd ..\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and using an absolute path + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd " + cwd + "/testfiles/TestDir1/" + + systemDirName + "\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and back out again + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd " + cwd + "/testfiles/TestDir1/" + + systemDirName + "\" " + "\"lcd ..\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + { + FileStream fs(filepath.c_str(), O_CREAT | O_RDWR); + + std::string data("hello world\n"); + fs.Write(data.c_str(), data.size()); + TEST_THAT(fs.GetPosition() == 12); + fs.Close(); + } + + wait_for_backup_operation(); + // Compare to check that the file was uploaded + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // Check that we can find it in directory listing + { + SocketStreamTLS conn; + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); + BackupProtocolClient protocol(conn); + protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); + protocol.QueryLogin(0x01234567, 0); + + int64_t rootDirId = BackupProtocolClientListDirectory + ::RootDirectory; + std::auto_ptr<BackupProtocolClientSuccess> dirreply( + protocol.QueryListDirectory( + rootDirId, false, 0, false)); + std::auto_ptr<IOStream> dirstream( + protocol.ReceiveStream()); + BackupStoreDirectory dir; + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); + + int64_t baseDirId = SearchDir(dir, "Test1"); + TEST_THAT(baseDirId != 0); + dirreply = protocol.QueryListDirectory(baseDirId, + false, 0, false); + dirstream = protocol.ReceiveStream(); + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); + + int64_t testDirId = SearchDir(dir, dirname.c_str()); + TEST_THAT(testDirId != 0); + dirreply = protocol.QueryListDirectory(testDirId, + false, 0, false); + dirstream = protocol.ReceiveStream(); + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); + + TEST_THAT(SearchDir(dir, filename.c_str()) != 0); + // Log out + protocol.QueryFinished(); + } + + + // Check that bbackupquery shows the dir in console encoding + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-q \"list Test1\" quit"; + pid_t bbackupquery_pid; + std::auto_ptr<IOStream> queryout; + queryout = LocalProcessStream(command.c_str(), + bbackupquery_pid); + TEST_THAT(queryout.get() != NULL); + TEST_THAT(bbackupquery_pid != -1); + + IOStreamGetLine reader(*queryout); + std::string line; + bool found = false; + while (!reader.IsEOF()) + { + TEST_THAT(reader.GetLine(line)); + if (line.find(consoleDirName) != std::string::npos) + { + found = true; + } + } + TEST_THAT(!(queryout->StreamDataLeft())); + TEST_THAT(reader.IsEOF()); + TEST_THAT(found); + queryout->Close(); + + // Check that bbackupquery can list the dir when given + // on the command line in system encoding, and shows + // the file in console encoding + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"list Test1/" + systemDirName + "\" quit"; + queryout = LocalProcessStream(command.c_str(), + bbackupquery_pid); + TEST_THAT(queryout.get() != NULL); + TEST_THAT(bbackupquery_pid != -1); + + IOStreamGetLine reader2(*queryout); + found = false; + while (!reader2.IsEOF()) + { + TEST_THAT(reader2.GetLine(line)); + if (line.find(consoleFileName) != std::string::npos) + { + found = true; + } + } + TEST_THAT(!(queryout->StreamDataLeft())); + TEST_THAT(reader2.IsEOF()); + TEST_THAT(found); + queryout->Close(); + + // Check that bbackupquery can compare the dir when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/TestDir1/" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + // Check that bbackupquery can restore the dir when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"restore Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 0); + + // Compare to make sure it was restored properly. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + std::string fileToUnlink = "testfiles/restore-" + + dirname + "/" + filename; + TEST_THAT(::unlink(fileToUnlink.c_str()) == 0); + + // Check that bbackupquery can get the file when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"get Test1/" + systemDirName + "/" + + systemFileName + " " + "testfiles/restore-" + + systemDirName + "/" + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // And after changing directory to a relative path + command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + "\"lcd testfiles\" " + "\"cd Test1/" + systemDirName + "\" " + + "\"get " + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks"); + + // cannot overwrite a file that exists, so delete it + std::string tmp = "testfiles/" + filename; + TEST_THAT(::unlink(tmp.c_str()) == 0); + + // And after changing directory to an absolute path + command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + "\"lcd " + cwd + "/testfiles\" " + "\"cd Test1/" + systemDirName + "\" " + + "\"get " + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks"); + + // Compare to make sure it was restored properly. + // The Get command does not restore attributes, so + // we must compare without them (-A) to succeed. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cAEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + // Compare without attributes. This should fail. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 2); +#endif // WIN32 + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Check that SyncAllowScript is executed and can " + "pause backup\n"); + fflush(stdout); + + { + wait_for_sync_end(); + // we now have 3 seconds before bbackupd + // runs the SyncAllowScript again. + + char* sync_control_file = "testfiles" + DIRECTORY_SEPARATOR "syncallowscript.control"; + int fd = open(sync_control_file, + O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd <= 0) + { + perror(sync_control_file); + } + TEST_THAT(fd > 0); - printf("Delete file and update another, create symlink.\n"); + char* control_string = "10\n"; + TEST_THAT(write(fd, control_string, + strlen(control_string)) == + (int)strlen(control_string)); + close(fd); + + // this will pause backups, bbackupd will check + // every 10 seconds to see if they are allowed again. + + char* new_test_file = "testfiles" + DIRECTORY_SEPARATOR "TestDir1" + DIRECTORY_SEPARATOR "Added_During_Pause"; + fd = open(new_test_file, + O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd <= 0) + { + perror(new_test_file); + } + TEST_THAT(fd > 0); + close(fd); + + struct stat st; + + // next poll should happen within the next + // 5 seconds (normally about 3 seconds) + + safe_sleep(1); // 2 seconds before + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.1", &st) != 0); + safe_sleep(4); // 2 seconds after + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.1", &st) == 0); + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) != 0); + + // next poll should happen within the next + // 10 seconds (normally about 8 seconds) + + safe_sleep(6); // 2 seconds before + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) != 0); + safe_sleep(4); // 2 seconds after + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) == 0); + + // check that no backup has run (compare fails) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + long start_time = time(NULL); + TEST_THAT(unlink(sync_control_file) == 0); + wait_for_sync_start(); + long end_time = time(NULL); + + long wait_time = end_time - start_time + 2; + // should be about 10 seconds + printf("Waited for %ld seconds, should have been %s", + wait_time, control_string); + TEST_THAT(wait_time >= 8); + TEST_THAT(wait_time <= 12); + + wait_for_sync_end(); + // check that backup has run (compare succeeds) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + } + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Delete file and update another, " + "create symlink.\n"); // Delete a file TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); - // New symlink - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/symlink-to-dir") == 0); - + + #ifndef WIN32 + // New symlink + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/symlink-to-dir") == 0); + #endif + // Update a file (will be uploaded as a diff) { - // Check that the file is over the diffing threshold in the bbackupd.conf file - TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024); + // Check that the file is over the diffing + // threshold in the bbackupd.conf file + TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") + > 1024); // Add a bit to the end FILE *f = ::fopen("testfiles/TestDir1/f45.df", "a"); TEST_THAT(f != 0); ::fprintf(f, "EXTRA STUFF"); ::fclose(f); - TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024); + TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") + > 1024); } // wait for backup daemon to do it's stuff, and compare again wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query2.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Try a quick compare, just for fun - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2q.log \"compare -acq\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query2q.log " + "\"compare -acqQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // Check that store errors are reported neatly + printf("\n==== Create store error\n"); + TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf", + "testfiles/0_0/backup/01234567/info.rf.bak") == 0); + TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf", + "testfiles/0_1/backup/01234567/info.rf.bak") == 0); + TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf", + "testfiles/0_2/backup/01234567/info.rf.bak") == 0); + // Create a file to trigger an upload + { + int fd1 = open("testfiles/TestDir1/force-upload", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(write(fd1, "just do it", 10) == 10); + TEST_THAT(close(fd1) == 0); + wait_for_backup_operation(4); + } + // Wait and test... + wait_for_backup_operation(); + // Check that it was reported correctly + TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1")); + // Check that the error was only reported once + TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2")); + // Fix the store + TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak", + "testfiles/0_0/backup/01234567/info.rf") == 0); + TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf.bak", + "testfiles/0_1/backup/01234567/info.rf") == 0); + TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak", + "testfiles/0_2/backup/01234567/info.rf") == 0); + + // Check that we DO get errors on compare + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // Wait until bbackupd recovers from the exception + wait_for_backup_operation(100); + + // Ensure that the force-upload file gets uploaded, + // meaning that bbackupd recovered + sync_and_wait(); + + // Check that it did get uploaded, and we have no more errors + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Bad case: delete a file/symlink, replace it with a directory - printf("Replace symlink with directory, add new directory\n"); - TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0); - TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) == 0); - TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); - // NOTE: create a file within the directory to avoid deletion by the housekeeping process later - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents") == 0); + printf("\n==== Replace symlink with directory, " + "add new directory\n"); + + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") + == 0); + #endif + + TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) + == 0); + TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) + == 0); + + // NOTE: create a file within the directory to + // avoid deletion by the housekeeping process later + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file/contents") + == 0); + #endif + wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3c.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // And the inverse, replace a directory with a file/symlink - printf("Replace directory with symlink\n"); - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents") == 0); + printf("\n==== Replace directory with symlink\n"); + + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file" + "/contents") == 0); + #endif + TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file") == 0); + #endif + wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3d.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // And then, put it back to how it was before. - printf("Replace symlink with directory (which was a symlink)\n"); - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file") == 0); - TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents2") == 0); + printf("\n==== Replace symlink with directory " + "(which was a symlink)\n"); + + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1" + "/dir-to-file") == 0); + #endif + + TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", + 0755) == 0); + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file/contents2") + == 0); + #endif + wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3e.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // And finally, put it back to how it was before it was put back to how it was before - // This gets lots of nasty things in the store with directories over other old directories. - printf("Put it all back to how it was\n"); - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // And finally, put it back to how it was before + // it was put back to how it was before + // This gets lots of nasty things in the store with + // directories over other old directories. + printf("\n==== Put it all back to how it was\n"); + + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file" + "/contents2") == 0); + #endif + TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file") == 0); + #endif + + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3f.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // rename an untracked file over an + // existing untracked file + printf("\n==== Rename over existing untracked file\n"); + int fd1 = open("testfiles/TestDir1/untracked-1", + O_CREAT | O_EXCL | O_WRONLY, 0700); + int fd2 = open("testfiles/TestDir1/untracked-2", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(fd2 > 0); + TEST_THAT(write(fd1, "hello", 5) == 5); + TEST_THAT(close(fd1) == 0); + safe_sleep(1); + TEST_THAT(write(fd2, "world", 5) == 5); + TEST_THAT(close(fd2) == 0); + TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-1")); + TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-2")); + wait_for_operation(5); + // back up both files wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3g.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // case which went wrong: rename a tracked file over a deleted file - printf("Rename an existing file over a deleted file\n"); - TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); + #ifdef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/untracked-2") + == 0); + #endif + + TEST_THAT(::rename("testfiles/TestDir1/untracked-1", + "testfiles/TestDir1/untracked-2") == 0); + TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1")); + TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2")); + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3g.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // case which went wrong: rename a tracked file over an + // existing tracked file + printf("\n==== Rename over existing tracked file\n"); + fd1 = open("testfiles/TestDir1/tracked-1", + O_CREAT | O_EXCL | O_WRONLY, 0700); + fd2 = open("testfiles/TestDir1/tracked-2", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(fd2 > 0); + char buffer[1024]; + TEST_THAT(write(fd1, "hello", 5) == 5); + TEST_THAT(write(fd1, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd1) == 0); + safe_sleep(1); + TEST_THAT(write(fd2, "world", 5) == 5); + TEST_THAT(write(fd2, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd2) == 0); + TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-1")); + TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-2")); + wait_for_operation(5); + // back up both files + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3h.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + #ifdef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/tracked-2") + == 0); + #endif + + TEST_THAT(::rename("testfiles/TestDir1/tracked-1", + "testfiles/TestDir1/tracked-2") == 0); + TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1")); + TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2")); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3i.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // case which went wrong: rename a tracked file + // over a deleted file + printf("\n==== Rename an existing file over a deleted file\n"); + TEST_THAT(!TestFileExists("testfiles/TestDir1/x1/dsfdsfs98.fd")); + TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", + "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); - printf("Add files with old times, update attributes of one to latest time\n"); + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3j.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Add files with old times, update " + "attributes of one to latest time\n"); // Move that file back - TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", "testfiles/TestDir1/df9834.dsf") == 0); + TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", + "testfiles/TestDir1/df9834.dsf") == 0); // Add some more files - // Because the 'm' option is not used, these files will look very old to the daemon. + // Because the 'm' option is not used, these files will + // look very old to the daemon. // Lucky it'll upload them then! - TEST_THAT(::system("gzip -d < testfiles/test2.tgz | ( cd testfiles && tar xf - )") == 0); - ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415); + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test2.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test2.tgz " + "| ( cd testfiles && tar xf - )") == 0); + ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415); + #endif // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3k.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // Check that modifying files with old timestamps still get added - printf("Modify existing file, but change timestamp to rather old\n"); - // Time critical, so sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); - // Then wait a second, to make sure the scan is complete - ::sleep(1); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // Check that modifying files with old timestamps + // still get added + printf("\n==== Modify existing file, but change timestamp " + "to rather old\n"); + wait_for_sync_end(); + // Then modify an existing file { - chmod("testfiles/TestDir1/sub23/rand.h", 0777); // in the archive, it's read only - FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", "w+"); + // in the archive, it's read only + #ifdef WIN32 + TEST_THAT(::system("chmod 0777 testfiles" + "/TestDir1/sub23/rand.h") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/sub23" + "/rand.h", 0777) == 0); + #endif + + FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", + "w+"); + + if (f == 0) + { + perror("Failed to open"); + } + TEST_THAT(f != 0); - fprintf(f, "MODIFIED!\n"); - fclose(f); + + if (f != 0) + { + fprintf(f, "MODIFIED!\n"); + fclose(f); + } + // and then move the time backwards! struct timeval times[2]; - BoxTimeToTimeval(SecondsToBoxTime((time_t)(365*24*60*60)), times[1]); + BoxTimeToTimeval(SecondsToBoxTime( + (time_t)(365*24*60*60)), times[1]); times[0] = times[1]; - TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", times) == 0); + TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", + times) == 0); } + // Wait and test - wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + wait_for_sync_end(); // files too new + wait_for_sync_end(); // should (not) be backed up this time + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3l.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Add some files and directories which are marked as excluded - printf("Add files and dirs for exclusion test\n"); - TEST_THAT(::system("gzip -d < testfiles/testexclude.tgz | ( cd testfiles && tar xf - )") == 0); + printf("\n==== Add files and dirs for exclusion test\n"); + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < " + "testfiles/testexclude.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif + // Wait and test - wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3c.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + wait_for_sync_end(); + wait_for_sync_end(); + + // compare with exclusions, should not find differences + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3m.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3d.log \"compare -acE\" quit"); - TEST_THAT(compareReturnValue == 2*256); // should find differences + + // compare without exclusions, should find differences + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3n.log " + "\"compare -acEQ\" quit"); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // check that the excluded files did not make it + // into the store, and the included files did + printf("\n==== Check that exclude/alwaysinclude commands " + "actually work\n"); + + { + std::string errs; + std::auto_ptr<Configuration> config( + Configuration::LoadAndVerify( + "testfiles/bbackupd.conf", + &BackupDaemonConfigVerify, errs)); + Configuration& conf(*config); + SSLLib::Initialise(); + TLSContext tlsContext; + std::string certFile(conf.GetKeyValue("CertificateFile")); + std::string keyFile (conf.GetKeyValue("PrivateKeyFile")); + std::string caFile (conf.GetKeyValue("TrustedCAsFile")); + tlsContext.Initialise(false, certFile.c_str(), + keyFile.c_str(), caFile.c_str()); + BackupClientCryptoKeys_Setup( + conf.GetKeyValue("KeysFile").c_str()); + SocketStreamTLS socket; + socket.Open(tlsContext, Socket::TypeINET, + conf.GetKeyValue("StoreHostname").c_str(), + BOX_PORT_BBSTORED); + BackupProtocolClient connection(socket); + connection.Handshake(); + std::auto_ptr<BackupProtocolClientVersion> + serverVersion(connection.QueryVersion( + BACKUP_STORE_SERVER_VERSION)); + if(serverVersion->GetVersion() != + BACKUP_STORE_SERVER_VERSION) + { + THROW_EXCEPTION(BackupStoreException, + WrongServerVersion); + } + connection.QueryLogin( + conf.GetKeyValueInt("AccountNumber"), + BackupProtocolClientLogin::Flags_ReadOnly); + + int64_t rootDirId = BackupProtocolClientListDirectory + ::RootDirectory; + std::auto_ptr<BackupProtocolClientSuccess> dirreply( + connection.QueryListDirectory( + rootDirId, false, 0, false)); + std::auto_ptr<IOStream> dirstream( + connection.ReceiveStream()); + BackupStoreDirectory dir; + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + + int64_t testDirId = SearchDir(dir, "Test1"); + TEST_THAT(testDirId != 0); + dirreply = connection.QueryListDirectory(testDirId, false, 0, false); + dirstream = connection.ReceiveStream(); + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + + TEST_THAT(!SearchDir(dir, "excluded_1")); + TEST_THAT(!SearchDir(dir, "excluded_2")); + TEST_THAT(!SearchDir(dir, "exclude_dir")); + TEST_THAT(!SearchDir(dir, "exclude_dir_2")); + // xx_not_this_dir_22 should not be excluded by + // ExcludeDirsRegex, because it's a file + TEST_THAT(SearchDir (dir, "xx_not_this_dir_22")); + TEST_THAT(!SearchDir(dir, "zEXCLUDEu")); + TEST_THAT(SearchDir (dir, "dont.excludethis")); + TEST_THAT(SearchDir (dir, "xx_not_this_dir_ALWAYSINCLUDE")); + + int64_t sub23id = SearchDir(dir, "sub23"); + TEST_THAT(sub23id != 0); + dirreply = connection.QueryListDirectory(sub23id, false, 0, false); + dirstream = connection.ReceiveStream(); + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + TEST_THAT(!SearchDir(dir, "xx_not_this_dir_22")); + TEST_THAT(!SearchDir(dir, "somefile.excludethis")); + connection.QueryFinished(); + } + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + +#ifndef WIN32 // These tests only work as non-root users. if(::getuid() != 0) { // Check that read errors are reported neatly - printf("Add unreadable files\n"); + printf("\n==== Add unreadable files\n"); + { // Dir and file which can't be read - TEST_THAT(::mkdir("testfiles/TestDir1/sub23/read-fail-test-dir", 0000) == 0); - int fd = ::open("testfiles/TestDir1/read-fail-test-file", O_CREAT | O_WRONLY, 0000); + TEST_THAT(::mkdir("testfiles/TestDir1/sub23" + "/read-fail-test-dir", 0000) == 0); + int fd = ::open("testfiles/TestDir1" + "/read-fail-test-file", + O_CREAT | O_WRONLY, 0000); TEST_THAT(fd != -1); ::close(fd); } + // Wait and test... wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); // should find differences + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3o.log " + "\"compare -acQ\" quit"); + + // should find differences + TEST_RETURN(compareReturnValue, 3); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1")); + + // Check that the error was only reported once TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); - // Set permissions on file and dir to stop errors in the future - ::chmod("testfiles/TestDir1/sub23/read-fail-test-dir", 0770); - ::chmod("testfiles/TestDir1/read-fail-test-file", 0770); + + // Set permissions on file and dir to stop + // errors in the future + TEST_THAT(::chmod("testfiles/TestDir1/sub23" + "/read-fail-test-dir", 0770) == 0); + TEST_THAT(::chmod("testfiles/TestDir1" + "/read-fail-test-file", 0770) == 0); } +#endif + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Continuously update file, check isn't uploaded\n"); + printf("\n==== Continuously update file, " + "check isn't uploaded\n"); - // Make sure everything happens at the same point in the sync cycle: wait until exactly the start of a sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); + // Make sure everything happens at the same point in the + // sync cycle: wait until exactly the start of a sync + wait_for_sync_start(); + // Then wait a second, to make sure the scan is complete - ::sleep(1); + ::safe_sleep(1); { // Open a file, then save something to it every second @@ -744,39 +2235,54 @@ int test_bbackupd() TEST_THAT(f != 0); fprintf(f, "Loop iteration %d\n", l); fflush(f); - sleep(1); + fclose(f); + printf("."); fflush(stdout); - ::fclose(f); + safe_sleep(1); } printf("\n"); + fflush(stdout); // Check there's a difference - compareReturnValue = ::system("testfiles/extcheck1.pl"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system("perl testfiles/" + "extcheck1.pl"); + + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - printf("Keep on continuously updating file, check it is uploaded eventually\n"); + printf("\n==== Keep on continuously updating file, " + "check it is uploaded eventually\n"); for(int l = 0; l < 28; ++l) { - FILE *f = ::fopen("testfiles/TestDir1/continousupdate", "w+"); + FILE *f = ::fopen("testfiles/TestDir1/" + "continousupdate", "w+"); TEST_THAT(f != 0); fprintf(f, "Loop 2 iteration %d\n", l); fflush(f); - sleep(1); + fclose(f); + printf("."); fflush(stdout); - ::fclose(f); + safe_sleep(1); } printf("\n"); + fflush(stdout); - compareReturnValue = ::system("testfiles/extcheck2.pl"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system("perl testfiles/" + "extcheck2.pl"); + + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } - printf("Delete directory, change attributes\n"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Delete directory, change attributes\n"); // Delete a directory TEST_THAT(::system("rm -rf testfiles/TestDir1/x1") == 0); @@ -785,109 +2291,288 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query4.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - printf("Restore files and directories\n"); + printf("\n==== Restore files and directories\n"); int64_t deldirid = 0; int64_t restoredirid = 0; { // connect and log in SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly)); + std::auto_ptr<BackupProtocolClientLoginConfirmed> + loginConf(protocol.QueryLogin(0x01234567, + BackupProtocolClientLogin::Flags_ReadOnly)); // Find the ID of the Test1 directory - restoredirid = GetDirID(protocol, "Test1", BackupProtocolClientListDirectory::RootDirectory); + restoredirid = GetDirID(protocol, "Test1", + BackupProtocolClientListDirectory::RootDirectory); TEST_THAT(restoredirid != 0); // Test the restoration - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-Test1", + true /* print progress dots */) + == Restore_Complete); - // Compare it - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query10.log \"compare -cE Test1 testfiles/restore-Test1\" quit"); - TEST_THAT(compareReturnValue == 1*256); - TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // On Win32 we can't open another connection + // to the server, so we'll compare later. // Make sure you can't restore a restored directory - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_TargetExists); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-Test1", + true /* print progress dots */) + == Restore_TargetExists); + + // Make sure you can't restore to a nonexistant path + printf("Try to restore to a path that doesn't exist\n"); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/no-such-path/subdir", + true /* print progress dots */) + == Restore_TargetPathNotFound); // Find ID of the deleted directory deldirid = GetDirID(protocol, "x1", restoredirid); TEST_THAT(deldirid != 0); - // Just check it doesn't bomb out -- will check this properly later (when bbackupd is stopped) - TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1", true /* print progress dots */, true /* deleted files */) == Restore_Complete); + // Just check it doesn't bomb out -- will check this + // properly later (when bbackupd is stopped) + TEST_THAT(BackupClientRestore(protocol, deldirid, + "testfiles/restore-Test1-x1", + true /* print progress dots */, + true /* deleted files */) + == Restore_Complete); // Log out protocol.QueryFinished(); } - printf("Add files with current time\n"); + // Compare the restored files + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + +#ifdef WIN32 + // make one of the files read-only, expect a compare failure + compareReturnValue = ::system("attrib +r " + "testfiles\\restore-Test1\\f1.dat"); + TEST_RETURN(compareReturnValue, 0); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // set it back, expect no failures + compareReturnValue = ::system("attrib -r " + "testfiles\\restore-Test1\\f1.dat"); + TEST_RETURN(compareReturnValue, 0); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // change the timestamp on a file, expect a compare failure + char* testfile = "testfiles\\restore-Test1\\f1.dat"; + HANDLE handle = openfile(testfile, O_RDWR, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + FILETIME creationTime, lastModTime, lastAccessTime; + TEST_THAT(GetFileTime(handle, &creationTime, &lastAccessTime, + &lastModTime) != 0); + TEST_THAT(CloseHandle(handle)); + + FILETIME dummyTime = lastModTime; + dummyTime.dwHighDateTime -= 100; + + // creation time is backed up, so changing it should cause + // a compare failure + TEST_THAT(set_file_time(testfile, dummyTime, lastModTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // last access time is not backed up, so it cannot be compared + TEST_THAT(set_file_time(testfile, creationTime, lastModTime, + dummyTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // last write time is backed up, so changing it should cause + // a compare failure + TEST_THAT(set_file_time(testfile, creationTime, dummyTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // set back to original values, check that compare succeeds + TEST_THAT(set_file_time(testfile, creationTime, lastModTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); +#endif // WIN32 + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Add files with current time\n"); // Add some more files and modify others // Use the m flag this time so they have a recent modification time - TEST_THAT(::system("gzip -d < testfiles/test3.tgz | ( cd testfiles && tar xmf - )") == 0); + #ifdef WIN32 + TEST_THAT(::system("tar xzvmf testfiles/test3.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test3.tgz " + "| ( cd testfiles && tar xmf - )") == 0); + #endif // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query5.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query5.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Rename directory - printf("Rename directory\n"); - TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); + printf("\n==== Rename directory\n"); + TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", + "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // and again, but with quick flag - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6q.log \"compare -acq\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6q.log " + "\"compare -acqQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Rename some files -- one under the threshold, others above - printf("Rename files\n"); - TEST_THAT(rename("testfiles/TestDir1/continousupdate", "testfiles/TestDir1/continousupdate-ren") == 0); - TEST_THAT(rename("testfiles/TestDir1/df324", "testfiles/TestDir1/df324-ren") == 0); - TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); + printf("\n==== Rename files\n"); + TEST_THAT(rename("testfiles/TestDir1/continousupdate", + "testfiles/TestDir1/continousupdate-ren") == 0); + TEST_THAT(rename("testfiles/TestDir1/df324", + "testfiles/TestDir1/df324-ren") == 0); + TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", + "testfiles/TestDir1/find2perl-ren") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // Check that modifying files with madly in the future timestamps still get added - printf("Create a file with timestamp to way ahead in the future\n"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // Check that modifying files with madly in the future + // timestamps still get added + printf("\n==== Create a file with timestamp way ahead " + "in the future\n"); + // Time critical, so sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); + wait_for_sync_start(); + // Then wait a second, to make sure the scan is complete - ::sleep(1); + ::safe_sleep(1); + // Then modify an existing file { - FILE *f = fopen("testfiles/TestDir1/sub23/in-the-future", "w"); + FILE *f = fopen("testfiles/TestDir1/sub23/" + "in-the-future", "w"); TEST_THAT(f != 0); fprintf(f, "Back to the future!\n"); fclose(f); // and then move the time forwards! struct timeval times[2]; - BoxTimeToTimeval(GetCurrentBoxTime() + SecondsToBoxTime((time_t)(365*24*60*60)), times[1]); + BoxTimeToTimeval(GetCurrentBoxTime() + + SecondsToBoxTime((time_t)(365*24*60*60)), + times[1]); times[0] = times[1]; - TEST_THAT(::utimes("testfiles/TestDir1/sub23/in-the-future", times) == 0); + TEST_THAT(::utimes("testfiles/TestDir1/sub23/" + "in-the-future", times) == 0); } + // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3e.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - printf("Change client store marker\n"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Change client store marker\n"); - // Then... connect to the server, and change the client store marker. See what that does! + // Then... connect to the server, and change the + // client store marker. See what that does! { bool done = false; int tries = 4; @@ -896,7 +2581,8 @@ int test_bbackupd() try { SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, + "localhost", BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write @@ -920,10 +2606,15 @@ int test_bbackupd() TEST_THAT(done); } - printf("Check change of store marker pauses daemon\n"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Check change of store marker pauses daemon\n"); - // Make a change to a file, to detect whether or not it's hanging around - // waiting to retry. + // Make a change to a file, to detect whether or not + // it's hanging around waiting to retry. { FILE *f = ::fopen("testfiles/TestDir1/fileaftermarker", "w"); TEST_THAT(f != 0); @@ -932,56 +2623,114 @@ int test_bbackupd() } // Wait and test that there *are* differences - wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); + wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION * + 3) / 2); // little bit longer than usual + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - - printf("Interrupted restore\n"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Waiting for bbackupd to recover\n"); + // 100 seconds - (12*3/2) + wait_for_operation(82); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + +#ifndef WIN32 + printf("\n==== Interrupted restore\n"); { do_interrupted_restore(context, restoredirid); int64_t resumesize = 0; - TEST_THAT(FileExists("testfiles/restore-interrupt.boxbackupresume", &resumesize)); - TEST_THAT(resumesize > 16); // make sure it has recorded something to resume + TEST_THAT(FileExists("testfiles/" + "restore-interrupt.boxbackupresume", + &resumesize)); + // make sure it has recorded something to resume + TEST_THAT(resumesize > 16); - printf("\nResume restore\n"); + printf("\n==== Resume restore\n"); SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write + std::auto_ptr<BackupProtocolClientLoginConfirmed> + loginConf(protocol.QueryLogin(0x01234567, + 0 /* read-write */)); - // Check that the restore fn returns resume possible, rather than doing anything - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */) == Restore_ResumePossible); + // Check that the restore fn returns resume possible, + // rather than doing anything + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-interrupt", + true /* print progress dots */) + == Restore_ResumePossible); // Then resume it - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */, false /* deleted files */, false /* undelete server */, true /* resume */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-interrupt", + true /* print progress dots */, + false /* deleted files */, + false /* undelete server */, + true /* resume */) + == Restore_Complete); protocol.QueryFinished(); // Then check it has restored the correct stuff - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query14.log \"compare -cE Test1 testfiles/restore-interrupt\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query14.log " + "\"compare -cEQ Test1 " + "testfiles/restore-interrupt\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } +#endif // !WIN32 + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Check restore deleted files\n"); - printf("Check restore deleted files\n"); { SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write + std::auto_ptr<BackupProtocolClientLoginConfirmed> + loginConf(protocol.QueryLogin(0x01234567, + 0 /* read-write */)); // Do restore and undelete - TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1-2", true /* print progress dots */, true /* deleted files */, true /* undelete on server */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, deldirid, + "testfiles/restore-Test1-x1-2", + true /* print progress dots */, + true /* deleted files */, + true /* undelete on server */) + == Restore_Complete); protocol.QueryFinished(); // Do a compare with the now undeleted files - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query11.log \"compare -cE Test1/x1 testfiles/restore-Test1-x1-2\" quit"); - TEST_THAT(compareReturnValue == 1*256); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query11.log " + "\"compare -cEQ Test1/x1 " + "testfiles/restore-Test1-x1-2\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -989,39 +2738,124 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + +#ifdef WIN32 + printf("\n==== Testing locked file behaviour:\n"); + + // Test that locked files cannot be backed up, + // and the appropriate error is reported. + // Wait for the sync to finish, so that we have time to work + wait_for_sync_start(); + // Now we have about three seconds to work + + handle = openfile("testfiles/TestDir1/lockedfile", + O_CREAT | O_EXCL | O_LOCK, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + if (handle != 0) + { + // first sync will ignore the file, it's too new + wait_for_sync_end(); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.1")); + + // this sync should try to back up the file, + // and fail, because it's locked + wait_for_sync_end(); + TEST_THAT(TestFileExists("testfiles/" + "notifyran.read-error.1")); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.2")); + + // now close the file and check that it is + // backed up on the next run. + CloseHandle(handle); + wait_for_sync_end(); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.2")); + + // compare, and check that it works + // reports the correct error message (and finishes) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query15a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // open the file again, compare and check that compare + // reports the correct error message (and finishes) + handle = openfile("testfiles/TestDir1/lockedfile", + O_LOCK, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + compareReturnValue = ::system(BBACKUPQUERY + " -q -c testfiles/bbackupd.conf " + "-l testfiles/query15.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 3); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // close the file again, check that compare + // works again + CloseHandle(handle); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query15a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + } +#endif + // Kill the daemon - TEST_THAT(KillServer(pid)); - ::sleep(1); - TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + terminate_bbackupd(bbackupd_pid); // Start it again - pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); - TEST_THAT(pid != -1 && pid != 0); - if(pid != -1 && pid != 0) + cmd = BBACKUPD + bbackupd_args + " testfiles/bbackupd.conf"; + bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); + + TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + if(bbackupd_pid != -1 && bbackupd_pid != 0) { - // Wait and comapre - wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + // Wait and compare (a little bit longer than usual) + wait_for_backup_operation( + (TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query4a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Kill it again - TEST_THAT(KillServer(pid)); - ::sleep(1); - TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + terminate_bbackupd(bbackupd_pid); } } // List the files on the server - ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/queryLIST.log \"list -rotdh\" quit"); + ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf " + "-l testfiles/queryLIST.log \"list -rotdh\" quit"); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - - if(::getuid() == 0) - { - ::printf("WARNING: This test was run as root. Some tests have been omitted.\n"); - } + + #ifndef WIN32 + if(::getuid() == 0) + { + ::printf("WARNING: This test was run as root. " + "Some tests have been omitted.\n"); + } + #endif return 0; } @@ -1035,7 +2869,13 @@ int test(int argc, const char *argv[]) BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); // Initial files - TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test_base.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif // Do the tests @@ -1049,7 +2889,12 @@ int test(int argc, const char *argv[]) if(r != 0) return r; r = test_bbackupd(); - if(r != 0) return r; + if(r != 0) + { + KillServer(bbackupd_pid); + KillServer(bbstored_pid); + return r; + } test_kill_bbstored(); diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in index 6d381d5b..ce5d5b7c 100644 --- a/test/bbackupd/testfiles/bbackupd.conf.in +++ b/test/bbackupd/testfiles/bbackupd.conf.in @@ -17,13 +17,16 @@ MaxUploadWait = 24 FileTrackingSizeThreshold = 1024 DiffingUploadSizeThreshold = 1024 -MaximumDiffingTime = 8 +MaximumDiffingTime = 3 +KeepAliveTime = 1 -ExtendedLogging = yes +ExtendedLogging = no +ExtendedLogFile = testfiles/bbackupd.log CommandSocket = testfiles/bbackupd.sock -NotifyScript = @PERL@ testfiles/notifyscript.pl +NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl +SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl Server { diff --git a/test/bbackupd/testfiles/extcheck1.pl.in b/test/bbackupd/testfiles/extcheck1.pl.in index edbacd0a..2a7c0e9a 100755 --- a/test/bbackupd/testfiles/extcheck1.pl.in +++ b/test/bbackupd/testfiles/extcheck1.pl.in @@ -1,7 +1,9 @@ #!@PERL@ use strict; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|") +my $flags = $ARGV[0] or ""; + +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; @@ -15,14 +17,23 @@ while(<IN>) next unless m/\S/; if(m/continousupdate/) { - $ret = 2 unless m/exists/; + unless (/exists/) + { + print "FAIL: continousupdate line does not match\n"; + $ret = 2; + } $seen = 1; } else { - $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/; + unless (/\AWARNING/ or /\ADifferences/ or /might be reason/ + or /probably due to file mod/) + { + print "FAIL: Summary line does not match\n"; + $ret = 2; + } } - print; + print "READ: $_"; } close IN; diff --git a/test/bbackupd/testfiles/extcheck2.pl.in b/test/bbackupd/testfiles/extcheck2.pl.in index 68baa045..c79bf414 100755 --- a/test/bbackupd/testfiles/extcheck2.pl.in +++ b/test/bbackupd/testfiles/extcheck2.pl.in @@ -1,7 +1,9 @@ #!@PERL@ use strict; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|") +my $flags = $ARGV[0] or ""; + +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; @@ -14,13 +16,23 @@ while(<IN>) next unless m/\S/; if(m/continousupdate/) { - $ret = 2 unless m/contents/ || m/attributes/; + unless (m/contents/ or m/attributes/) + { + print "FAIL: continuousupdate line does not match\n"; + $ret = 2; + } } else { - $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/; + unless (/\AWARNING/ or /\ADifferences/ or /might be reason/ + or /probably due to file mod/) + { + print "FAIL: summary line does not match\n"; + $ret = 2; + } } - print; + + print "READ: $_"; } close IN; diff --git a/test/bbackupd/testfiles/notifyscript.pl.in b/test/bbackupd/testfiles/notifyscript.pl.in index df0e5a2d..89741e46 100755 --- a/test/bbackupd/testfiles/notifyscript.pl.in +++ b/test/bbackupd/testfiles/notifyscript.pl.in @@ -1,4 +1,4 @@ -#!@PERL@ +#!@TARGET_PERL@ my $f = 'testfiles/notifyran.'.$ARGV[0].'.'; diff --git a/test/bbackupd/testfiles/syncallowscript.pl.in b/test/bbackupd/testfiles/syncallowscript.pl.in index af425e90..f2ef1171 100755 --- a/test/bbackupd/testfiles/syncallowscript.pl.in +++ b/test/bbackupd/testfiles/syncallowscript.pl.in @@ -1,4 +1,4 @@ -#!@PERL@ +#!@TARGET_PERL@ use strict; use warnings; diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index ce5cd931..eb057228 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -9,13 +9,16 @@ #include "Box.h" +#include <errno.h> #include <stdio.h> +#include <time.h> #include "Test.h" #include "Configuration.h" #include "FdGetLine.h" #include "Guards.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" #include "IOStreamGetLine.h" #include "NamedLock.h" #include "ReadGatherStream.h" @@ -24,6 +27,12 @@ #include "CommonException.h" #include "Conversion.h" #include "autogen_ConversionException.h" +#include "CollectInBufferStream.h" +#include "Archive.h" +#include "Timer.h" +#include "Logging.h" +#include "ZeroStream.h" +#include "PartialReadStream.h" #include "MemLeakFindOn.h" @@ -130,11 +139,139 @@ ConfigurationVerify verify = 0 }; +class TestLogger : public Logger +{ + private: + bool mTriggered; + Log::Level mTargetLevel; + + public: + TestLogger(Log::Level targetLevel) + : mTriggered(false), mTargetLevel(targetLevel) + { + Logging::Add(this); + } + ~TestLogger() + { + Logging::Remove(this); + } + + bool IsTriggered() { return mTriggered; } + void Reset() { mTriggered = false; } + + virtual bool Log(Log::Level level, const std::string& rFile, + int line, std::string& rMessage) + { + if (level == mTargetLevel) + { + mTriggered = true; + } + return true; + } + + virtual const char* GetType() { return "Test"; } + virtual void SetProgramName(const std::string& rProgramName) { } +}; + int test(int argc, const char *argv[]) { - // Test memory leak detection + // Test PartialReadStream and ReadGatherStream handling of files + // over 2GB (refs #2) + { + char buffer[8]; + + ZeroStream zero(0x80000003); + zero.Seek(0x7ffffffe, IOStream::SeekType_Absolute); + TEST_THAT(zero.GetPosition() == 0x7ffffffe); + TEST_THAT(zero.Read(buffer, 8) == 5); + TEST_THAT(zero.GetPosition() == 0x80000003); + TEST_THAT(zero.Read(buffer, 8) == 0); + zero.Seek(0, IOStream::SeekType_Absolute); + TEST_THAT(zero.GetPosition() == 0); + + char* buffer2 = new char [0x1000000]; + TEST_THAT(buffer2 != NULL); + + PartialReadStream part(zero, 0x80000002); + for (int i = 0; i < 0x80; i++) + { + int read = part.Read(buffer2, 0x1000000); + TEST_THAT(read == 0x1000000); + } + TEST_THAT(part.Read(buffer, 8) == 2); + TEST_THAT(part.Read(buffer, 8) == 0); + + delete [] buffer2; + + ReadGatherStream gather(false); + zero.Seek(0, IOStream::SeekType_Absolute); + int component = gather.AddComponent(&zero); + gather.AddBlock(component, 0x80000002); + TEST_THAT(gather.Read(buffer, 8) == 8); + } + + // Test self-deleting temporary file streams + { + std::string tempfile("testfiles/tempfile"); + TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), + CommonException, OSFileOpenError); + InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT); + + #ifdef WIN32 + // file is still visible under Windows + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it again should work + InvisibleTempFileStream fs2(tempfile.c_str()); + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it to create exclusively should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), + O_CREAT | O_EXCL), CommonException, OSFileOpenError); + + fs2.Close(); + #else + // file is not visible under Unix + TEST_THAT(!TestFileExists(tempfile.c_str())); + + // opening it again should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()), + CommonException, OSFileOpenError); + + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(!TestFileExists(tempfile.c_str())); + + // opening it to create exclusively should work + InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL); + TEST_THAT(!TestFileExists(tempfile.c_str())); + + fs4.Close(); + #endif + + fs.Close(); + fs3.Close(); + + // now that it's closed, it should be invisible on all platforms + TEST_THAT(!TestFileExists(tempfile.c_str())); + } + + // Test that memory leak detection doesn't crash + { + char *test = new char[1024]; + delete [] test; + MemBlockStream *s = new MemBlockStream(test,12); + delete s; + } + #ifdef BOX_MEMORY_LEAK_TESTING { + Timers::Cleanup(); + TEST_THAT(memleakfinder_numleaks() == 0); void *block = ::malloc(12); TEST_THAT(memleakfinder_numleaks() == 1); @@ -150,9 +287,85 @@ int test(int argc, const char *argv[]) TEST_THAT(memleakfinder_numleaks() == 1); delete [] test; TEST_THAT(memleakfinder_numleaks() == 0); + + Timers::Init(); } #endif // BOX_MEMORY_LEAK_TESTING + + // test main() initialises timers for us, so uninitialise them + Timers::Cleanup(); + + // Check that using timer methods without initialisation + // throws an assertion failure. Can only do this in debug mode + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), + CommonException, AssertFailed); + TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), + CommonException, AssertFailed); + #endif + + // TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, + AssertFailed); + #endif + // Check that we can initialise the timers + Timers::Init(); + + // Check that double initialisation throws an exception + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Init(), CommonException, + AssertFailed); + #endif + + // Check that we can clean up the timers + Timers::Cleanup(); + + // Check that double cleanup throws an exception + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, + AssertFailed); + #endif + + Timers::Init(); + + Timer t0(0); // should never expire + Timer t1(1); + Timer t2(2); + Timer t3(3); + + TEST_THAT(!t0.HasExpired()); + TEST_THAT(!t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + safe_sleep(1); + TEST_THAT(!t0.HasExpired()); + TEST_THAT(t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + safe_sleep(1); + TEST_THAT(!t0.HasExpired()); + TEST_THAT(t1.HasExpired()); + TEST_THAT(t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + t1 = Timer(1); + t2 = Timer(2); + TEST_THAT(!t0.HasExpired()); + TEST_THAT(!t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + + safe_sleep(1); + TEST_THAT(!t0.HasExpired()); + TEST_THAT(t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(t3.HasExpired()); + + // Leave timers initialised for rest of test. + // Test main() will cleanup after test finishes. static char *testfilelines[] = { @@ -537,7 +750,7 @@ int test(int argc, const char *argv[]) TEST_THAT(elist.SizeOfDefiniteList() == 4); // Add regex entries - #ifdef HAVE_REGEX_H + #ifdef HAVE_REGEX_SUPPORT elist.AddRegexEntries(std::string("[a-d]+\\.reg$" "\x01" "EXCLUDE" "\x01" "^exclude$")); elist.AddRegexEntries(std::string("")); TEST_CHECK_THROWS(elist.AddRegexEntries(std::string("[:not_valid")), CommonException, BadRegularExpression); @@ -569,7 +782,7 @@ int test(int argc, const char *argv[]) TEST_THAT(elist.IsExcluded("thingdefthree") == !CASE_SENSITIVE); - #ifdef HAVE_REGEX_H + #ifdef HAVE_REGEX_SUPPORT TEST_THAT(elist.IsExcluded(std::string("b.reg")) == true); TEST_THAT(elist.IsExcluded(std::string("B.reg")) == !CASE_SENSITIVE); TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == !CASE_SENSITIVE); @@ -583,9 +796,86 @@ int test(int argc, const char *argv[]) #endif #undef CASE_SENSITIVE + + TestLogger logger(Log::WARNING); + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo")); + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo/")); + TEST_THAT(logger.IsTriggered()); + logger.Reset(); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR)); + TEST_THAT(logger.IsTriggered()); + logger.Reset(); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR "bar\x01/foo")); + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR "bar\x01/foo" + DIRECTORY_SEPARATOR)); + TEST_THAT(logger.IsTriggered()); } test_conversions(); + // test that we can use Archive and CollectInBufferStream + // to read and write arbitrary types to a memory buffer + + { + CollectInBufferStream buffer; + ASSERT(buffer.GetPosition() == 0); + + { + Archive archive(buffer, 0); + ASSERT(buffer.GetPosition() == 0); + + archive.Write((bool) true); + archive.Write((bool) false); + archive.Write((int) 0x12345678); + archive.Write((int) 0x87654321); + archive.Write((int64_t) 0x0badfeedcafebabeLL); + archive.Write((uint64_t) 0xfeedfacedeadf00dLL); + archive.Write((uint8_t) 0x01); + archive.Write((uint8_t) 0xfe); + archive.Write(std::string("hello world!")); + archive.Write(std::string("goodbye cruel world!")); + } + + CollectInBufferStream buf2; + buf2.Write(buffer.GetBuffer(), buffer.GetSize()); + TEST_THAT(buf2.GetPosition() == buffer.GetSize()); + + buf2.SetForReading(); + TEST_THAT(buf2.GetPosition() == 0); + + { + Archive archive(buf2, 0); + TEST_THAT(buf2.GetPosition() == 0); + + bool b; + archive.Read(b); TEST_THAT(b == true); + archive.Read(b); TEST_THAT(b == false); + + int i; + archive.Read(i); TEST_THAT(i == 0x12345678); + archive.Read(i); TEST_THAT((unsigned int)i == 0x87654321); + + uint64_t i64; + archive.Read(i64); TEST_THAT(i64 == 0x0badfeedcafebabeLL); + archive.Read(i64); TEST_THAT(i64 == 0xfeedfacedeadf00dLL); + + uint8_t i8; + archive.Read(i8); TEST_THAT(i8 == 0x01); + archive.Read(i8); TEST_THAT(i8 == 0xfe); + + std::string s; + archive.Read(s); TEST_THAT(s == "hello world!"); + archive.Read(s); TEST_THAT(s == "goodbye cruel world!"); + + TEST_THAT(!buf2.StreamDataLeft()); + } + } + return 0; } diff --git a/test/raidfile/intercept.cpp b/test/raidfile/intercept.cpp deleted file mode 100644 index 6df344e1..00000000 --- a/test/raidfile/intercept.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// -------------------------------------------------------------------------- -// -// File -// Name: intercept.cpp -// Purpose: Syscall interception code for the raidfile test -// Created: 2003/07/22 -// -// -------------------------------------------------------------------------- - -#include "Box.h" - -#ifdef HAVE_SYS_SYSCALL_H - #include <sys/syscall.h> -#endif -#include <sys/types.h> -#include <unistd.h> -#include <sys/uio.h> -#include <errno.h> - -#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - -#if !defined(HAVE_SYSCALL) && !defined(HAVE___SYSCALL) && !defined(HAVE___SYSCALL_NEED_DEFN) - #define PLATFORM_NO_SYSCALL -#endif - -#ifdef PLATFORM_NO_SYSCALL - // For some reason, syscall just doesn't work on Darwin - // so instead, we build functions using assembler in a varient - // of the technique used in the Darwin Libc - extern "C" int - TEST_open(const char *path, int flags, mode_t mode); - extern "C" int - TEST_close(int d); - extern "C" ssize_t - TEST_write(int d, const void *buf, size_t nbytes); - extern "C" ssize_t - TEST_read(int d, void *buf, size_t nbytes); - extern "C" ssize_t - TEST_readv(int d, const struct iovec *iov, int iovcnt); - extern "C" off_t - TEST_lseek(int fildes, off_t offset, int whence); -#else - #ifdef HAVE___SYSCALL_NEED_DEFN - // Need this, not declared in syscall.h nor unistd.h - extern "C" off_t __syscall(quad_t number, ...); - #endif - #ifndef HAVE_SYSCALL - #undef syscall - #define syscall __syscall - #endif -#endif - -#include <string.h> -#include <stdio.h> - -#include "MemLeakFindOn.h" - -bool intercept_enabled = false; -const char *intercept_filename = 0; -int intercept_filedes = -1; -off_t intercept_errorafter = 0; -int intercept_errno = 0; -int intercept_syscall = 0; -off_t intercept_filepos = 0; - -#define SIZE_ALWAYS_ERROR -773 - -void intercept_clear_setup() -{ - intercept_enabled = false; - intercept_filename = 0; - intercept_filedes = -1; - intercept_errorafter = 0; - intercept_syscall = 0; - intercept_filepos = 0; -} - -bool intercept_triggered() -{ - return !intercept_enabled; -} - -void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror) -{ - TRACE4("Setup for error: %s, after %d, err %d, syscall %d\n", filename, errorafter, errortoreturn, syscalltoerror); - intercept_enabled = true; - intercept_filename = filename; - intercept_filedes = -1; - intercept_errorafter = errorafter; - intercept_syscall = syscalltoerror; - intercept_errno = errortoreturn; - intercept_filepos = 0; -} - -bool intercept_errornow(int d, int size, int syscallnum) -{ - if(intercept_filedes != -1 && d == intercept_filedes && syscallnum == intercept_syscall) - { - //printf("Checking for err, %d, %d, %d\n", d, size, syscallnum); - if(size == SIZE_ALWAYS_ERROR) - { - // Looks good for an error! - TRACE2("Returning error %d for syscall %d\n", intercept_errno, syscallnum); - return true; - } - // where are we in the file? - if(intercept_filepos >= intercept_errorafter || intercept_filepos >= ((off_t)intercept_errorafter - size)) - { - TRACE3("Returning error %d for syscall %d, file pos %d\n", intercept_errno, syscallnum, (int)intercept_filepos); - return true; - } - } - return false; // no error please! -} - -int intercept_reterr() -{ - intercept_enabled = false; - intercept_filename = 0; - intercept_filedes = -1; - intercept_errorafter = 0; - intercept_syscall = 0; - return intercept_errno; -} - -#define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \ - if(intercept_enabled) \ - { \ - if(intercept_errornow(D, S, CALL)) \ - { \ - errno = intercept_reterr(); \ - return FAILRES; \ - } \ - } - -extern "C" int -open(const char *path, int flags, mode_t mode) -{ - if(intercept_enabled) - { - if(intercept_syscall == SYS_open && strcmp(path, intercept_filename) == 0) - { - errno = intercept_reterr(); - return -1; - } - } -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_open(path, flags, mode); -#else - int r = syscall(SYS_open, path, flags, mode); -#endif - if(intercept_enabled && intercept_filedes == -1) - { - // Right file? - if(strcmp(intercept_filename, path) == 0) - { - intercept_filedes = r; - //printf("Found file to intercept, h = %d\n", r); - } - } - return r; -} - -extern "C" int -open64(const char *path, int flags, mode_t mode) -{ - // With _FILE_OFFSET_BITS set to 64 this should really use (flags | - // O_LARGEFILE) here, but not actually necessary for the tests and not - // worth the trouble finding O_LARGEFILE - return open(path, flags, mode); -} - -extern "C" int -close(int d) -{ - CHECK_FOR_FAKE_ERROR_COND(d, SIZE_ALWAYS_ERROR, SYS_close, -1); -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_close(d); -#else - int r = syscall(SYS_close, d); -#endif - if(r == 0) - { - if(d == intercept_filedes) - { - intercept_filedes = -1; - } - } - return r; -} - -extern "C" ssize_t -write(int d, const void *buf, size_t nbytes) -{ - CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_write, -1); -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_write(d, buf, nbytes); -#else - int r = syscall(SYS_write, d, buf, nbytes); -#endif - if(r != -1) - { - intercept_filepos += r; - } - return r; -} - -extern "C" ssize_t -read(int d, void *buf, size_t nbytes) -{ - CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_read, -1); -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_read(d, buf, nbytes); -#else - int r = syscall(SYS_read, d, buf, nbytes); -#endif - if(r != -1) - { - intercept_filepos += r; - } - return r; -} - -extern "C" ssize_t -readv(int d, const struct iovec *iov, int iovcnt) -{ - // how many bytes? - int nbytes = 0; - for(int b = 0; b < iovcnt; ++b) - { - nbytes += iov[b].iov_len; - } - - CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_readv, -1); -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_readv(d, iov, iovcnt); -#else - int r = syscall(SYS_readv, d, iov, iovcnt); -#endif - if(r != -1) - { - intercept_filepos += r; - } - return r; -} - -extern "C" off_t -lseek(int fildes, off_t offset, int whence) -{ - // random magic for lseek syscall, see /usr/src/lib/libc/sys/lseek.c - CHECK_FOR_FAKE_ERROR_COND(fildes, 0, SYS_lseek, -1); -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_lseek(fildes, offset, whence); -#else - #ifdef HAVE_LSEEK_DUMMY_PARAM - off_t r = syscall(SYS_lseek, fildes, 0 /* extra 0 required here! */, offset, whence); - #elif defined(_FILE_OFFSET_BITS) - // Don't bother trying to call SYS__llseek on 32 bit since it is - // fiddly and not needed for the tests - off_t r = syscall(SYS_lseek, fildes, (uint32_t)offset, whence); - #else - off_t r = syscall(SYS_lseek, fildes, offset, whence); - #endif -#endif - if(r != -1) - { - intercept_filepos = r; - } - return r; -} - -#endif // n PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE diff --git a/test/raidfile/testraidfile.cpp b/test/raidfile/testraidfile.cpp index 1e510486..40703de5 100644 --- a/test/raidfile/testraidfile.cpp +++ b/test/raidfile/testraidfile.cpp @@ -12,7 +12,10 @@ #include <fcntl.h> #include <unistd.h> #include <errno.h> + +#ifdef HAVE_SYSCALL #include <sys/syscall.h> +#endif #include <string.h> @@ -207,16 +210,24 @@ void testReadingFileContents(int set, const char *filename, void *data, int data bytesread += r; } TEST_THAT(!readstream4.StreamDataLeft()); // check IOStream interface is correct + pread.reset(); // Be nasty, and create some errors for the RAID stuff to recover from... if(TestRAIDProperties) { char stripe1fn[256], stripe1fnRename[256]; - sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename); - sprintf(stripe1fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, startDisc, filename); + sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename); + sprintf(stripe1fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, startDisc, + filename); char stripe2fn[256], stripe2fnRename[256]; - sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); - sprintf(stripe2fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); // Read with stripe1 + parity TEST_THAT(::rename(stripe2fn, stripe2fnRename) == 0); @@ -252,9 +263,15 @@ void testReadingFileContents(int set, const char *filename, void *data, int data } mungefilename[m++] = '\0'; char stripe1munge[256]; - sprintf(stripe1munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, startDisc, mungefilename); + sprintf(stripe1munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR ".raidfile-unreadable" + DIRECTORY_SEPARATOR "%s", set, startDisc, + mungefilename); char stripe2munge[256]; - sprintf(stripe2munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename); + sprintf(stripe2munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR ".raidfile-unreadable" + DIRECTORY_SEPARATOR "%s", set, + (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename); #ifdef TRF_CAN_INTERCEPT @@ -359,10 +376,12 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize write4.Write(data, datasize); // This time, don't discard and transform it to a RAID File char writefnPre[256]; - sprintf(writefnPre, "testfiles/%d_%d/%s.rfwX", set, startDisc, filename); + sprintf(writefnPre, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rfwX", set, startDisc, filename); TEST_THAT(TestFileExists(writefnPre)); char writefn[256]; - sprintf(writefn, "testfiles/%d_%d/%s.rfw", set, startDisc, filename); + sprintf(writefn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rfw", set, startDisc, filename); int usageInBlocks = write4.GetDiscUsageInBlocks(); write4.Commit(DoTransform); // Check that files are nicely done... @@ -390,14 +409,19 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize fs1 = ((fullblocks / 2)+1) * RAID_BLOCK_SIZE; } char stripe1fn[256]; - sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename); + sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename); TEST_THAT(TestGetFileSize(stripe1fn) == fs1); char stripe2fn[256]; - sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); TEST_THAT(TestGetFileSize(stripe2fn) == (int)(datasize - fs1)); // Parity file size char parityfn[256]; - sprintf(parityfn, "testfiles/%d_%d/%s.rf", set, (startDisc + 2) % RAID_NUMBER_DISCS, filename); + sprintf(parityfn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 2) % RAID_NUMBER_DISCS, filename); // Mildly complex calculation unsigned int blocks = datasize / RAID_BLOCK_SIZE; unsigned int bytesOver = datasize % RAID_BLOCK_SIZE; @@ -436,14 +460,16 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize if(datasize > (3*1024)) { int f; - TEST_THAT((f = ::open(stripe1fn, O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open(stripe1fn, O_RDONLY | O_BINARY, + 0)) != -1); TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock))); for(unsigned int q = 0; q < sizeof(testblock); ++q) { TEST_THAT(testblock[q] == ((char*)data)[q]); } ::close(f); - TEST_THAT((f = ::open(stripe2fn, O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open(stripe2fn, O_RDONLY | O_BINARY, + 0)) != -1); TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock))); for(unsigned int q = 0; q < sizeof(testblock); ++q) { @@ -536,7 +562,9 @@ void test_overwrites() // Generate a random pre-existing write file (and ensure that it doesn't exist already) int f; - TEST_THAT((f = ::open("testfiles/0_2/overwrite_B.rfwX", O_WRONLY | O_CREAT | O_EXCL, 0755)) != -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "overwrite_B.rfwX", + O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0755)) != -1); TEST_THAT(::write(f, "TESTTEST", 8) == 8); ::close(f); @@ -557,7 +585,7 @@ int test(int argc, const char *argv[]) // Initialise the controller RaidFileController &rcontroller = RaidFileController::GetController(); - rcontroller.Initialise("testfiles/raidfile.conf"); + rcontroller.Initialise("testfiles" DIRECTORY_SEPARATOR "raidfile.conf"); // some data char data[TEST_DATA_SIZE]; @@ -574,9 +602,12 @@ int test(int argc, const char *argv[]) // Try creating a directory RaidFileWrite::CreateDirectory(0, "test-dir"); - TEST_THAT(TestDirExists("testfiles/0_0/test-dir")); - TEST_THAT(TestDirExists("testfiles/0_1/test-dir")); - TEST_THAT(TestDirExists("testfiles/0_2/test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_1" + DIRECTORY_SEPARATOR "test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test-dir")); TEST_THAT(RaidFileRead::DirectoryExists(0, "test-dir")); TEST_THAT(!RaidFileRead::DirectoryExists(0, "test-dir-not")); @@ -608,9 +639,12 @@ int test(int argc, const char *argv[]) // Before it's deleted, check to see the contents are as expected int f; - TEST_THAT((f = ::open("testfiles/0_2/test1.rfwX", O_RDONLY, 0)) >= 0); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfwX", O_RDONLY | O_BINARY, 0)) + >= 0); char buffer[sizeof(data)]; - TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer)); + int bytes_read = ::read(f, buffer, sizeof(buffer)); + TEST_THAT(bytes_read == sizeof(buffer)); for(unsigned int l = 0; l < 1024; ++l) { TEST_THAT(buffer[l] == data[l]); @@ -624,7 +658,8 @@ int test(int argc, const char *argv[]) TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]); } TEST_THAT(::lseek(f, sizeof(data), SEEK_SET) == sizeof(buffer)); - TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer)); + bytes_read = ::read(f, buffer, sizeof(buffer)); + TEST_THAT(bytes_read == sizeof(buffer)); for(unsigned int l = 0; l < 1024; ++l) { TEST_THAT(buffer[l] == data[l]); @@ -635,7 +670,9 @@ int test(int argc, const char *argv[]) // Commit the data write1.Commit(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) >= 0); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + >= 0); ::close(f); // Now try and read it @@ -687,7 +724,9 @@ int test(int argc, const char *argv[]) write2.Write(data, sizeof(data)); // This time, discard it write2.Discard(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) == -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + == -1); // And leaving it there... RaidFileWrite writeLeave(0, "test1"); @@ -695,7 +734,9 @@ int test(int argc, const char *argv[]) writeLeave.Write(data, sizeof(data)); // This time, commit it writeLeave.Commit(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + != -1); ::close(f); // Then check that the thing will refuse to open it again. @@ -712,7 +753,8 @@ int test(int argc, const char *argv[]) write3b.Write(data + 3, sizeof(data) - 3); write3b.Commit(); // Test it - testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false /*TestRAIDProperties*/); + testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false + /* TestRAIDProperties */); // And once again, but this time making it a raid file RaidFileWrite write3c(0, "test1"); @@ -721,7 +763,8 @@ int test(int argc, const char *argv[]) write3c.Write(data + 7, sizeof(data) - 7); write3c.Commit(true); // make RAID // Test it - testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false /*TestRAIDProperties*/); + testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false + /*TestRAIDProperties*/); // Test opening a file which doesn't exist TEST_CHECK_THROWS( @@ -736,20 +779,23 @@ int test(int argc, const char *argv[]) w.Commit(true); // Try removing the parity file - TEST_THAT(::rename("testfiles/0_0/damage.rf", "testfiles/0_0/damage.rf-NT") == 0); + TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "damage.rf", + "testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "damage.rf-NT") == 0); { std::auto_ptr<RaidFileRead> pr0 = RaidFileRead::Open(0, "damage"); pr0->Read(buffer, sizeof(data)); } - TEST_THAT(::rename("testfiles/0_0/damage.rf-NT", "testfiles/0_0/damage.rf") == 0); - + TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf-NT", "testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); + // Delete one of the files - TEST_THAT(::unlink("testfiles/0_1/damage.rf") == 0); // stripe 1 + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "damage.rf") == 0); // stripe 1 #ifdef TRF_CAN_INTERCEPT // Open it and read... { - intercept_setup_error("testfiles/0_2/damage.rf", 0, EIO, SYS_read); // stripe 2 + intercept_setup_error("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "damage.rf", 0, EIO, SYS_read); // stripe 2 std::auto_ptr<RaidFileRead> pr1 = RaidFileRead::Open(0, "damage"); TEST_CHECK_THROWS( pr1->Read(buffer, sizeof(data)), @@ -761,7 +807,7 @@ int test(int argc, const char *argv[]) #endif //TRF_CAN_INTERCEPT // Delete another - TEST_THAT(::unlink("testfiles/0_0/damage.rf") == 0); // parity + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); // parity TEST_CHECK_THROWS( std::auto_ptr<RaidFileRead> pread2 = RaidFileRead::Open(0, "damage"), @@ -772,22 +818,22 @@ int test(int argc, const char *argv[]) { RaidFileWrite::CreateDirectory(0, "dirread"); // Make some contents - RaidFileWrite::CreateDirectory(0, "dirread/dfsdf1"); - RaidFileWrite::CreateDirectory(0, "dirread/ponwq2"); + RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "dfsdf1"); + RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "ponwq2"); { - RaidFileWrite w(0, "dirread/sdf9873241"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "sdf9873241"); w.Open(); w.Write(data, sizeof(data)); w.Commit(true); } { - RaidFileWrite w(0, "dirread/fsdcxjni3242"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "fsdcxjni3242"); w.Open(); w.Write(data, sizeof(data)); w.Commit(true); } { - RaidFileWrite w(0, "dirread/cskjnds3"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "cskjnds3"); w.Open(); w.Write(data, sizeof(data)); w.Commit(false); @@ -803,15 +849,15 @@ int test(int argc, const char *argv[]) TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_DirsOnly, names)); TEST_THAT(list_matches(names, dir_list1)); // Delete things - TEST_THAT(::unlink("testfiles/0_0/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list1)); // Delete something else so that it's not recoverable - TEST_THAT(::unlink("testfiles/0_1/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(false == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list1)); // And finally... - TEST_THAT(::unlink("testfiles/0_2/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list2)); } diff --git a/test/win32/testlibwin32.cpp b/test/win32/testlibwin32.cpp index ca2989d8..fb735c56 100644 --- a/test/win32/testlibwin32.cpp +++ b/test/win32/testlibwin32.cpp @@ -6,12 +6,214 @@ #ifdef WIN32 +#include <assert.h> +#include <AccCtrl.h> +#include <Aclapi.h> + #include "../../bin/bbackupd/BackupDaemon.h" #include "BoxPortsAndFiles.h" #include "emu.h" int main(int argc, char* argv[]) { + // ACL tests + char* exename = getenv("WINDIR"); + + PSID psidOwner; + PSID psidGroup; + PACL pDacl; + PSECURITY_DESCRIPTOR pSecurityDesc; + + DWORD result = GetNamedSecurityInfo( + exename, // pObjectName + SE_FILE_OBJECT, // ObjectType + DACL_SECURITY_INFORMATION | // SecurityInfo + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION, + &psidOwner, // ppsidOwner, + &psidGroup, // ppsidGroup, + &pDacl, // ppDacl, + NULL, // ppSacl, + &pSecurityDesc // ppSecurityDescriptor + ); + if (result != ERROR_SUCCESS) + { + printf("Error getting security info for '%s': error %d", + exename, result); + } + assert(result == ERROR_SUCCESS); + + char namebuf[1024]; + char domainbuf[1024]; + SID_NAME_USE nametype; + DWORD namelen = sizeof(namebuf); + DWORD domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, psidOwner, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("Owner:\n"); + printf("User name: %s\n", namebuf); + printf("Domain name: %s\n", domainbuf); + printf("Name type: %d\n", nametype); + printf("\n"); + + namelen = sizeof(namebuf); + domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, psidGroup, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("Group:\n"); + printf("User name: %s\n", namebuf); + printf("Domain name: %s\n", domainbuf); + printf("Name type: %d\n", nametype); + printf("\n"); + + ULONG numEntries; + PEXPLICIT_ACCESS pEntries; + result = GetExplicitEntriesFromAcl + ( + pDacl, // pAcl + &numEntries, // pcCountOfExplicitEntries, + &pEntries // pListOfExplicitEntries + ); + assert(result == ERROR_SUCCESS); + + printf("Found %lu explicit DACL entries for '%s'\n\n", + (unsigned long)numEntries, exename); + + for (ULONG i = 0; i < numEntries; i++) + { + EXPLICIT_ACCESS* pEntry = &(pEntries[i]); + printf("DACL entry %lu:\n", (unsigned long)i); + + DWORD perms = pEntry->grfAccessPermissions; + printf(" Access permissions: ", perms); + + #define PRINT_PERM(name) \ + if (perms & name) \ + { \ + printf(#name " "); \ + perms &= ~name; \ + } + + PRINT_PERM(FILE_ADD_FILE); + PRINT_PERM(FILE_ADD_SUBDIRECTORY); + PRINT_PERM(FILE_ALL_ACCESS); + PRINT_PERM(FILE_APPEND_DATA); + PRINT_PERM(FILE_CREATE_PIPE_INSTANCE); + PRINT_PERM(FILE_DELETE_CHILD); + PRINT_PERM(FILE_EXECUTE); + PRINT_PERM(FILE_LIST_DIRECTORY); + PRINT_PERM(FILE_READ_ATTRIBUTES); + PRINT_PERM(FILE_READ_DATA); + PRINT_PERM(FILE_READ_EA); + PRINT_PERM(FILE_TRAVERSE); + PRINT_PERM(FILE_WRITE_ATTRIBUTES); + PRINT_PERM(FILE_WRITE_DATA); + PRINT_PERM(FILE_WRITE_EA); + PRINT_PERM(STANDARD_RIGHTS_READ); + PRINT_PERM(STANDARD_RIGHTS_WRITE); + PRINT_PERM(SYNCHRONIZE); + PRINT_PERM(DELETE); + PRINT_PERM(READ_CONTROL); + PRINT_PERM(WRITE_DAC); + PRINT_PERM(WRITE_OWNER); + PRINT_PERM(MAXIMUM_ALLOWED); + PRINT_PERM(GENERIC_ALL); + PRINT_PERM(GENERIC_EXECUTE); + PRINT_PERM(GENERIC_WRITE); + PRINT_PERM(GENERIC_READ); + printf("\n"); + + if (perms) + { + printf(" Bits left over: %08x\n", perms); + } + assert(!perms); + + printf(" Access mode: "); + switch(pEntry->grfAccessMode) + { + case NOT_USED_ACCESS: + printf("NOT_USED_ACCESS\n"); break; + case GRANT_ACCESS: + printf("GRANT_ACCESS\n"); break; + case DENY_ACCESS: + printf("DENY_ACCESS\n"); break; + case REVOKE_ACCESS: + printf("REVOKE_ACCESS\n"); break; + case SET_AUDIT_SUCCESS: + printf("SET_AUDIT_SUCCESS\n"); break; + case SET_AUDIT_FAILURE: + printf("SET_AUDIT_FAILURE\n"); break; + default: + printf("Unknown (%08x)\n", pEntry->grfAccessMode); + } + + printf(" Trustee: "); + assert(pEntry->Trustee.pMultipleTrustee == NULL); + assert(pEntry->Trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE); + switch(pEntry->Trustee.TrusteeForm) + { + case TRUSTEE_IS_SID: + { + PSID trusteeSid = (PSID)(pEntry->Trustee.ptstrName); + + namelen = sizeof(namebuf); + domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, trusteeSid, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("SID of %s\\%s (%d)\n", domainbuf, namebuf, nametype); + } + break; + case TRUSTEE_IS_NAME: + printf("Name\n"); break; + case TRUSTEE_BAD_FORM: + printf("Bad form\n"); assert(0); + case TRUSTEE_IS_OBJECTS_AND_SID: + printf("Objects and SID\n"); break; + case TRUSTEE_IS_OBJECTS_AND_NAME: + printf("Objects and name\n"); break; + default: + printf("Unknown form\n"); assert(0); + } + + printf(" Trustee type: "); + switch(pEntry->Trustee.TrusteeType) + { + case TRUSTEE_IS_UNKNOWN: + printf("Unknown type.\n"); break; + case TRUSTEE_IS_USER: + printf("User\n"); break; + case TRUSTEE_IS_GROUP: + printf("Group\n"); break; + case TRUSTEE_IS_DOMAIN: + printf("Domain\n"); break; + case TRUSTEE_IS_ALIAS: + printf("Alias\n"); break; + case TRUSTEE_IS_WELL_KNOWN_GROUP: + printf("Well-known group\n"); break; + case TRUSTEE_IS_DELETED: + printf("Deleted account\n"); break; + case TRUSTEE_IS_INVALID: + printf("Invalid trustee type\n"); break; + case TRUSTEE_IS_COMPUTER: + printf("Computer\n"); break; + default: + printf("Unknown type %d\n", pEntry->Trustee.TrusteeType); + assert(0); + } + + printf("\n"); + } + + assert(LocalFree((HLOCAL)pEntries) == 0); + assert(LocalFree((HLOCAL)pSecurityDesc) == 0); + chdir("c:\\tmp"); openfile("test", O_CREAT, 0); struct stat ourfs; @@ -25,12 +227,11 @@ int main(int argc, char* argv[]) do { info = readdir(ourDir); - if ( info ) printf("File/Dir name is : %s\r\n", info->d_name); - - }while ( info != NULL ); + if (info) printf("File/Dir name is : %s\r\n", info->d_name); + } + while (info != NULL); closedir(ourDir); - } std::string diry("C:\\Projects\\boxbuild\\testfiles\\"); @@ -41,12 +242,12 @@ int main(int argc, char* argv[]) do { info = readdir(ourDir); - if ( info == NULL ) break; + if (info == NULL) break; std::string file(diry + info->d_name); stat(file.c_str(), &ourfs); - if ( info ) printf("File/Dir name is : %s\r\n", info->d_name); - - }while ( info != NULL ); + if (info) printf("File/Dir name is : %s\r\n", info->d_name); + } + while ( info != NULL ); closedir(ourDir); @@ -54,47 +255,70 @@ int main(int argc, char* argv[]) stat("c:\\windows", &ourfs); stat("c:\\autoexec.bat", &ourfs); - printf("Finished dir read"); -#if 0 - //remove - sleepycat include a version of getopt - mine never REALLY worked ! - //test our getopt function - std::string commline("-q -c fgfgfg -f -l hello"); + printf("Finished dir read\n"); - int c; - while((c = getopt(commline.size(), (char * const *)commline.c_str(), "qwc:l:")) != -1) + //test our getopt function + char * test_argv[] = { - printf("switch = %c, param is %s\r\n", c, optarg); - } -#endif + "foobar.exe", + "-qwc", + "-", + "-c", + "fgfgfg", + "-f", + "-l", + "hello", + "-", + "force-sync", + NULL + }; + int test_argc; + for (test_argc = 0; test_argv[test_argc]; test_argc++) { } + const char* opts = "qwc:l:"; + + assert(getopt(test_argc, test_argv, opts) == 'q'); + assert(getopt(test_argc, test_argv, opts) == 'w'); + assert(getopt(test_argc, test_argv, opts) == 'c'); + assert(strcmp(optarg, "-") == 0); + assert(getopt(test_argc, test_argv, opts) == 'c'); + assert(strcmp(optarg, "fgfgfg") == 0); + assert(getopt(test_argc, test_argv, opts) == '?'); + assert(optopt == 'f'); + assert(getopt(test_argc, test_argv, opts) == 'l'); + assert(strcmp(optarg, "hello") == 0); + assert(getopt(test_argc, test_argv, opts) == -1); + // assert(optopt == 0); // no more options + assert(strcmp(test_argv[optind], "-") == 0); + assert(strcmp(test_argv[optind+1], "force-sync") == 0); //end of getopt test //now test our statfs funct stat("c:\\cert.cer", &ourfs); - - char *timee; timee = ctime(&ourfs.st_mtime); - if ( S_ISREG(ourfs.st_mode)) + if (S_ISREG(ourfs.st_mode)) { - printf("is a normal file"); + printf("is a normal file\n"); } else { - printf("is a directory?"); + printf("is a directory?\n"); + exit(1); } - lstat("c:\\windows", &ourfs); + lstat(getenv("WINDIR"), &ourfs); if ( S_ISDIR(ourfs.st_mode)) { - printf("is a directory"); + printf("is a directory\n"); } else { - printf("is a file?"); + printf("is a file?\n"); + exit(1); } //test the syslog functions @@ -105,6 +329,7 @@ int main(int argc, char* argv[]) closelog(); + /* //first off get the path name for the default char buf[MAX_PATH]; @@ -112,7 +337,7 @@ int main(int argc, char* argv[]) std::string buffer(buf); std::string conf("-c " + buffer.substr(0,(buffer.find("win32test.exe"))) + "bbackupd.conf"); //std::string conf( "-c " + buffer.substr(0,(buffer.find("bbackupd.exe"))) + "bbackupd.conf"); - + */ return 0; } |