diff options
author | Reinhard Tartler <siretart@tauware.de> | 2009-04-02 14:02:56 +0200 |
---|---|---|
committer | Reinhard Tartler <siretart@tauware.de> | 2009-04-02 14:02:56 +0200 |
commit | 76089c3bb5b915241da6d2f8f8c34eb65a78be95 (patch) | |
tree | 6b9524a5277ab57762cb01e9ea14131401c44ef5 /test | |
parent | 76af1c5e724dc558506be411e85a21122aef840d (diff) | |
parent | a84d45498bd861c9225080232948a99c2e317bb8 (diff) |
merge new upstream version
Diffstat (limited to 'test')
23 files changed, 2492 insertions, 495 deletions
diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index a91d6dfe..816f50d1 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -64,7 +64,7 @@ bool files_identical(const char *file1, const char *file2) return true; } -void make_file_of_zeros(const char *filename, size_t size) +bool make_file_of_zeros(const char *filename, size_t size) { #ifdef WIN32 HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0); @@ -75,7 +75,9 @@ void make_file_of_zeros(const char *filename, size_t size) BOOL result = SetEndOfFile(handle); if (result != TRUE) { - printf("Error %u\n", GetLastError()); + BOX_ERROR("Failed to create large file " << filename << + " (" << (size >> 20) << " MB): " << + GetErrorMessage(GetLastError())); } TEST_THAT(result == TRUE); TEST_THAT(CloseHandle(handle) == TRUE); @@ -87,7 +89,16 @@ void make_file_of_zeros(const char *filename, size_t size) TEST_THAT(close(fd) == 0); #endif - TEST_THAT((size_t)TestGetFileSize(filename) == size); + bool correct_size = ((size_t)TestGetFileSize(filename) == size); + TEST_THAT(correct_size); + if (!correct_size) + { + BOX_ERROR("Failed to create large file " << filename << + " (" << (size >> 20) << " MB): " << + "got " << (TestGetFileSize(filename) >> 20) << + " MB instead"); + } + return correct_size; } @@ -110,8 +121,10 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block TEST_THAT((uint64_t)box_ntoh64(hdr.mOtherFileID) == (uint64_t)OtherFileID); // number of blocks int64_t nblocks = box_ntoh64(hdr.mNumBlocks); - TRACE2("Reading index from '%s', has %lld blocks\n", filename, nblocks); - TRACE0("======== ===== ========== ======== ========\n Index Where EncSz/Idx Size WChcksm\n"); + BOX_TRACE("Reading index from '" << filename << "', has " << + nblocks << " blocks"); + BOX_TRACE("======== ===== ========== ======== ========"); + BOX_TRACE(" Index Where EncSz/Idx Size WChcksm"); // Read them all in int64_t nnew = 0, nold = 0; for(int64_t b = 0; b < nblocks; ++b) @@ -119,35 +132,36 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block file_BlockIndexEntry en; TEST_THAT(enc.ReadFullBuffer(&en, sizeof(en), 0)); int64_t s = box_ntoh64(en.mEncodedSize); + + // Decode the rest + uint64_t iv = box_ntoh64(hdr.mEntryIVBase); + iv += b; + sBlowfishDecryptBlockEntry.SetIV(&iv); + file_BlockIndexEntryEnc entryEnc; + sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, + sizeof(entryEnc), en.mEnEnc, sizeof(en.mEnEnc)); + + if(s > 0) { nnew++; - #ifdef WIN32 - TRACE2("%8I64d this s=%8I64d", b, s); - #else - TRACE2("%8lld this s=%8lld", b, s); - #endif + BOX_TRACE(std::setw(8) << b << " this s=" << + std::setw(8) << s << " " << + std::setw(8) << ntohl(entryEnc.mSize) << " " << + std::setw(8) << std::setfill('0') << + std::hex << ntohl(entryEnc.mWeakChecksum)); } else { nold++; - #ifdef WIN32 - TRACE2("%8I64d other i=%8I64d", b, 0 - s); - #else - TRACE2("%8lld other i=%8lld", b, 0 - s); - #endif + BOX_TRACE(std::setw(8) << b << " other i=" << + std::setw(8) << (0-s) << " " << + std::setw(8) << ntohl(entryEnc.mSize) << " " << + std::setw(8) << std::setfill('0') << + std::hex << ntohl(entryEnc.mWeakChecksum)); } - // Decode the rest - uint64_t iv = box_ntoh64(hdr.mEntryIVBase); - iv += b; - sBlowfishDecryptBlockEntry.SetIV(&iv); - file_BlockIndexEntryEnc entryEnc; - sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc), - en.mEnEnc, sizeof(en.mEnEnc)); - TRACE2(" %8d %08x\n", ntohl(entryEnc.mSize), ntohl(entryEnc.mWeakChecksum)); - } - TRACE0("======== ===== ========== ======== ========\n"); + BOX_TRACE("======== ===== ========== ======== ========"); TEST_THAT(new_blocks_expected == nnew); TEST_THAT(old_blocks_expected == nold); } @@ -374,7 +388,7 @@ void test_combined_diffs() int test(int argc, const char *argv[]) { // Want to trace out all the details - #ifndef NDEBUG + #ifndef BOX_RELEASE_BUILD #ifndef WIN32 BackupStoreFile::TraceDetailsOfDiffProcess = true; #endif @@ -512,13 +526,20 @@ int test(int argc, const char *argv[]) // found. Check this out! #ifdef WIN32 - ::fprintf(stdout, "Testing diffing two large streams, " - "may take a while!\n"); - ::fflush(stdout); + BOX_WARNING("Testing diffing two large streams, may take a while!"); + ::fflush(stderr); #endif - make_file_of_zeros("testfiles/zero.0", 20*1024*1024); - make_file_of_zeros("testfiles/zero.1", 200*1024*1024); + if (!make_file_of_zeros("testfiles/zero.0", 20*1024*1024)) + { + return 1; + } + + if (!make_file_of_zeros("testfiles/zero.1", 200*1024*1024)) + { + remove("testfiles/zero.0"); + return 1; + } // Generate a first encoded file { diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index a5eacc7d..0266d097 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -72,7 +72,7 @@ static const char *ens_filenames[] = {"obj1ertewt", "obj2", "obj3", "obj4dfedfg4 typedef struct { - char *fnextra; + const char *fnextra; BackupStoreFilenameClear name; int seed; int size; @@ -232,7 +232,8 @@ int test1(int argc, const char *argv[]) TEST_THAT(fn1 == fn3); // Check that it's been encrypted - TEST_THAT(fn2.find("name") == fn2.npos); + std::string name(fn2.GetEncodedFilename()); + TEST_THAT(name.find("name") == name.npos); // Bung it in a stream, get it out in a Clear filename { @@ -974,6 +975,9 @@ int test_server(const char *hostname) test_server_1(protocol, protocolReadOnly); + // sleep to ensure that the timestamp on the file will change + ::safe_sleep(1); + // Create and upload some test files int64_t maxID = 0; for(int t = 0; t < UPLOAD_NUM; ++t) @@ -1048,11 +1052,16 @@ int test_server(const char *hostname) StreamableMemBlock attrtest(attr3, sizeof(attr3)); // Use the read only connection to verify that the directory is as we expect + printf("\n\n==== Reading directory using read-only connection\n"); check_dir_after_uploads(protocolReadOnly, attrtest); + printf("done.\n\n"); // And on the read/write one check_dir_after_uploads(protocol, attrtest); } + // sleep to ensure that the timestamp on the file will change + ::safe_sleep(1); + // Check diffing and rsync like stuff... // Build a modified file { @@ -1149,6 +1158,8 @@ int test_server(const char *hostname) *upload)); subdirfileid = stored->GetObjectID(); } + + printf("\n==== Checking upload using read-only connection\n"); // Check the directories on the read only connection { // Command @@ -1181,6 +1192,7 @@ int test_server(const char *hostname) TEST_THAT(en->GetObjectID() == subdirid); TEST_THAT(en->GetModificationTime() == 0); // dirs don't have modification times. } + { // Command std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory( @@ -1211,6 +1223,7 @@ int test_server(const char *hostname) StreamableMemBlock attr(attr1, sizeof(attr1)); TEST_THAT(dir.GetAttributes() == attr); } + printf("done.\n\n"); // Check that we don't get attributes if we don't ask for them { @@ -1258,6 +1271,9 @@ int test_server(const char *hostname) TEST_THAT(dir.GetAttributes() == attrtest); } + // sleep to ensure that the timestamp on the file will change + ::safe_sleep(1); + // Test moving a file { BackupStoreFilenameClear newName("moved-files"); @@ -1281,9 +1297,6 @@ int test_server(const char *hostname) ConnectionException, Conn_Protocol_UnexpectedReply); } - // sleep to ensure that the timestamp on the file will change - ::safe_sleep(1); - // Rename within a directory { BackupStoreFilenameClear newName("moved-files-x"); @@ -1342,6 +1355,9 @@ int test_server(const char *hostname) TEST_THAT(foundOld); } + // sleep to ensure that the timestamp on the file will change + ::safe_sleep(1); + // make a little bit more of a thing to look at int64_t subsubdirid = 0; int64_t subsubfileid = 0; @@ -1763,9 +1779,12 @@ int test3(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 - TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif + + #ifdef WIN32 + TEST_THAT(unlink("testfiles/bbstored.pid") == 0); + #else + 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 @@ -1857,9 +1876,11 @@ int test3(int argc, const char *argv[]) ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 - TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif + #ifdef WIN32 + TEST_THAT(unlink("testfiles/bbstored.pid") == 0); + #else + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } return 0; @@ -1896,9 +1917,12 @@ int multi_server() TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 - TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif + + #ifdef WIN32 + TEST_THAT(unlink("testfiles/bbstored.pid") == 0); + #else + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 34565bd5..2d4ce052 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -338,7 +338,7 @@ int test(int argc, const char *argv[]) } // Generate a list of all the object IDs - TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -q " + TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -Wwarning " "-c testfiles/bbackupd.conf \"list -r\" quit " "> testfiles/initial-listing.txt") == 0); @@ -598,10 +598,13 @@ int test(int argc, const char *argv[]) " testfiles/testbackupstorefix.pl reroot 6") == 0); - // ------------------------------------------------------------------------------------------------ + // --------------------------------------------------------- // Stop server TEST_THAT(KillServer(pid)); - #ifndef WIN32 + + #ifdef WIN32 + TEST_THAT(unlink("testfiles/bbstored.pid") == 0); + #else TestRemoteProcessMemLeaks("bbstored.memleaks"); #endif } diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in index e64474f0..d27c1106 100755 --- a/test/backupstorefix/testfiles/testbackupstorefix.pl.in +++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in @@ -93,8 +93,12 @@ elsif($ARGV[0] eq 'check') } # read in the new listing, and compare - open LISTING,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit |" or die "Can't open list utility"; - open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' or die "can't open copy listing file"; + open LISTING,"../../bin/bbackupquery/bbackupquery -Wwarning " . + "-c testfiles/bbackupd.conf " . + "\"list -r\" quit |" + or die "Can't open list utility"; + open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' + or die "can't open copy listing file"; my $err = 0; while(<LISTING>) { @@ -125,8 +129,12 @@ elsif($ARGV[0] eq 'check') } elsif($ARGV[0] eq 'reroot') { - open LISTING,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit |" or die "Can't open list utility"; - open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' or die "can't open copy listing file"; + open LISTING,"../../bin/bbackupquery/bbackupquery -Wwarning " . + "-c testfiles/bbackupd.conf " . + "\"list -r\" quit |" + or die "Can't open list utility"; + open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' + or die "can't open copy listing file"; my $err = 0; my $count = 0; while(<LISTING>) diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index 18329441..18bc0aa8 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -185,7 +185,7 @@ const ConfigurationVerify *testserver::GetConfigVerify() const { static ConfigurationVerifyKey verifyserverkeys[] = { - SERVERSTREAM_VERIFY_SERVER_KEYS(0) // no default addresses + SERVERSTREAM_VERIFY_SERVER_KEYS(ConfigurationVerifyKey::NoDefaultValue) // no default listen addresses }; static ConfigurationVerify verifyserver[] = @@ -258,7 +258,7 @@ const ConfigurationVerify *testTLSserver::GetConfigVerify() const { static ConfigurationVerifyKey verifyserverkeys[] = { - SERVERTLS_VERIFY_SERVER_KEYS(0) // no default listen addresses + SERVERTLS_VERIFY_SERVER_KEYS(ConfigurationVerifyKey::NoDefaultValue) // no default listen addresses }; static ConfigurationVerify verifyserver[] = diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra index 1d3f5103..0ae56bd1 100644 --- a/test/bbackupd/Makefile.extra +++ b/test/bbackupd/Makefile.extra @@ -1 +1,14 @@ -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 +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 \ + ../../bin/bbstored/BackupStoreContext.o \ + ../../bin/bbstored/BBStoreDHousekeeping.o \ + ../../bin/bbstored/HousekeepStoreAccount.o \ + ../../bin/bbstored/autogen_BackupProtocolServer.o \ + ../../bin/bbstored/BackupCommands.o \ + ../../bin/bbstored/BackupStoreDaemon.o diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index a0732c21..9d82a11b 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -32,18 +32,26 @@ #include <sys/xattr.h> #endif +#ifdef HAVE_SIGNAL_H + #include <signal.h> +#endif + #include <map> #ifdef HAVE_SYSCALL #include <sys/syscall.h> #endif +#include "autogen_BackupProtocolServer.h" #include "BackupClientCryptoKeys.h" #include "BackupClientFileAttributes.h" #include "BackupClientRestore.h" #include "BackupDaemon.h" #include "BackupDaemonConfigVerify.h" +#include "BackupQueries.h" #include "BackupStoreConstants.h" +#include "BackupStoreContext.h" +#include "BackupStoreDaemon.h" #include "BackupStoreDirectory.h" #include "BackupStoreException.h" #include "BoxPortsAndFiles.h" @@ -79,27 +87,6 @@ // two cycles and a bit #define TIME_TO_WAIT_FOR_BACKUP_OPERATION 12 -// utility macro for comparing two strings in a line -#define TEST_EQUAL(expected, found, line) \ -{ \ - std::string exp_str = expected; \ - std::string found_str = found; \ - TEST_THAT(exp_str == found_str); \ - if(exp_str != found_str) \ - { \ - printf("Expected <%s> but found <%s> in <%s>\n", \ - exp_str.c_str(), found_str.c_str(), line.c_str()); \ - } \ -} - -// utility macro for testing a line -#define TEST_LINE(condition, line) \ - TEST_THAT(condition); \ - if (!(condition)) \ - { \ - printf("Test failed on <%s>\n", line.c_str()); \ - } - void wait_for_backup_operation(int seconds = TIME_TO_WAIT_FOR_BACKUP_OPERATION) { wait_for_operation(seconds); @@ -271,9 +258,9 @@ void finish_with_write_xattr_test() bool attrmatch(const char *f1, const char *f2) { - struct stat s1, s2; - TEST_THAT(::lstat(f1, &s1) == 0); - TEST_THAT(::lstat(f2, &s2) == 0); + EMU_STRUCT_STAT s1, s2; + TEST_THAT(EMU_LSTAT(f1, &s1) == 0); + TEST_THAT(EMU_LSTAT(f2, &s2) == 0); #ifdef HAVE_SYS_XATTR_H { @@ -336,7 +323,11 @@ int test_basics() #endif BackupClientFileAttributes t3; - TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"), CommonException, OSFileError); + { + Logging::Guard guard(Log::ERROR); + TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"), + CommonException, OSFileError); + } // Create some more files FILE *f = fopen("testfiles/test1_n", "w"); @@ -353,8 +344,13 @@ int test_basics() #endif #ifndef WIN32 - TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"), CommonException, OSFileError); - TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"), BackupStoreException, AttributesNotLoaded); + { + Logging::Guard guard(Log::ERROR); + TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"), + CommonException, OSFileError); + TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"), + BackupStoreException, AttributesNotLoaded); + } // Test that attributes are vaguely similar TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_n")); @@ -440,7 +436,8 @@ int test_setupaccount() int test_run_bbstored() { - std::string cmd = BBSTORED + bbstored_args + " testfiles/bbstored.conf"; + std::string cmd = BBSTORED " " + bbstored_args + + " testfiles/bbstored.conf"; bbstored_pid = LaunchServer(cmd, "testfiles/bbstored.pid"); TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0); @@ -455,13 +452,19 @@ int test_run_bbstored() return 1; } -int test_kill_bbstored() +int test_kill_bbstored(bool wait_for_process = false) { - TEST_THAT(KillServer(bbstored_pid)); + TEST_THAT(KillServer(bbstored_pid, wait_for_process)); ::safe_sleep(1); TEST_THAT(!ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbstored_pid)) + { + bbstored_pid = 0; + } - #ifndef WIN32 + #ifdef WIN32 + TEST_THAT(unlink("testfiles/bbstored.pid") == 0); + #else TestRemoteProcessMemLeaks("bbstored.memleaks"); #endif @@ -511,7 +514,8 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) { // connect and log in SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + 22011); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly)); @@ -601,10 +605,10 @@ int64_t SearchDir(BackupStoreDirectory& rDir, SocketStreamTLS sSocket; -std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext, int flags) +std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext) { sSocket.Open(rContext, Socket::TypeINET, - "localhost", BOX_PORT_BBSTORED); + "localhost", 22011); std::auto_ptr<BackupProtocolClient> connection; connection.reset(new BackupProtocolClient(sSocket)); connection->Handshake(); @@ -617,10 +621,17 @@ std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext, int flags) THROW_EXCEPTION(BackupStoreException, WrongServerVersion); } - connection->QueryLogin(0x01234567, flags); return connection; } +std::auto_ptr<BackupProtocolClient> ConnectAndLogin(TLSContext& rContext, + int flags) +{ + std::auto_ptr<BackupProtocolClient> connection(Connect(rContext)); + connection->QueryLogin(0x01234567, flags); + return connection; +} + std::auto_ptr<BackupStoreDirectory> ReadDirectory ( BackupProtocolClient& rClient, @@ -639,6 +650,7 @@ int start_internal_daemon() { // ensure that no child processes end up running tests! int own_pid = getpid(); + BOX_TRACE("Test PID is " << own_pid); // this is a quick hack to allow passing some options to the daemon const char* argv[] = { @@ -658,18 +670,14 @@ int start_internal_daemon() result = daemon.Main("testfiles/bbackupd.conf", 1, argv); } - TEST_THAT(result == 0); - if (result != 0) - { - printf("Daemon exited with code %d\n", result); - } + TEST_EQUAL_LINE(0, result, "Daemon exit code"); // ensure that no child processes end up running tests! - TEST_THAT(getpid() == own_pid); if (getpid() != own_pid) { // abort! - _exit(1); + BOX_INFO("Daemon child finished, exiting now."); + _exit(0); } TEST_THAT(TestFileExists("testfiles/bbackupd.pid")); @@ -703,20 +711,9 @@ int start_internal_daemon() bool stop_internal_daemon(int pid) { - bool killed_server = KillServer(pid); + bool killed_server = KillServer(pid, false); TEST_THAT(killed_server); return killed_server; - - /* - 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; @@ -728,15 +725,15 @@ static char stat_hook_filename[512]; // 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); +extern "C" 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); +extern "C" 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); +extern "C" int lstat_test_hook(const char *file_name, struct stat *buf); #endif -struct dirent *readdir_test_hook_1(DIR *dir) +extern "C" struct dirent *readdir_test_hook_1(DIR *dir) { #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE intercept_setup_readdir_hook(NULL, readdir_test_hook_2); @@ -747,7 +744,7 @@ struct dirent *readdir_test_hook_1(DIR *dir) // 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) +extern "C" struct dirent *readdir_test_hook_2(DIR *dir) { if (time(NULL) >= readdir_stop_time) { @@ -783,17 +780,45 @@ 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) +extern "C" 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) +extern "C" int lstat_test_hook(const char *file_name, struct stat *buf) #endif { - // TRACE1("lstat hook triggered for %s", file_name); + // TRACE1("lstat hook triggered for %s", file_name); memset(buf, 0, sizeof(*buf)); buf->st_mode = S_IFREG; return 0; } +// Simulate a symlink that is on a different device than the file +// that it points to. +int lstat_test_post_hook(int old_ret, const char *file_name, struct stat *buf) +{ + BOX_TRACE("lstat post hook triggered for " << file_name); + if (old_ret == 0 && + strcmp(file_name, "testfiles/symlink-to-TestDir1") == 0) + { + buf->st_dev ^= 0xFFFF; + } + return old_ret; +} + +bool test_entry_deleted(BackupStoreDirectory& rDir, + const std::string& rName) +{ + BackupStoreDirectory::Iterator i(rDir); + + BackupStoreDirectory::Entry *en = i.FindMatchingClearName( + BackupStoreFilenameClear(rName)); + TEST_THAT(en != 0); + if (en == 0) return false; + + int16_t flags = en->GetFlags(); + TEST_THAT(flags && BackupStoreDirectory::Entry::Flags_Deleted); + return flags && BackupStoreDirectory::Entry::Flags_Deleted; +} + int test_bbackupd() { // First, wait for a normal period to make sure the last changes @@ -807,6 +832,23 @@ int test_bbackupd() "testfiles/clientPrivKey.pem", "testfiles/clientTrustedCAs.pem"); + printf("\n==== Testing that ReadDirectory on nonexistent directory " + "does not crash\n"); + { + std::auto_ptr<BackupProtocolClient> client = ConnectAndLogin( + context, 0 /* read-write */); + + { + Logging::Guard guard(Log::ERROR); + TEST_CHECK_THROWS(ReadDirectory(*client, 0x12345678), + ConnectionException, + Conn_Protocol_UnexpectedReply); + } + + client->QueryFinished(); + sSocket.Close(); + } + // unpack the files for the initial test TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0); TEST_THAT(::mkdir("testfiles/TestDir1", 0777) == 0); @@ -818,7 +860,7 @@ int test_bbackupd() 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"); @@ -841,7 +883,9 @@ int test_bbackupd() char buffer[10000]; memset(buffer, 0, sizeof(buffer)); - TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_EQUAL_LINE(sizeof(buffer), + write(fd, buffer, sizeof(buffer)), + "Buffer write"); TEST_THAT(close(fd) == 0); int pid = start_internal_daemon(); @@ -856,11 +900,14 @@ int test_bbackupd() TEST_THAT(unlink("testfiles/bbackupd.log") == 0); pid = start_internal_daemon(); + intercept_clear_setup(); 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_EQUAL_LINE(sizeof(buffer), + write(fd, buffer, sizeof(buffer)), + "Buffer write"); TEST_THAT(close(fd) == 0); wait_for_backup_operation(); @@ -892,20 +939,22 @@ int test_bbackupd() std::string line; TEST_THAT(reader.GetLine(line)); std::string comp = "Receive Success(0x"; - TEST_EQUAL(comp, line.substr(0, comp.size()), line); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receiving stream, size 124", line, line); + TEST_EQUAL("Receiving stream, size 124", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Send GetIsAlive()", line, line); + TEST_EQUAL("Send GetIsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receive IsAlive()", line, line); + TEST_EQUAL("Receive IsAlive()", line); TEST_THAT(reader.GetLine(line)); comp = "Send StoreFile(0x3,"; - TEST_EQUAL(comp, line.substr(0, comp.size()), line); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); comp = ",\"f1\")"; std::string sub = line.substr(line.size() - comp.size()); - TEST_EQUAL(comp, sub, line); + TEST_EQUAL_LINE(comp, sub, line); std::string comp2 = ",0x0,"; sub = line.substr(line.size() - comp.size() - comp2.size() + 1, comp2.size()); @@ -926,11 +975,14 @@ int test_bbackupd() intercept_setup_delay("testfiles/TestDir1/spacetest/f1", 0, 4000, SYS_read, 1); pid = start_internal_daemon(); + intercept_clear_setup(); 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_EQUAL_LINE(sizeof(buffer), + write(fd, buffer, sizeof(buffer)), + "Buffer write"); TEST_THAT(close(fd) == 0); wait_for_backup_operation(); @@ -959,9 +1011,10 @@ int test_bbackupd() std::string line; TEST_THAT(reader.GetLine(line)); std::string comp = "Receive Success(0x"; - TEST_THAT(line.substr(0, comp.size()) == comp); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receiving stream, size 124"); + TEST_EQUAL("Receiving stream, size 124", line); // delaying for 4 seconds in one step means that // the diff timer and the keepalive timer will @@ -970,10 +1023,11 @@ int test_bbackupd() TEST_THAT(reader.GetLine(line)); comp = "Send StoreFile(0x3,"; - TEST_EQUAL(comp, line.substr(0, comp.size()), line); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); comp = ",0x0,\"f1\")"; std::string sub = line.substr(line.size() - comp.size()); - TEST_EQUAL(comp, sub, line); + TEST_EQUAL_LINE(comp, sub, line); } if (failures > 0) @@ -986,11 +1040,14 @@ int test_bbackupd() intercept_setup_delay("testfiles/TestDir1/spacetest/f1", 0, 1000, SYS_read, 3); pid = start_internal_daemon(); + intercept_clear_setup(); 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_EQUAL_LINE(sizeof(buffer), + write(fd, buffer, sizeof(buffer)), + "Buffer write"); TEST_THAT(close(fd) == 0); wait_for_backup_operation(); @@ -1019,9 +1076,10 @@ int test_bbackupd() std::string line; TEST_THAT(reader.GetLine(line)); std::string comp = "Receive Success(0x"; - TEST_THAT(line.substr(0, comp.size()) == comp); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receiving stream, size 124"); + TEST_EQUAL("Receiving stream, size 124", line); // delaying for 3 seconds in steps of 1 second // means that the keepalive timer will expire 3 times, @@ -1030,23 +1088,24 @@ int test_bbackupd() // only two keepalives. TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Send GetIsAlive()"); + TEST_EQUAL("Send GetIsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receive IsAlive()"); + TEST_EQUAL("Receive IsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Send GetIsAlive()"); + TEST_EQUAL("Send GetIsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receive IsAlive()"); + TEST_EQUAL("Receive IsAlive()", line); // but two matching blocks should have been found // already, so the upload should be a diff. TEST_THAT(reader.GetLine(line)); comp = "Send StoreFile(0x3,"; - TEST_EQUAL(comp, line.substr(0, comp.size()), line); + TEST_EQUAL_LINE(comp, line.substr(0, comp.size()), + line); comp = ",\"f1\")"; std::string sub = line.substr(line.size() - comp.size()); - TEST_EQUAL(comp, sub, line); + TEST_EQUAL_LINE(comp, sub, line); std::string comp2 = ",0x0,"; sub = line.substr(line.size() - comp.size() - comp2.size() + 1, comp2.size()); @@ -1067,6 +1126,7 @@ int test_bbackupd() readdir_stop_time = time(NULL) + 12 + 2; pid = start_internal_daemon(); + intercept_clear_setup(); std::string touchfile = "testfiles/TestDir1/spacetest/d1/touch-me"; @@ -1074,7 +1134,9 @@ int test_bbackupd() 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_EQUAL_LINE(sizeof(buffer), + write(fd, buffer, sizeof(buffer)), + "Buffer write"); TEST_THAT(close(fd) == 0); wait_for_backup_operation(); @@ -1091,7 +1153,7 @@ int test_bbackupd() { std::string line; TEST_THAT(reader.GetLine(line)); - if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)") + if (line == "Send ListDirectory(0x3,0xffff,0xc,true)") { found1 = true; break; @@ -1119,17 +1181,17 @@ int test_bbackupd() { std::string line; TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receive Success(0x3)", line, line); + TEST_EQUAL("Receive Success(0x3)", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receiving stream, size 425", line, line); + TEST_EQUAL("Receiving stream, size 425", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Send GetIsAlive()", line, line); + TEST_EQUAL("Send GetIsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receive IsAlive()", line, line); + TEST_EQUAL("Receive IsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Send GetIsAlive()", line, line); + TEST_EQUAL("Send GetIsAlive()", line); TEST_THAT(reader.GetLine(line)); - TEST_EQUAL("Receive IsAlive()", line, line); + TEST_EQUAL("Receive IsAlive()", line); } if (failures > 0) @@ -1146,8 +1208,11 @@ int test_bbackupd() } #endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + std::string cmd = BBACKUPD " " + bbackupd_args + - " testfiles/bbackupd-temploc.conf"; + " testfiles/bbackupd.conf"; bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); @@ -1158,6 +1223,553 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; + if(bbackupd_pid > 0) + { + printf("\n==== Testing that backup pauses when " + "store is full\n"); + + // wait for files to be uploaded + BOX_TRACE("Waiting for all outstanding files to be uploaded") + wait_for_sync_end(); + BOX_TRACE("done.") + + // Set limit to something very small + // 26 blocks will be used at this point. + // (12 files + location * 2 for raidfile) + // 20 is what we'll need in a minute + // set soft limit to 0 to ensure that all deleted files + // are deleted immediately by housekeeping + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 0B 20B") + == 0); + TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); + + // Unpack some more files + #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/f1") == 0); + TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d7") == 0); + + // The following files should be on the server: + // 00000001 -d---- 00002 (root) + // 00000002 -d---- 00002 Test1 + // 00000003 -d---- 00002 Test1/spacetest + // 00000004 f-X--- 00002 Test1/spacetest/f1 + // 00000005 f----- 00002 Test1/spacetest/f2 + // 00000006 -d---- 00002 Test1/spacetest/d1 + // 00000007 f----- 00002 Test1/spacetest/d1/f3 + // 00000008 f----- 00002 Test1/spacetest/d1/f4 + // 00000009 -d---- 00002 Test1/spacetest/d2 + // 0000000a -d---- 00002 Test1/spacetest/d3 + // 0000000b -d---- 00002 Test1/spacetest/d3/d4 + // 0000000c f----- 00002 Test1/spacetest/d3/d4/f5 + // 0000000d -d---- 00002 Test1/spacetest/d6 + // 0000000e -dX--- 00002 Test1/spacetest/d7 + // This is 28 blocks total, of which 2 in deleted files + // and 18 in directories. Note that f1 and d7 may or may + // not be deleted yet. + // + // spacetest1 + spacetest2 = 16 files = 32 blocks with raidfile + // minus one file and one dir is 28 blocks + // + // d2/f6, d6/d8 and d6/d8/f7 are new + // even if the client marks f1 and d7 as deleted, and + // housekeeping deleted them, the backup cannot complete + // if the limit is 20 blocks. + + BOX_TRACE("Waiting for bbackupd to notice that the " + "store is full"); + wait_for_sync_end(); + BOX_TRACE("done."); + + BOX_TRACE("Compare to check that there are differences"); + int compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query0a.log " + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + BOX_TRACE("done."); + + // Check that the notify script was run + TEST_THAT(TestFileExists("testfiles/notifyran.store-full.1")); + // But only once! + TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); + + // Kill the daemon + terminate_bbackupd(bbackupd_pid); + + BOX_TRACE("Wait for housekeeping to remove the deleted files"); + wait_for_backup_operation(5); + BOX_TRACE("done."); + + // This removes f1 and d7, which were previously marked + // as deleted, so total usage drops by 4 blocks to 24. + + // BLOCK + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, 0 /* read-write */); + + std::auto_ptr<BackupProtocolClientAccountUsage> usage( + client->QueryGetAccountUsage()); + TEST_EQUAL_LINE(24, usage->GetBlocksUsed(), + "blocks used"); + TEST_EQUAL_LINE(0, usage->GetBlocksInDeletedFiles(), + "deleted blocks"); + TEST_EQUAL_LINE(16, usage->GetBlocksInDirectories(), + "directory blocks"); + + client->QueryFinished(); + sSocket.Close(); + } + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + + // ensure time is different to refresh the cache + ::safe_sleep(1); + + BOX_TRACE("Restart bbackupd with more exclusions"); + // Start again with a new config that excludes d3 and f2, + // and hence also d3/d4 and d3/d4/f5. bbackupd should mark + // them as deleted and housekeeping should clean up, + // making space to upload the new files. + // total required: (13-2-4+3)*2 = 20 blocks + /* + cmd = BBACKUPD " " + bbackupd_args + + " testfiles/bbackupd-exclude.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; + */ + + BackupDaemon bbackupd; + bbackupd.Configure("testfiles/bbackupd-exclude.conf"); + bbackupd.InitCrypto(); + BOX_TRACE("done."); + + // Should be marked as deleted by this run + // wait_for_sync_end(); + { + // Logging::Guard guard(Log::ERROR); + bbackupd.RunSyncNow(); + } + + TEST_THAT(bbackupd.StorageLimitExceeded()); + + // Check that the notify script was run + // TEST_THAT(TestFileExists("testfiles/notifyran.store-full.2")); + // But only twice! + // TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.3")); + + // All these should be marked as deleted but hopefully + // not removed by housekeeping yet: + // f1 deleted + // f2 excluded + // d1 excluded (why?) + // d1/f3 excluded (why?) + // d3 excluded + // d3/d4 excluded + // d3/d4/f5 excluded + // d7 deleted + // Careful with timing here, these files will be removed by + // housekeeping the next time it runs. On Win32, housekeeping + // runs immediately after disconnect, but only if enough time + // has elapsed since the last housekeeping. Since the + // backup run closely follows the last one, housekeeping + // should not run afterwards. On other platforms, we want to + // get in immediately after the backup and hope that + // housekeeping doesn't beat us to it. + + BOX_TRACE("Find out whether bbackupd marked files as deleted"); + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, 0 /* read-write */); + + std::auto_ptr<BackupStoreDirectory> rootDir = + ReadDirectory(*client, + BackupProtocolClientListDirectory::RootDirectory); + + int64_t testDirId = SearchDir(*rootDir, "Test1"); + TEST_THAT(testDirId != 0); + + std::auto_ptr<BackupStoreDirectory> Test1_dir = + ReadDirectory(*client, testDirId); + + int64_t spacetestDirId = SearchDir(*Test1_dir, + "spacetest"); + TEST_THAT(spacetestDirId != 0); + + std::auto_ptr<BackupStoreDirectory> spacetest_dir = + ReadDirectory(*client, spacetestDirId); + + // these files were deleted before, they should be + // long gone by now + + TEST_THAT(SearchDir(*spacetest_dir, "f1") == 0); + TEST_THAT(SearchDir(*spacetest_dir, "d7") == 0); + + // these files have just been deleted, because + // they are excluded by the new configuration. + // but housekeeping should not have run yet + + TEST_THAT(test_entry_deleted(*spacetest_dir, "f2")); + TEST_THAT(test_entry_deleted(*spacetest_dir, "d3")); + + int64_t d3_id = SearchDir(*spacetest_dir, "d3"); + TEST_THAT(d3_id != 0); + + std::auto_ptr<BackupStoreDirectory> d3_dir = + ReadDirectory(*client, d3_id); + TEST_THAT(test_entry_deleted(*d3_dir, "d4")); + + int64_t d4_id = SearchDir(*d3_dir, "d4"); + TEST_THAT(d4_id != 0); + + std::auto_ptr<BackupStoreDirectory> d4_dir = + ReadDirectory(*client, d4_id); + TEST_THAT(test_entry_deleted(*d4_dir, "f5")); + + std::auto_ptr<BackupProtocolClientAccountUsage> usage( + client->QueryGetAccountUsage()); + TEST_EQUAL_LINE(24, usage->GetBlocksUsed(), + "blocks used"); + TEST_EQUAL_LINE(4, usage->GetBlocksInDeletedFiles(), + "deleted blocks"); + TEST_EQUAL_LINE(16, usage->GetBlocksInDirectories(), + "directory blocks"); + // d1/f3 and d1/f4 are the only two files on the + // server which are not deleted, they use 2 blocks + // each, the rest is directories and 2 deleted files + // (f1 and d3/d4/f5) + + // Log out. + client->QueryFinished(); + sSocket.Close(); + } + BOX_TRACE("done."); + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + + BOX_TRACE("Wait for housekeeping to remove the deleted files"); + wait_for_backup_operation(5); + BOX_TRACE("done."); + + BOX_TRACE("Check that the files were removed"); + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, 0 /* read-write */); + + std::auto_ptr<BackupStoreDirectory> rootDir = + ReadDirectory(*client, + BackupProtocolClientListDirectory::RootDirectory); + + int64_t testDirId = SearchDir(*rootDir, "Test1"); + TEST_THAT(testDirId != 0); + + std::auto_ptr<BackupStoreDirectory> Test1_dir = + ReadDirectory(*client, testDirId); + + int64_t spacetestDirId = SearchDir(*Test1_dir, + "spacetest"); + TEST_THAT(spacetestDirId != 0); + + std::auto_ptr<BackupStoreDirectory> spacetest_dir = + ReadDirectory(*client, spacetestDirId); + + TEST_THAT(SearchDir(*spacetest_dir, "f1") == 0); + TEST_THAT(SearchDir(*spacetest_dir, "f2") == 0); + TEST_THAT(SearchDir(*spacetest_dir, "d3") == 0); + TEST_THAT(SearchDir(*spacetest_dir, "d7") == 0); + + std::auto_ptr<BackupProtocolClientAccountUsage> usage( + client->QueryGetAccountUsage()); + TEST_EQUAL_LINE(16, usage->GetBlocksUsed(), + "blocks used"); + TEST_EQUAL_LINE(0, usage->GetBlocksInDeletedFiles(), + "deleted blocks"); + TEST_EQUAL_LINE(12, usage->GetBlocksInDirectories(), + "directory blocks"); + // d1/f3 and d1/f4 are the only two files on the + // server, they use 2 blocks each, the rest is + // directories. + + // Log out. + client->QueryFinished(); + sSocket.Close(); + } + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + + // Need 22 blocks free to upload everything + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 0B 22B") + == 0); + TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); + + // Run another backup, now there should be enough space + // for everything we want to upload. + { + Logging::Guard guard(Log::ERROR); + bbackupd.RunSyncNow(); + } + TEST_THAT(!bbackupd.StorageLimitExceeded()); + + // Check that the contents of the store are the same + // as the contents of the disc + // (-a = all, -c = give result in return code) + BOX_TRACE("Check that all files were uploaded successfully"); + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd-exclude.conf " + "-l testfiles/query1.log " + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + BOX_TRACE("done."); + + // BLOCK + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, 0 /* read-write */); + + std::auto_ptr<BackupProtocolClientAccountUsage> usage( + client->QueryGetAccountUsage()); + TEST_EQUAL_LINE(22, usage->GetBlocksUsed(), + "blocks used"); + TEST_EQUAL_LINE(0, usage->GetBlocksInDeletedFiles(), + "deleted blocks"); + TEST_EQUAL_LINE(14, usage->GetBlocksInDirectories(), + "directory blocks"); + // d2/f6, d6/d8 and d6/d8/f7 are new + // i.e. 2 new files, 1 new directory + + client->QueryFinished(); + sSocket.Close(); + } + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + + // Put the limit back + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 " + "1000B 2000B") == 0); + TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); + + // Start again with the old config + BOX_TRACE("Restart bbackupd with original configuration"); + // terminate_bbackupd(); + 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; + BOX_TRACE("done."); + + // unpack the initial files again + #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 + + BOX_TRACE("Wait for bbackupd to upload more files"); + wait_for_backup_operation(); + BOX_TRACE("done."); + + // Check that the contents of the store are the same + // as the contents of the disc + // (-a = all, -c = give result in return code) + BOX_TRACE("Check that all files were uploaded successfully"); + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query1.log " + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + BOX_TRACE("done."); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + } + + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + + #ifndef WIN32 // requires fork + printf("\n==== Testing that bbackupd responds correctly to " + "connection failure\n"); + + { + // Kill the daemons + terminate_bbackupd(bbackupd_pid); + test_kill_bbstored(); + + // create a new file to force an upload + + const char* new_file = "testfiles/TestDir1/force-upload-2"; + int fd = open(new_file, + O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd <= 0) + { + perror(new_file); + } + TEST_THAT(fd > 0); + + const char* control_string = "whee!\n"; + TEST_THAT(write(fd, control_string, + strlen(control_string)) == + (int)strlen(control_string)); + close(fd); + + // sleep to make it old enough to upload + safe_sleep(4); + + class MyHook : public BackupStoreContext::TestHook + { + virtual std::auto_ptr<ProtocolObject> StartCommand( + BackupProtocolObject& rCommand) + { + if (rCommand.GetType() == + BackupProtocolServerStoreFile::TypeID) + { + // terminate badly + THROW_EXCEPTION(CommonException, + Internal); + } + return std::auto_ptr<ProtocolObject>(); + } + }; + MyHook hook; + + bbstored_pid = fork(); + + if (bbstored_pid < 0) + { + BOX_LOG_SYS_ERROR("failed to fork()"); + return 1; + } + + if (bbstored_pid == 0) + { + // in fork child + TEST_THAT(setsid() != -1); + + if (!Logging::IsEnabled(Log::TRACE)) + { + Logging::SetGlobalLevel(Log::NOTHING); + } + + // BackupStoreDaemon must be destroyed before exit(), + // to avoid memory leaks being reported. + { + BackupStoreDaemon bbstored; + bbstored.SetTestHook(hook); + bbstored.SetRunInForeground(true); + bbstored.Main("testfiles/bbstored.conf"); + } + + Timers::Cleanup(); // avoid memory leaks + exit(0); + } + + // in fork parent + bbstored_pid = WaitForServerStartup("testfiles/bbstored.pid", + bbstored_pid); + + TEST_THAT(::system("rm -f testfiles/notifyran.store-full.*") == 0); + + // Ignore SIGPIPE so that when the connection is broken, + // the daemon doesn't terminate. + ::signal(SIGPIPE, SIG_IGN); + + { + Log::Level newLevel = Logging::GetGlobalLevel(); + + if (!Logging::IsEnabled(Log::TRACE)) + { + newLevel = Log::NOTHING; + } + + Logging::Guard guard(newLevel); + + BackupDaemon bbackupd; + bbackupd.Configure("testfiles/bbackupd.conf"); + bbackupd.InitCrypto(); + bbackupd.RunSyncNowWithExceptionHandling(); + } + + ::signal(SIGPIPE, SIG_DFL); + + TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1")); + TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2")); + TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.1")); + + test_kill_bbstored(true); + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + + test_run_bbstored(); + + 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; + } + #endif // !WIN32 + + #ifndef WIN32 printf("\n==== Testing that absolute symlinks are not followed " "during restore\n"); @@ -1179,7 +1791,7 @@ int test_bbackupd() fclose(fp); char buf[PATH_MAX]; - TEST_THAT(getcwd(buf, sizeof(buf)) != NULL); + TEST_THAT(getcwd(buf, sizeof(buf)) == buf); std::string path = buf; path += DIRECTORY_SEPARATOR SYM_DIR DIRECTORY_SEPARATOR "a" @@ -1188,15 +1800,19 @@ int test_bbackupd() DIRECTORY_SEPARATOR "b" DIRECTORY_SEPARATOR "link") == 0); + // also test symlink-to-self loop does not break restore + TEST_THAT(symlink("self", SYM_DIR "/self") == 0); + ::wait_for_operation(4); ::sync_and_wait(); // Check that the backup was successful, i.e. no differences - int compareReturnValue = ::system(BBACKUPQUERY " -q " + int compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query1.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // now stop bbackupd and update the test file, @@ -1215,9 +1831,10 @@ int test_bbackupd() // check that we can restore it compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " - "-q \"restore Test1 testfiles/restore-symlink\" " + "-Wwarning \"restore Test1 testfiles/restore-symlink\" " "quit"); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); // make it accessible again TEST_THAT(chmod(SYM_DIR, 0755) == 0); @@ -1228,10 +1845,52 @@ int test_bbackupd() std::string line; TEST_THAT(gl.GetLine(line)); TEST_THAT(line != "before"); - TEST_THAT(line == "after"); + TEST_EQUAL("after", line); #undef SYM_DIR + /* + // This is not worth testing or fixing. + // + #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE + printf("\n==== Testing that symlinks to other filesystems " + "can be backed up as roots\n"); + + intercept_setup_lstat_post_hook(lstat_test_post_hook); + TEST_THAT(symlink("TestDir1", "testfiles/symlink-to-TestDir1") + == 0); + + struct stat stat_st, lstat_st; + TEST_THAT(stat("testfiles/symlink-to-TestDir1", &stat_st) == 0); + TEST_THAT(lstat("testfiles/symlink-to-TestDir1", &lstat_st) == 0); + TEST_EQUAL_LINE((stat_st.st_dev ^ 0xFFFF), lstat_st.st_dev, + "stat vs lstat"); + + BackupDaemon bbackupd; + bbackupd.Configure("testfiles/bbackupd-symlink.conf"); + bbackupd.InitCrypto(); + bbackupd.RunSyncNow(); + intercept_clear_setup(); + + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query0a.log " + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // and again using the symlink during compare + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd-symlink.conf " + "-l testfiles/query0a.log " + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + #endif + */ + bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); ::safe_sleep(1); @@ -1241,31 +1900,65 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; } + #endif // !WIN32 + + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); printf("\n==== Testing that redundant locations are deleted on time\n"); + // unpack the files for the redundant location test + TEST_THAT(::system("rm -rf testfiles/TestDir2") == 0); + TEST_THAT(::mkdir("testfiles/TestDir2", 0777) == 0); + + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz " + "-C testfiles/TestDir2") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz " + "| ( cd testfiles/TestDir2 && tar xf - )") == 0); + #endif + + // BLOCK { - std::auto_ptr<BackupProtocolClient> client = Connect( - context, - BackupProtocolClientLogin::Flags_ReadOnly); - - std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory( - *client, - BackupProtocolClientListDirectory::RootDirectory); + // Kill the daemon + terminate_bbackupd(bbackupd_pid); + + // Start it with a config that has a temporary location + // that will be created on the server + std::string cmd = BBACKUPD " " + bbackupd_args + + " testfiles/bbackupd-temploc.conf"; - // int64_t testDirId = SearchDir(*dir, "Test2"); - // TEST_THAT(testDirId == 0); + 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; sync_and_wait(); - dir = ReadDirectory(*client, - BackupProtocolClientListDirectory::RootDirectory); - int64_t testDirId = SearchDir(*dir, "Test2"); - TEST_THAT(testDirId != 0); + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, + BackupProtocolClientLogin::Flags_ReadOnly); + + std::auto_ptr<BackupStoreDirectory> dir = + ReadDirectory(*client, + BackupProtocolClientListDirectory::RootDirectory); + int64_t testDirId = SearchDir(*dir, "Test2"); + TEST_THAT(testDirId != 0); + + client->QueryFinished(); + sSocket.Close(); + } // Kill the daemon terminate_bbackupd(bbackupd_pid); + // Start it again with the normal config (no Test2) cmd = BBACKUPD " " + bbackupd_args + " testfiles/bbackupd.conf"; bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); @@ -1284,28 +1977,41 @@ int test_bbackupd() wait_for_sync_end(); wait_for_sync_end(); - dir = ReadDirectory(*client, - BackupProtocolClientListDirectory::RootDirectory); - testDirId = SearchDir(*dir, "Test2"); - TEST_THAT(testDirId != 0); + // not yet! should still be there + + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, + BackupProtocolClientLogin::Flags_ReadOnly); + + std::auto_ptr<BackupStoreDirectory> dir = + ReadDirectory(*client, + BackupProtocolClientListDirectory::RootDirectory); + int64_t testDirId = SearchDir(*dir, "Test2"); + TEST_THAT(testDirId != 0); + + client->QueryFinished(); + sSocket.Close(); + } wait_for_sync_end(); - - dir = ReadDirectory(*client, - BackupProtocolClientListDirectory::RootDirectory); - testDirId = SearchDir(*dir, "Test2"); - TEST_THAT(testDirId != 0); - - BackupStoreDirectory::Iterator i(*dir); - BackupStoreFilenameClear dirname("Test2"); - BackupStoreDirectory::Entry *en = i.FindMatchingClearName(dirname); - TEST_THAT(en != 0); - int16_t en_flags = en->GetFlags(); - TEST_THAT(en_flags && BackupStoreDirectory::Entry::Flags_Deleted); - - // Log out. - client->QueryFinished(); - sSocket.Close(); + + // NOW it should be gone + + { + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, + BackupProtocolClientLogin::Flags_ReadOnly); + + std::auto_ptr<BackupStoreDirectory> root_dir = + ReadDirectory(*client, + BackupProtocolClientListDirectory::RootDirectory); + + TEST_THAT(test_entry_deleted(*root_dir, "Test2")); + + client->QueryFinished(); + sSocket.Close(); + } } TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -1315,85 +2021,14 @@ int test_bbackupd() if(bbackupd_pid > 0) { - printf("\n==== Testing that backup pauses when store is full\n"); - - // wait for files to be uploaded - wait_for_backup_operation(); - - // 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(BBSTOREACCOUNTS " -c " - "testfiles/bbstored.conf setlimit 01234567 9B 10B") - == 0); - TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); - - // Unpack some more files - #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(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(BBSTOREACCOUNTS " -c " - "testfiles/bbstored.conf setlimit 01234567 " - "1000B 2000B") == 0); - TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); - - // Check that the notify script was run - TEST_THAT(TestFileExists("testfiles/notifyran.store-full.1")); - // But only once! - TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); - - // unpack the initial files again - #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(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; - + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); printf("\n==== Check that read-only directories and " "their contents can be restored.\n"); + int compareReturnValue; + { #ifdef WIN32 TEST_THAT(::system("chmod 0555 testfiles/" @@ -1407,35 +2042,45 @@ int test_bbackupd() wait_for_sync_end(); // should be backed up now compareReturnValue = ::system(BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " - "-q \"compare -cEQ Test1 testfiles/TestDir1\" " + "\"compare -cEQ Test1 testfiles/TestDir1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // check that we can restore it compareReturnValue = ::system(BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " - "-q \"restore Test1 testfiles/restore1\" " + "\"restore Test1 testfiles/restore1\" " "quit"); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // check that it restored properly compareReturnValue = ::system(BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " - "-q \"compare -cEQ Test1 testfiles/restore1\" " + "\"compare -cEQ Test1 testfiles/restore1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // put the permissions back to sensible values #ifdef WIN32 TEST_THAT(::system("chmod 0755 testfiles/" "TestDir1/x1") == 0); + TEST_THAT(::system("chmod 0755 testfiles/" + "restore1/x1") == 0); #else TEST_THAT(chmod("testfiles/TestDir1/x1", 0755) == 0); + TEST_THAT(chmod("testfiles/restore1/x1", + 0755) == 0); #endif } @@ -1512,58 +2157,68 @@ int test_bbackupd() // test that bbackupd will let us lcd into the local // directory using a relative path - std::string command = BBACKUPQUERY " -q " + std::string command = BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " "\"lcd testfiles/TestDir1/" + systemDirName + "\" " "quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); // and back out again - command = BBACKUPQUERY " -q " + command = BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " "\"lcd testfiles/TestDir1/" + systemDirName + "\" " "\"lcd ..\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); // and using an absolute path - command = BBACKUPQUERY " -q " + command = BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " "\"lcd " + cwd + "/testfiles/TestDir1/" + systemDirName + "\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); // and back out again - command = BBACKUPQUERY " -q " + command = BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " "\"lcd " + cwd + "/testfiles/TestDir1/" + systemDirName + "\" " "\"lcd ..\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); { 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); + TEST_EQUAL_LINE(12, fs.GetPosition(), + "FileStream position"); fs.Close(); } wait_for_backup_operation(); // Compare to check that the file was uploaded - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " -Wwarning " "-c testfiles/bbackupd.conf \"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that we can find it in directory listing { std::auto_ptr<BackupProtocolClient> client = - Connect(context, 0); + ConnectAndLogin(context, 0); std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory( *client, @@ -1573,19 +2228,18 @@ int test_bbackupd() TEST_THAT(baseDirId != 0); dir = ReadDirectory(*client, baseDirId); - int64_t testDirId = SearchDir(dir, dirname.c_str()); + int64_t testDirId = SearchDir(*dir, dirname.c_str()); TEST_THAT(testDirId != 0); dir = ReadDirectory(*client, testDirId); - TEST_THAT(SearchDir(dir, filename.c_str()) != 0); + TEST_THAT(SearchDir(*dir, filename.c_str()) != 0); // Log out client->QueryFinished(); sSocket.Close(); } - // Check that bbackupquery shows the dir in console encoding - command = BBACKUPQUERY " -q " + command = BBACKUPQUERY " -Wwarning " "-c testfiles/bbackupd.conf " "-q \"list Test1\" quit"; pid_t bbackupquery_pid; @@ -1615,7 +2269,7 @@ int test_bbackupd() // 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"; + "-Wwarning \"list Test1/" + systemDirName + "\" quit"; queryout = LocalProcessStream(command.c_str(), bbackupquery_pid); TEST_THAT(queryout.get() != NULL); @@ -1639,31 +2293,34 @@ int test_bbackupd() // 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 + + "-Wwarning \"compare -cEQ Test1/" + systemDirName + " testfiles/TestDir1/" + systemDirName + "\" quit"; compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); // 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 + + "-Wwarning \"restore Test1/" + systemDirName + " testfiles/restore-" + systemDirName + "\" quit"; compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); // Compare to make sure it was restored properly. command = BBACKUPQUERY " -c testfiles/bbackupd.conf " - "-q \"compare -cEQ Test1/" + systemDirName + + "-Wwarning \"compare -cEQ Test1/" + systemDirName + " testfiles/restore-" + systemDirName + "\" quit"; compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); std::string fileToUnlink = "testfiles/restore-" + dirname + "/" + filename; @@ -1672,22 +2329,25 @@ int test_bbackupd() // 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 + "/" + + "-Wwarning \"get Test1/" + systemDirName + "/" + systemFileName + " " + "testfiles/restore-" + systemDirName + "/" + systemFileName + "\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // And after changing directory to a relative path - command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-Wwarning " "\"lcd testfiles\" " "\"cd Test1/" + systemDirName + "\" " + "\"get " + systemFileName + "\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks"); // cannot overwrite a file that exists, so delete it @@ -1695,36 +2355,43 @@ int test_bbackupd() TEST_THAT(::unlink(tmp.c_str()) == 0); // And after changing directory to an absolute path - command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + command = BBACKUPQUERY " -c testfiles/bbackupd.conf -Wwarning " "\"lcd " + cwd + "/testfiles\" " "\"cd Test1/" + systemDirName + "\" " + "\"get " + systemFileName + "\" quit"; compareReturnValue = ::system(command.c_str()); - TEST_RETURN(compareReturnValue, 0); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Command_OK); 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 + + command = BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-Wwarning \"compare -cAEQ Test1/" + systemDirName + " testfiles/restore-" + systemDirName + "\" quit"; compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); // Compare without attributes. This should fail. - command = BBACKUPQUERY " -c testfiles/bbackupd.conf " - "-q \"compare -cEQ Test1/" + systemDirName + + command = BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-Werror \"compare -cEQ Test1/" + systemDirName + " testfiles/restore-" + systemDirName + "\" quit"; - compareReturnValue = ::system(command.c_str()); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - TEST_RETURN(compareReturnValue, 2); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); #endif // WIN32 + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); if (!ServerIsAlive(bbackupd_pid)) return 1; @@ -1739,7 +2406,7 @@ int test_bbackupd() // we now have 3 seconds before bbackupd // runs the SyncAllowScript again. - char* sync_control_file = "testfiles" + const char* sync_control_file = "testfiles" DIRECTORY_SEPARATOR "syncallowscript.control"; int fd = open(sync_control_file, O_CREAT | O_EXCL | O_WRONLY, 0700); @@ -1749,7 +2416,7 @@ int test_bbackupd() } TEST_THAT(fd > 0); - char* control_string = "10\n"; + const char* control_string = "10\n"; TEST_THAT(write(fd, control_string, strlen(control_string)) == (int)strlen(control_string)); @@ -1758,7 +2425,7 @@ int test_bbackupd() // this will pause backups, bbackupd will check // every 10 seconds to see if they are allowed again. - char* new_test_file = "testfiles" + const char* new_test_file = "testfiles" DIRECTORY_SEPARATOR "TestDir1" DIRECTORY_SEPARATOR "Added_During_Pause"; fd = open(new_test_file, @@ -1799,11 +2466,13 @@ int test_bbackupd() long start_time = time(NULL); // check that no backup has run (compare fails) - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " + "-Werror " "-c testfiles/bbackupd.conf " "-l testfiles/query3.log " "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 2); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(unlink(sync_control_file) == 0); @@ -1819,11 +2488,13 @@ int test_bbackupd() wait_for_sync_end(); // check that backup has run (compare succeeds) - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " + "-Wwarning " "-c testfiles/bbackupd.conf " "-l testfiles/query3a.log " "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); if (failures > 0) @@ -1833,6 +2504,9 @@ int test_bbackupd() } } + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); if (!ServerIsAlive(bbackupd_pid)) return 1; @@ -1865,22 +2539,24 @@ int test_bbackupd() 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(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " -Wwarning " "-c testfiles/bbackupd.conf " "-l testfiles/query2.log " "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Try a quick compare, just for fun - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query2q.log " - "\"compare -acqQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acqQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -1890,12 +2566,17 @@ int test_bbackupd() // Check that store errors are reported neatly printf("\n==== Create store error\n"); + TEST_THAT(system("rm -f testfiles/notifyran.backup-error.*") + == 0); + + // break the store 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", @@ -1903,50 +2584,195 @@ int test_bbackupd() 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 + + wait_for_backup_operation(4); + // Check that an error was reported just once 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 + // Now kill bbackupd and start one that's running in + // snapshot mode, check that it automatically syncs after + // an error, without waiting for another sync command. + terminate_bbackupd(bbackupd_pid); + std::string cmd = BBACKUPD " " + bbackupd_args + + " testfiles/bbackupd-snapshot.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; + + sync_and_wait(); + + // Check that the error was reported once more + TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.2")); + TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.3")); + + // Fix the store (so that bbackupquery compare works) 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); + + int store_fixed_time = time(NULL); + + // Check that we DO get errors on compare (cannot do this + // until after we fix the store, which creates a race) + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // Test initial state + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.backup-start.wait-snapshot.1")); + + // Set a tag for the notify script to distinguish from + // previous runs. + { + int fd1 = open("testfiles/notifyscript.tag", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(write(fd1, "wait-snapshot", 13) == 13); + TEST_THAT(close(fd1) == 0); + } + + // bbackupd should pause for about 90 seconds from store_fixed_time, + // so check that it hasn't run after 85 seconds from store_fixed_time + wait_for_backup_operation(85 - time(NULL) + store_fixed_time); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.backup-start.wait-snapshot.1")); + + // Should not have backed up, should still get errors + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // wait another 10 seconds, bbackup should have run + wait_for_backup_operation(10); + TEST_THAT(TestFileExists("testfiles/" + "notifyran.backup-start.wait-snapshot.1")); - // Check that we DO get errors on compare - compareReturnValue = ::system(BBACKUPQUERY " -q " + // Check that it did get uploaded, and we have no more errors + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3b.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 2); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0); + + // Stop the snapshot bbackupd + terminate_bbackupd(bbackupd_pid); + + // Break the store again + 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); + + // Modify a file to trigger an upload + { + int fd1 = open("testfiles/TestDir1/force-upload", + O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(write(fd1, "and again", 9) == 9); + TEST_THAT(close(fd1) == 0); + } + + // Restart the old bbackupd, in automatic mode + 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; - // 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(); + // Fix the store again + 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); + + store_fixed_time = time(NULL); + + // Check that we DO get errors on compare (cannot do this + // until after we fix the store, which creates a race) + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // Test initial state + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.backup-start.wait-automatic.1")); + + // Set a tag for the notify script to distinguist from + // previous runs. + { + int fd1 = open("testfiles/notifyscript.tag", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(write(fd1, "wait-automatic", 14) == 14); + TEST_THAT(close(fd1) == 0); + } + + // bbackupd should pause for about 90 seconds from store_fixed_time, + // so check that it hasn't run after 85 seconds from store_fixed_time + wait_for_backup_operation(85 - time(NULL) + store_fixed_time); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.backup-start.wait-automatic.1")); + + // Should not have backed up, should still get errors + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // wait another 10 seconds, bbackup should have run + wait_for_backup_operation(10); + TEST_THAT(TestFileExists("testfiles/" + "notifyran.backup-start.wait-automatic.1")); + // Check that it did get uploaded, and we have no more errors - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3b.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0); + TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); if (!ServerIsAlive(bbackupd_pid)) return 1; @@ -1976,11 +2802,12 @@ int test_bbackupd() #endif wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3c.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2004,11 +2831,12 @@ int test_bbackupd() #endif wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3d.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2035,11 +2863,12 @@ int test_bbackupd() #endif wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3e.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2066,11 +2895,12 @@ int test_bbackupd() #endif wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3f.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2097,11 +2927,12 @@ int test_bbackupd() wait_for_operation(5); // back up both files wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3g.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #ifdef WIN32 @@ -2114,11 +2945,12 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1")); TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2")); wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3g.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2148,11 +2980,12 @@ int test_bbackupd() wait_for_operation(5); // back up both files wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3h.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #ifdef WIN32 @@ -2165,11 +2998,12 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1")); TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2")); wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3i.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2185,13 +3019,17 @@ int test_bbackupd() "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3j.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); if (!ServerIsAlive(bbackupd_pid)) return 1; @@ -2219,11 +3057,12 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3k.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2231,6 +3070,9 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + // Check that modifying files with old timestamps // still get added printf("\n==== Modify existing file, but change timestamp " @@ -2277,11 +3119,12 @@ int test_bbackupd() wait_for_sync_end(); // files too new wait_for_sync_end(); // should (not) be backed up this time - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3l.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2289,6 +3132,9 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; + // Check that no read error has been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + // Add some files and directories which are marked as excluded printf("\n==== Add files and dirs for exclusion test\n"); #ifdef WIN32 @@ -2305,19 +3151,21 @@ int test_bbackupd() wait_for_sync_end(); // compare with exclusions, should not find differences - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3m.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // compare without exclusions, should find differences - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3n.log " - "\"compare -acEQ\" quit"); - TEST_RETURN(compareReturnValue, 2); + "-Werror \"compare -acEQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2331,8 +3179,8 @@ int test_bbackupd() "actually work\n"); { - std::auto_ptr<BackupProtocolClient> client = Connect( - context, + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, BackupProtocolClientLogin::Flags_ReadOnly); std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory( @@ -2373,6 +3221,9 @@ int test_bbackupd() // These tests only work as non-root users. if(::getuid() != 0) { + // Check that the error has not been reported yet + TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1")); + // Check that read errors are reported neatly printf("\n==== Add unreadable files\n"); @@ -2389,13 +3240,14 @@ int test_bbackupd() // Wait and test... wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3o.log " - "\"compare -acQ\" quit"); + "-Werror \"compare -acQ\" quit"); // should find differences - TEST_RETURN(compareReturnValue, 3); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Error); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that it was reported correctly @@ -2492,11 +3344,12 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query4.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("\n==== Restore files and directories\n"); @@ -2504,8 +3357,8 @@ int test_bbackupd() int64_t restoredirid = 0; { // connect and log in - std::auto_ptr<BackupProtocolClient> client = Connect( - context, + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, BackupProtocolClientLogin::Flags_ReadOnly); // Find the ID of the Test1 directory @@ -2528,13 +3381,6 @@ int test_bbackupd() 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(*client, restoredirid, - "testfiles/no-such-path/subdir", - true /* print progress dots */) - == Restore_TargetPathNotFound); - // Find ID of the deleted directory deldirid = GetDirID(*client, "x1", restoredirid); TEST_THAT(deldirid != 0); @@ -2547,18 +3393,34 @@ int test_bbackupd() true /* deleted files */) == Restore_Complete); + // Make sure you can't restore to a nonexistant path + printf("\n==== Try to restore to a path " + "that doesn't exist\n"); + fflush(stdout); + + { + Logging::Guard guard(Log::FATAL); + TEST_THAT(BackupClientRestore(*client, + restoredirid, + "testfiles/no-such-path/subdir", + true /* print progress dots */) + == Restore_TargetPathNotFound); + } + // Log out client->QueryFinished(); sSocket.Close(); } // Compare the restored files - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10.log " + "-Wwarning " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2572,12 +3434,14 @@ int test_bbackupd() "testfiles\\restore-Test1\\f1.dat"); TEST_RETURN(compareReturnValue, 0); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10a.log " + "-Werror " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 2); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // set it back, expect no failures @@ -2585,11 +3449,13 @@ int test_bbackupd() "testfiles\\restore-Test1\\f1.dat"); TEST_RETURN(compareReturnValue, 0); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf -l testfiles/query10a.log " + "-Wwarning " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // change the timestamp on a file, expect a compare failure @@ -2609,46 +3475,54 @@ int test_bbackupd() // a compare failure TEST_THAT(set_file_time(testfile, dummyTime, lastModTime, lastAccessTime)); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10a.log " + "-Werror " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 2); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); 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 " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10a.log " + "-Wwarning " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); 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 " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10a.log " + "-Werror " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 2); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); 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 " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query10a.log " + "-Wwarning " "\"compare -cEQ Test1 testfiles/restore-Test1\" " "quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #endif // WIN32 @@ -2671,11 +3545,12 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query5.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2688,19 +3563,21 @@ int test_bbackupd() TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // and again, but with quick flag - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query6q.log " - "\"compare -acqQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acqQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Rename some files -- one under the threshold, others above @@ -2712,11 +3589,12 @@ int test_bbackupd() TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2754,11 +3632,12 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query3e.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2777,23 +3656,23 @@ int test_bbackupd() { try { - SocketStreamTLS conn; - 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 - // Make sure the marker isn't zero, because that's the default, and it should have changed + std::auto_ptr<BackupProtocolClient> + protocol = Connect(context); + // Make sure the marker isn't zero, + // because that's the default, and + // it should have changed + std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol->QueryLogin(0x01234567, 0)); TEST_THAT(loginConf->GetClientStoreMarker() != 0); // Change it to something else - protocol.QuerySetClientStoreMarker(12); + protocol->QuerySetClientStoreMarker(12); // Success! done = true; // Log out - protocol.QueryFinished(); + protocol->QueryFinished(); + sSocket.Close(); } catch(...) { @@ -2822,11 +3701,12 @@ 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(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 2); + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Different); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(ServerIsAlive(bbackupd_pid)); @@ -2856,8 +3736,8 @@ int test_bbackupd() printf("\n==== Resume restore\n"); - std::auto_ptr<BackupProtocolClient> client = Connect( - context, + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, BackupProtocolClientLogin::Flags_ReadOnly); // Check that the restore fn returns resume possible, @@ -2880,12 +3760,13 @@ int test_bbackupd() sSocket.Close(); // Then check it has restored the correct stuff - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query14.log " - "\"compare -cEQ Test1 " + "-Wwarning \"compare -cEQ Test1 " "testfiles/restore-interrupt\" quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } #endif // !WIN32 @@ -2898,8 +3779,8 @@ int test_bbackupd() printf("\n==== Check restore deleted files\n"); { - std::auto_ptr<BackupProtocolClient> client = Connect( - context, 0 /* read-write */); + std::auto_ptr<BackupProtocolClient> client = + ConnectAndLogin(context, 0 /* read-write */); // Do restore and undelete TEST_THAT(BackupClientRestore(*client, deldirid, @@ -2913,12 +3794,14 @@ int test_bbackupd() sSocket.Close(); // Do a compare with the now undeleted files - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query11.log " + "-Wwarning " "\"compare -cEQ Test1/x1 " "testfiles/restore-Test1-x1-2\" quit"); - TEST_RETURN(compareReturnValue, 1); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -2937,7 +3820,7 @@ int test_bbackupd() // 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(); + wait_for_sync_end(); // Now we have about three seconds to work handle = openfile("testfiles/TestDir1/lockedfile", @@ -2950,7 +3833,15 @@ int test_bbackupd() wait_for_sync_end(); TEST_THAT(!TestFileExists("testfiles/" "notifyran.read-error.1")); + } + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + if (handle != 0) + { // this sync should try to back up the file, // and fail, because it's locked wait_for_sync_end(); @@ -2958,45 +3849,82 @@ int test_bbackupd() "notifyran.read-error.1")); 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; + if (handle != 0) + { // now close the file and check that it is // backed up on the next run. CloseHandle(handle); wait_for_sync_end(); + + // still no read errors? 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; + + if (handle != 0) + { // compare, and check that it works // reports the correct error message (and finishes) - compareReturnValue = ::system(BBACKUPQUERY " -q " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query15a.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); 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; + + if (handle != 0) + { // 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 " + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " "-l testfiles/query15.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 3); + "-Werror \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Error); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // close the file again, check that compare // works again CloseHandle(handle); + } - compareReturnValue = ::system(BBACKUPQUERY " -q " + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + if (handle != 0) + { + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query15a.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } #endif @@ -3021,11 +3949,12 @@ int test_bbackupd() // 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 " + compareReturnValue = ::system(BBACKUPQUERY " " "-c testfiles/bbackupd.conf " "-l testfiles/query4a.log " - "\"compare -acQ\" quit"); - TEST_RETURN(compareReturnValue, 1); + "-Wwarning \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, + BackupQueries::ReturnCode::Compare_Same); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Kill it again @@ -3033,10 +3962,12 @@ int test_bbackupd() } } - // List the files on the server + /* + // List the files on the server - why? ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf " "-l testfiles/queryLIST.log \"list -rotdh\" quit"); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + */ #ifndef WIN32 if(::getuid() == 0) @@ -3080,8 +4011,14 @@ int test(int argc, const char *argv[]) r = test_bbackupd(); if(r != 0) { - KillServer(bbackupd_pid); - KillServer(bbstored_pid); + if (bbackupd_pid) + { + KillServer(bbackupd_pid); + } + if (bbstored_pid) + { + KillServer(bbstored_pid); + } return r; } diff --git a/test/bbackupd/testfiles/bbackupd-exclude.conf.in b/test/bbackupd/testfiles/bbackupd-exclude.conf.in new file mode 100644 index 00000000..4c08753f --- /dev/null +++ b/test/bbackupd/testfiles/bbackupd-exclude.conf.in @@ -0,0 +1,47 @@ + +CertificateFile = testfiles/clientCerts.pem +PrivateKeyFile = testfiles/clientPrivKey.pem +TrustedCAsFile = testfiles/clientTrustedCAs.pem + +KeysFile = testfiles/bbackupd.keys + +DataDirectory = testfiles/bbackupd-data + +StoreHostname = localhost +StorePort = 22011 +AccountNumber = 0x01234567 + +UpdateStoreInterval = 3 +MinimumFileAge = 4 +MaxUploadWait = 24 +DeleteRedundantLocationsAfter = 10 + +FileTrackingSizeThreshold = 1024 +DiffingUploadSizeThreshold = 1024 + +MaximumDiffingTime = 3 +KeepAliveTime = 1 + +ExtendedLogging = no +ExtendedLogFile = testfiles/bbackupd.log + +CommandSocket = testfiles/bbackupd.sock + +NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl +SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl + +Server +{ + PidFile = testfiles/bbackupd.pid +} + +BackupLocations +{ + Test1 + { + Path = testfiles/TestDir1 + ExcludeDir = testfiles/TestDir1/spacetest/d3 + ExcludeFile = testfiles/TestDir1/spacetest/f2 + } +} + diff --git a/test/bbackupd/testfiles/bbackupd-snapshot.conf.in b/test/bbackupd/testfiles/bbackupd-snapshot.conf.in new file mode 100644 index 00000000..d245d077 --- /dev/null +++ b/test/bbackupd/testfiles/bbackupd-snapshot.conf.in @@ -0,0 +1,56 @@ + +CertificateFile = testfiles/clientCerts.pem +PrivateKeyFile = testfiles/clientPrivKey.pem +TrustedCAsFile = testfiles/clientTrustedCAs.pem + +KeysFile = testfiles/bbackupd.keys + +DataDirectory = testfiles/bbackupd-data + +StoreHostname = localhost +StorePort = 22011 +AccountNumber = 0x01234567 + +AutomaticBackup = no +UpdateStoreInterval = 0 +MinimumFileAge = 4 +MaxUploadWait = 24 +DeleteRedundantLocationsAfter = 10 + +FileTrackingSizeThreshold = 1024 +DiffingUploadSizeThreshold = 1024 + +MaximumDiffingTime = 3 +KeepAliveTime = 1 + +ExtendedLogging = no +ExtendedLogFile = testfiles/bbackupd.log + +CommandSocket = testfiles/bbackupd.sock + +NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl +SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl + +Server +{ + PidFile = testfiles/bbackupd.pid +} + +BackupLocations +{ + Test1 + { + Path = testfiles/TestDir1 + + ExcludeFile = testfiles/TestDir1/excluded_1 + ExcludeFile = testfiles/TestDir1/excluded_2 + ExcludeFilesRegex = \.excludethis$ + ExcludeFilesRegex = EXCLUDE + AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis + ExcludeDir = testfiles/TestDir1/exclude_dir + ExcludeDir = testfiles/TestDir1/exclude_dir_2 + ExcludeDirsRegex = not_this_dir + AlwaysIncludeDirsRegex = ALWAYSINCLUDE + } +} + diff --git a/test/bbackupd/testfiles/bbackupd-symlink.conf.in b/test/bbackupd/testfiles/bbackupd-symlink.conf.in new file mode 100644 index 00000000..33bb6157 --- /dev/null +++ b/test/bbackupd/testfiles/bbackupd-symlink.conf.in @@ -0,0 +1,55 @@ + +CertificateFile = testfiles/clientCerts.pem +PrivateKeyFile = testfiles/clientPrivKey.pem +TrustedCAsFile = testfiles/clientTrustedCAs.pem + +KeysFile = testfiles/bbackupd.keys + +DataDirectory = testfiles/bbackupd-data + +StoreHostname = localhost +StorePort = 22011 +AccountNumber = 0x01234567 + +UpdateStoreInterval = 3 +MinimumFileAge = 4 +MaxUploadWait = 24 +DeleteRedundantLocationsAfter = 10 + +FileTrackingSizeThreshold = 1024 +DiffingUploadSizeThreshold = 1024 + +MaximumDiffingTime = 3 +KeepAliveTime = 1 + +ExtendedLogging = no +ExtendedLogFile = testfiles/bbackupd.log + +CommandSocket = testfiles/bbackupd.sock + +NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl +SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl + +Server +{ + PidFile = testfiles/bbackupd.pid +} + +BackupLocations +{ + Test1 + { + Path = testfiles/symlink-to-TestDir1 + + ExcludeFile = testfiles/TestDir1/excluded_1 + ExcludeFile = testfiles/TestDir1/excluded_2 + ExcludeFilesRegex = \.excludethis$ + ExcludeFilesRegex = EXCLUDE + AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis + ExcludeDir = testfiles/TestDir1/exclude_dir + ExcludeDir = testfiles/TestDir1/exclude_dir_2 + ExcludeDirsRegex = not_this_dir + AlwaysIncludeDirsRegex = ALWAYSINCLUDE + } +} + diff --git a/test/bbackupd/testfiles/bbackupd-temploc.conf b/test/bbackupd/testfiles/bbackupd-temploc.conf index 86901298..07cbdcd1 100644 --- a/test/bbackupd/testfiles/bbackupd-temploc.conf +++ b/test/bbackupd/testfiles/bbackupd-temploc.conf @@ -8,6 +8,7 @@ KeysFile = testfiles/bbackupd.keys DataDirectory = testfiles/bbackupd-data StoreHostname = localhost +StorePort = 22011 AccountNumber = 0x01234567 UpdateStoreInterval = 3 @@ -48,7 +49,7 @@ BackupLocations } Test2 { - Path = testfiles/TestDir1 + Path = testfiles/TestDir2 } } diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in index aecb3884..712b58b2 100644 --- a/test/bbackupd/testfiles/bbackupd.conf.in +++ b/test/bbackupd/testfiles/bbackupd.conf.in @@ -8,6 +8,7 @@ KeysFile = testfiles/bbackupd.keys DataDirectory = testfiles/bbackupd-data StoreHostname = localhost +StorePort = 22011 AccountNumber = 0x01234567 UpdateStoreInterval = 3 diff --git a/test/bbackupd/testfiles/bbstored.conf b/test/bbackupd/testfiles/bbstored.conf index 18c73a40..87f4fe6b 100644 --- a/test/bbackupd/testfiles/bbstored.conf +++ b/test/bbackupd/testfiles/bbstored.conf @@ -9,7 +9,7 @@ TimeBetweenHousekeeping = 5 Server { PidFile = testfiles/bbstored.pid - ListenAddresses = inet:localhost + ListenAddresses = inet:localhost:22011 CertificateFile = testfiles/serverCerts.pem PrivateKeyFile = testfiles/serverPrivKey.pem TrustedCAsFile = testfiles/serverTrustedCAs.pem diff --git a/test/bbackupd/testfiles/extcheck1.pl.in b/test/bbackupd/testfiles/extcheck1.pl.in index 4d0f2157..74884dd8 100755 --- a/test/bbackupd/testfiles/extcheck1.pl.in +++ b/test/bbackupd/testfiles/extcheck1.pl.in @@ -3,7 +3,10 @@ use strict; 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 |") +unless(open IN,"../../bin/bbackupquery/bbackupquery -Wwarning " . + "-c testfiles/bbackupd.conf " . + "-l testfiles/query4.log " . + "\"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; diff --git a/test/bbackupd/testfiles/extcheck2.pl.in b/test/bbackupd/testfiles/extcheck2.pl.in index 074defc0..3671ad93 100755 --- a/test/bbackupd/testfiles/extcheck2.pl.in +++ b/test/bbackupd/testfiles/extcheck2.pl.in @@ -3,7 +3,10 @@ use strict; 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 |") +unless(open IN,"../../bin/bbackupquery/bbackupquery -Wwarning " . + "-c testfiles/bbackupd.conf " . + "-l testfiles/query4.log " . + "\"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; diff --git a/test/bbackupd/testfiles/notifyscript.pl.in b/test/bbackupd/testfiles/notifyscript.pl.in index 89741e46..d3e324e9 100755 --- a/test/bbackupd/testfiles/notifyscript.pl.in +++ b/test/bbackupd/testfiles/notifyscript.pl.in @@ -1,7 +1,16 @@ #!@TARGET_PERL@ - my $f = 'testfiles/notifyran.'.$ARGV[0].'.'; + +if (-e 'testfiles/notifyscript.tag') +{ + open FILE, '< testfiles/notifyscript.tag' or die $!; + my $tag = <FILE>; + chomp $tag; + $f .= "$tag."; + close FILE; +} + my $n = 1; while(-e $f.$n) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index eb057228..da2133cd 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -57,15 +57,15 @@ void test_conversions() ConfigurationVerifyKey verifykeys1_1_1[] = { - {"bing", 0, ConfigTest_Exists, 0}, - {"carrots", 0, ConfigTest_Exists | ConfigTest_IsInt, 0}, - {"terrible", 0, ConfigTest_Exists | ConfigTest_LastEntry, 0} + ConfigurationVerifyKey("bing", ConfigTest_Exists), + ConfigurationVerifyKey("carrots", ConfigTest_Exists | ConfigTest_IsInt), + ConfigurationVerifyKey("terrible", ConfigTest_Exists | ConfigTest_LastEntry) }; ConfigurationVerifyKey verifykeys1_1_2[] = { - {"fish", 0, ConfigTest_Exists | ConfigTest_IsInt, 0}, - {"string", 0, ConfigTest_Exists | ConfigTest_LastEntry, 0} + ConfigurationVerifyKey("fish", ConfigTest_Exists | ConfigTest_IsInt), + ConfigurationVerifyKey("string", ConfigTest_Exists | ConfigTest_LastEntry) }; @@ -89,15 +89,15 @@ ConfigurationVerify verifysub1_1[] = ConfigurationVerifyKey verifykeys1_1[] = { - {"value", 0, ConfigTest_Exists | ConfigTest_IsInt, 0}, - {"string1", 0, ConfigTest_Exists, 0}, - {"string2", 0, ConfigTest_Exists | ConfigTest_LastEntry, 0} + ConfigurationVerifyKey("value", ConfigTest_Exists | ConfigTest_IsInt), + ConfigurationVerifyKey("string1", ConfigTest_Exists), + ConfigurationVerifyKey("string2", ConfigTest_Exists | ConfigTest_LastEntry) }; ConfigurationVerifyKey verifykeys1_2[] = { - {"carrots", 0, ConfigTest_Exists | ConfigTest_IsInt, 0}, - {"string", 0, ConfigTest_Exists | ConfigTest_LastEntry, 0} + ConfigurationVerifyKey("carrots", ConfigTest_Exists | ConfigTest_IsInt), + ConfigurationVerifyKey("string", ConfigTest_Exists | ConfigTest_LastEntry) }; ConfigurationVerify verifysub1[] = @@ -120,14 +120,15 @@ ConfigurationVerify verifysub1[] = ConfigurationVerifyKey verifykeys1[] = { - {"notExpected", 0, 0, 0}, - {"HasDefaultValue", "Lovely default value", 0, 0}, - {"MultiValue", 0, ConfigTest_MultiValueAllowed, 0}, - {"BoolTrue1", 0, ConfigTest_IsBool, 0}, - {"BoolTrue2", 0, ConfigTest_IsBool, 0}, - {"BoolFalse1", 0, ConfigTest_IsBool, 0}, - {"BoolFalse2", 0, ConfigTest_IsBool, 0}, - {"TOPlevel", 0, ConfigTest_LastEntry | ConfigTest_Exists, 0} + ConfigurationVerifyKey("notExpected", 0), + ConfigurationVerifyKey("HasDefaultValue", 0, "Lovely default value"), + ConfigurationVerifyKey("MultiValue", ConfigTest_MultiValueAllowed), + ConfigurationVerifyKey("BoolTrue1", ConfigTest_IsBool), + ConfigurationVerifyKey("BoolTrue2", ConfigTest_IsBool), + ConfigurationVerifyKey("BoolFalse1", ConfigTest_IsBool), + ConfigurationVerifyKey("BoolFalse2", ConfigTest_IsBool), + ConfigurationVerifyKey("TOPlevel", + ConfigTest_LastEntry | ConfigTest_Exists) }; ConfigurationVerify verify = @@ -297,7 +298,7 @@ int test(int argc, const char *argv[]) // Check that using timer methods without initialisation // throws an assertion failure. Can only do this in debug mode - #ifndef NDEBUG + #ifndef BOX_RELEASE_BUILD TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), CommonException, AssertFailed); TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), @@ -305,7 +306,7 @@ int test(int argc, const char *argv[]) #endif // TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); - #ifndef NDEBUG + #ifndef BOX_RELEASE_BUILD TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); #endif @@ -314,7 +315,7 @@ int test(int argc, const char *argv[]) Timers::Init(); // Check that double initialisation throws an exception - #ifndef NDEBUG + #ifndef BOX_RELEASE_BUILD TEST_CHECK_THROWS(Timers::Init(), CommonException, AssertFailed); #endif @@ -323,17 +324,17 @@ int test(int argc, const char *argv[]) Timers::Cleanup(); // Check that double cleanup throws an exception - #ifndef NDEBUG + #ifndef BOX_RELEASE_BUILD 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); + Timer t0(0, "t0"); // should never expire + Timer t1(1, "t1"); + Timer t2(2, "t2"); + Timer t3(3, "t3"); TEST_THAT(!t0.HasExpired()); TEST_THAT(!t1.HasExpired()); @@ -352,8 +353,8 @@ int test(int argc, const char *argv[]) TEST_THAT(t2.HasExpired()); TEST_THAT(!t3.HasExpired()); - t1 = Timer(1); - t2 = Timer(2); + t1 = Timer(1, "t1a"); + t2 = Timer(2, "t2a"); TEST_THAT(!t0.HasExpired()); TEST_THAT(!t1.HasExpired()); TEST_THAT(!t2.HasExpired()); diff --git a/test/compress/testcompress.cpp b/test/compress/testcompress.cpp index 592dd641..4a522d31 100644 --- a/test/compress/testcompress.cpp +++ b/test/compress/testcompress.cpp @@ -90,7 +90,8 @@ int test_stream() // Check sizes TEST_THAT(poutput->GetSize() < source.GetSize()); - TRACE2("compressed size = %d, source size = %d\n", poutput->GetSize(), source.GetSize()); + BOX_TRACE("compressed size = " << poutput->GetSize() << + ", source size = " << source.GetSize()); // Decompress the data { diff --git a/test/httpserver/testfiles/httpserver.conf b/test/httpserver/testfiles/httpserver.conf new file mode 100644 index 00000000..1a1c4644 --- /dev/null +++ b/test/httpserver/testfiles/httpserver.conf @@ -0,0 +1,8 @@ + +AddressPrefix = http://localhost:1080 + +Server +{ + PidFile = testfiles/httpserver.pid + ListenAddresses = inet:localhost:1080 +} diff --git a/test/httpserver/testfiles/photos/puppy.jpg b/test/httpserver/testfiles/photos/puppy.jpg new file mode 100644 index 00000000..a326a6a7 --- /dev/null +++ b/test/httpserver/testfiles/photos/puppy.jpg @@ -0,0 +1 @@ +omgpuppies! diff --git a/test/httpserver/testfiles/testrequests.pl b/test/httpserver/testfiles/testrequests.pl new file mode 100755 index 00000000..85380ee0 --- /dev/null +++ b/test/httpserver/testfiles/testrequests.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl +use strict; +use LWP::UserAgent; + +my $url_base = 'http://localhost:1080'; + +my $ua = LWP::UserAgent->new(env_proxy => 0, keep_alive => 1, timeout => 30); + +print "GET request...\n"; + +my $response1 = $ua->get("$url_base/test-one/34/341s/234?p1=vOne&p2=vTwo"); +die $response1->content unless $response1->is_success(); + +my $content = $response1->content(); + +check_url($content, '/test-one/34/341s/234'); +check_params($content, 'p1'=>'vOne','p2'=>'vTwo'); + +print "POST request...\n"; + +my %post = ('sdfgksjhdfsd'=>'dfvsiufy2e3434','sxciuhwf8723e4'=>'238947829334', + '&sfsfsfskfhs'=>'?hdkfjhsjfds','fdsf=sdf2342'=>'3984sajhksda'); + +my $response2 = $ua->post("$url_base/tdskjhfsjdkhf2943734?p1=vOne&p2=vTwo", \%post); + +my $content2 = $response2->content(); + +check_url($content2, '/tdskjhfsjdkhf2943734'); +check_params($content2, %post); + +print "HEAD request...\n"; + +my $response3 = $ua->head("$url_base/tdskjhfsdfkjhs"); + +if($response3->content() ne '') +{ + print "Content not zero length\n"; + exit(1); +} + +if($response3->code() != 200) +{ + print "Wrong response code\n"; + exit(1); +} + +print "Redirected GET request...\n"; + +my $response4 = $ua->get("$url_base/redirect?key=value"); +exit 4 unless $response4->is_success(); + +my $content4 = $response4->content(); + +check_url($content4, '/redirected'); +check_params($content4); + +print "Cookie tests...\n"; + +# from examples in specs +test_cookies('CUSTOMER=WILE_E_COYOTE', 'CUSTOMER=WILE_E_COYOTE'); +test_cookies('CUSTOMER="WILE_E_COYOTE"; C2="pants"', 'CUSTOMER=WILE_E_COYOTE', 'C2=pants'); +test_cookies('CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001', 'CUSTOMER=WILE_E_COYOTE', 'PART_NUMBER=ROCKET_LAUNCHER_0001'); +test_cookies('CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX', 'CUSTOMER=WILE_E_COYOTE', 'PART_NUMBER=ROCKET_LAUNCHER_0001', 'SHIPPING=FEDEX'); +test_cookies('$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"', 'Customer=WILE_E_COYOTE'); +test_cookies('$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme" ', + 'Customer=WILE_E_COYOTE', 'Part_Number=Rocket_Launcher_0001'); +test_cookies(qq!\$Version="1"; Customer="WILE_E_COYOTE"; \$Path="/acme"; Part_Number="Rocket_Launcher_0001"; \$Path="/acme"; Shipping="FedEx"; \t \$Path="/acme"!, + 'Customer=WILE_E_COYOTE', 'Part_Number=Rocket_Launcher_0001', 'Shipping=FedEx'); + +# test the server setting cookies in the UA +require HTTP::Cookies; +$ua->cookie_jar(HTTP::Cookies->new()); +$ua->get("$url_base/set-cookie"); +test_cookies('', 'SetByServer=Value1'); + +sub test_cookies +{ + my ($c_str, @cookies) = @_; + test_cookies2($c_str, @cookies); + $c_str =~ s/;/,/g; + test_cookies2($c_str, @cookies); +} + +sub test_cookies2 +{ + my ($c_str, @cookies) = @_; + my $r; + if($c_str ne '') + { + $r = $ua->get("$url_base/cookie", 'Cookie' => $c_str); + } + else + { + $r = $ua->get("$url_base/cookie"); + } + my $c = $r->content(); + for(@cookies) + { + unless($c =~ m/COOKIE:$_<br>/) + { + print "Cookie $_ not found\n"; + exit(1); + } + } +} + + +sub check_url +{ + my ($c,$url) = @_; + unless($c =~ m~URI:</b> (.+?)</p>~) + { + print "URI not found\n"; + exit(1); + } + if($url ne $1) + { + print "Wrong URI in content\n"; + exit(1); + } +} + +sub check_params +{ + my ($c,%params) = @_; + + while($c =~ m/^PARAM:(.+)=(.+?)<br>/mg) + { + if($params{$1} ne $2) + { + print "$1=$2 not found in response\n"; + exit(1); + } + delete $params{$1} + } + + my @k = keys %params; + if($#k != -1) + { + print "Didn't find all params\n"; + exit(1); + } +} diff --git a/test/httpserver/testhttpserver.cpp b/test/httpserver/testhttpserver.cpp new file mode 100644 index 00000000..c38ef8fe --- /dev/null +++ b/test/httpserver/testhttpserver.cpp @@ -0,0 +1,661 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: testhttpserver.cpp +// Purpose: Test code for HTTP server class +// Created: 26/3/04 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#include <cstdio> +#include <cstring> +#include <ctime> + +#ifdef HAVE_SIGNAL_H + #include <signal.h> +#endif + +#include <openssl/hmac.h> + +#include "autogen_HTTPException.h" +#include "HTTPRequest.h" +#include "HTTPResponse.h" +#include "HTTPServer.h" +#include "IOStreamGetLine.h" +#include "S3Client.h" +#include "ServerControl.h" +#include "Test.h" +#include "decode.h" +#include "encode.h" + +#include "MemLeakFindOn.h" + +class TestWebServer : public HTTPServer +{ +public: + TestWebServer(); + ~TestWebServer(); + + virtual void Handle(HTTPRequest &rRequest, HTTPResponse &rResponse); + +}; + +// Build a nice HTML response, so this can also be tested neatly in a browser +void TestWebServer::Handle(HTTPRequest &rRequest, HTTPResponse &rResponse) +{ + // Test redirection mechanism + if(rRequest.GetRequestURI() == "/redirect") + { + rResponse.SetAsRedirect("/redirected"); + return; + } + + // Set a cookie? + if(rRequest.GetRequestURI() == "/set-cookie") + { + rResponse.SetCookie("SetByServer", "Value1"); + } + + #define DEFAULT_RESPONSE_1 "<html>\n<head><title>TEST SERVER RESPONSE</title></head>\n<body><h1>Test response</h1>\n<p><b>URI:</b> " + #define DEFAULT_RESPONSE_3 "</p>\n<p><b>Query string:</b> " + #define DEFAULT_RESPONSE_4 "</p>\n<p><b>Method:</b> " + #define DEFAULT_RESPONSE_5 "</p>\n<p><b>Decoded query:</b><br>" + #define DEFAULT_RESPONSE_6 "</p>\n<p><b>Content type:</b> " + #define DEFAULT_RESPONSE_7 "</p>\n<p><b>Content length:</b> " + #define DEFAULT_RESPONSE_8 "</p>\n<p><b>Cookies:</b><br>\n" + #define DEFAULT_RESPONSE_2 "</p>\n</body>\n</html>\n" + + rResponse.SetResponseCode(HTTPResponse::Code_OK); + rResponse.SetContentType("text/html"); + rResponse.Write(DEFAULT_RESPONSE_1, sizeof(DEFAULT_RESPONSE_1) - 1); + const std::string &ruri(rRequest.GetRequestURI()); + rResponse.Write(ruri.c_str(), ruri.size()); + rResponse.Write(DEFAULT_RESPONSE_3, sizeof(DEFAULT_RESPONSE_3) - 1); + const std::string &rquery(rRequest.GetQueryString()); + rResponse.Write(rquery.c_str(), rquery.size()); + rResponse.Write(DEFAULT_RESPONSE_4, sizeof(DEFAULT_RESPONSE_4) - 1); + { + const char *m = "????"; + switch(rRequest.GetMethod()) + { + case HTTPRequest::Method_GET: m = "GET "; break; + case HTTPRequest::Method_HEAD: m = "HEAD"; break; + case HTTPRequest::Method_POST: m = "POST"; break; + default: m = "UNKNOWN"; + } + rResponse.Write(m, 4); + } + rResponse.Write(DEFAULT_RESPONSE_5, sizeof(DEFAULT_RESPONSE_5) - 1); + { + const HTTPRequest::Query_t &rquery(rRequest.GetQuery()); + for(HTTPRequest::Query_t::const_iterator i(rquery.begin()); i != rquery.end(); ++i) + { + rResponse.Write("\nPARAM:", 7); + rResponse.Write(i->first.c_str(), i->first.size()); + rResponse.Write("=", 1); + rResponse.Write(i->second.c_str(), i->second.size()); + rResponse.Write("<br>\n", 4); + } + } + rResponse.Write(DEFAULT_RESPONSE_6, sizeof(DEFAULT_RESPONSE_6) - 1); + const std::string &rctype(rRequest.GetContentType()); + rResponse.Write(rctype.c_str(), rctype.size()); + rResponse.Write(DEFAULT_RESPONSE_7, sizeof(DEFAULT_RESPONSE_7) - 1); + { + char l[32]; + rResponse.Write(l, ::sprintf(l, "%d", rRequest.GetContentLength())); + } + rResponse.Write(DEFAULT_RESPONSE_8, sizeof(DEFAULT_RESPONSE_8) - 1); + const HTTPRequest::CookieJar_t *pcookies = rRequest.GetCookies(); + if(pcookies != 0) + { + HTTPRequest::CookieJar_t::const_iterator i(pcookies->begin()); + for(; i != pcookies->end(); ++i) + { + char t[512]; + rResponse.Write(t, ::sprintf(t, "COOKIE:%s=%s<br>\n", i->first.c_str(), i->second.c_str())); + } + } + rResponse.Write(DEFAULT_RESPONSE_2, sizeof(DEFAULT_RESPONSE_2) - 1); +} + +TestWebServer::TestWebServer() {} +TestWebServer::~TestWebServer() {} + +class S3Simulator : public HTTPServer +{ +public: + S3Simulator() { } + ~S3Simulator() { } + + virtual void Handle(HTTPRequest &rRequest, HTTPResponse &rResponse); + virtual void HandleGet(HTTPRequest &rRequest, HTTPResponse &rResponse); + virtual void HandlePut(HTTPRequest &rRequest, HTTPResponse &rResponse); +}; + +void S3Simulator::Handle(HTTPRequest &rRequest, HTTPResponse &rResponse) +{ + // if anything goes wrong, return a 500 error + rResponse.SetResponseCode(HTTPResponse::Code_InternalServerError); + rResponse.SetContentType("text/plain"); + + try + { + // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html + std::string access_key = "0PN5J17HBGZHT7JJ3X82"; + std::string secret_key = "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"; + + std::string md5, date, bucket; + rRequest.GetHeader("Content-MD5", &md5); + rRequest.GetHeader("Date", &date); + + std::string host = rRequest.GetHostName(); + std::string s3suffix = ".s3.amazonaws.com"; + if (host.size() > s3suffix.size()) + { + std::string suffix = host.substr(host.size() - + s3suffix.size(), s3suffix.size()); + if (suffix == s3suffix) + { + bucket = host.substr(0, host.size() - + s3suffix.size()); + } + } + + std::ostringstream data; + data << rRequest.GetVerb() << "\n"; + data << md5 << "\n"; + data << rRequest.GetContentType() << "\n"; + data << date << "\n"; + + std::vector<HTTPRequest::Header> headers = rRequest.GetHeaders(); + + for (std::vector<HTTPRequest::Header>::iterator + i = headers.begin(); i != headers.end(); i++) + { + std::string& rHeaderName = i->first; + + for (std::string::iterator c = rHeaderName.begin(); + c != rHeaderName.end() && *c != ':'; c++) + { + *c = tolower(*c); + } + } + + sort(headers.begin(), headers.end()); + + for (std::vector<HTTPRequest::Header>::iterator + i = headers.begin(); i != headers.end(); i++) + { + if (i->first.substr(0, 5) == "x-amz") + { + data << i->first << ":" << i->second << "\n"; + } + } + + if (! bucket.empty()) + { + data << "/" << bucket; + } + + data << rRequest.GetRequestURI(); + std::string data_string = data.str(); + + unsigned char digest_buffer[EVP_MAX_MD_SIZE]; + unsigned int digest_size = sizeof(digest_buffer); + /* unsigned char* mac = */ HMAC(EVP_sha1(), + secret_key.c_str(), secret_key.size(), + (const unsigned char*)data_string.c_str(), + data_string.size(), digest_buffer, &digest_size); + std::string digest((const char *)digest_buffer, digest_size); + + base64::encoder encoder; + std::string expectedAuth = "AWS " + access_key + ":" + + encoder.encode(digest); + + if (expectedAuth[expectedAuth.size() - 1] == '\n') + { + expectedAuth = expectedAuth.substr(0, + expectedAuth.size() - 1); + } + + std::string actualAuth; + if (!rRequest.GetHeader("Authorization", &actualAuth) || + actualAuth != expectedAuth) + { + rResponse.SetResponseCode(HTTPResponse::Code_Unauthorized); + } + else if (rRequest.GetMethod() == HTTPRequest::Method_GET) + { + HandleGet(rRequest, rResponse); + } + else if (rRequest.GetMethod() == HTTPRequest::Method_PUT) + { + HandlePut(rRequest, rResponse); + } + else + { + rResponse.SetResponseCode(HTTPResponse::Code_MethodNotAllowed); + } + } + catch (CommonException &ce) + { + rResponse.IOStream::Write(ce.what()); + } + catch (std::exception &e) + { + rResponse.IOStream::Write(e.what()); + } + catch (...) + { + rResponse.IOStream::Write("Unknown error"); + } + + return; +} + +void S3Simulator::HandleGet(HTTPRequest &rRequest, HTTPResponse &rResponse) +{ + std::string path = "testfiles"; + path += rRequest.GetRequestURI(); + std::auto_ptr<FileStream> apFile; + + try + { + apFile.reset(new FileStream(path)); + } + catch (CommonException &ce) + { + if (ce.GetSubType() == CommonException::OSFileOpenError) + { + rResponse.SetResponseCode(HTTPResponse::Code_NotFound); + } + else if (ce.GetSubType() == CommonException::AccessDenied) + { + rResponse.SetResponseCode(HTTPResponse::Code_Forbidden); + } + throw; + } + + // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingRESTOperations.html + apFile->CopyStreamTo(rResponse); + rResponse.AddHeader("x-amz-id-2", "qBmKRcEWBBhH6XAqsKU/eg24V3jf/kWKN9dJip1L/FpbYr9FDy7wWFurfdQOEMcY"); + rResponse.AddHeader("x-amz-request-id", "F2A8CCCA26B4B26D"); + rResponse.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + rResponse.AddHeader("Last-Modified", "Sun, 1 Jan 2006 12:00:00 GMT"); + rResponse.AddHeader("ETag", "\"828ef3fdfa96f00ad9f27c383fc9ac7f\""); + rResponse.AddHeader("Server", "AmazonS3"); + rResponse.SetResponseCode(HTTPResponse::Code_OK); +} + +void S3Simulator::HandlePut(HTTPRequest &rRequest, HTTPResponse &rResponse) +{ + std::string path = "testfiles"; + path += rRequest.GetRequestURI(); + std::auto_ptr<FileStream> apFile; + + try + { + apFile.reset(new FileStream(path, O_CREAT | O_WRONLY)); + } + catch (CommonException &ce) + { + if (ce.GetSubType() == CommonException::OSFileOpenError) + { + rResponse.SetResponseCode(HTTPResponse::Code_NotFound); + } + else if (ce.GetSubType() == CommonException::AccessDenied) + { + rResponse.SetResponseCode(HTTPResponse::Code_Forbidden); + } + throw; + } + + if (rRequest.IsExpectingContinue()) + { + rResponse.SendContinue(); + } + + rRequest.ReadContent(*apFile); + + // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTObjectPUT.html + rResponse.AddHeader("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7"); + rResponse.AddHeader("x-amz-request-id", "F2A8CCCA26B4B26D"); + rResponse.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + rResponse.AddHeader("Last-Modified", "Sun, 1 Jan 2006 12:00:00 GMT"); + rResponse.AddHeader("ETag", "\"828ef3fdfa96f00ad9f27c383fc9ac7f\""); + rResponse.SetContentType(""); + rResponse.AddHeader("Server", "AmazonS3"); + rResponse.SetResponseCode(HTTPResponse::Code_OK); +} + +int test(int argc, const char *argv[]) +{ + if(argc >= 2 && ::strcmp(argv[1], "server") == 0) + { + // Run a server + TestWebServer server; + return server.Main("doesnotexist", argc - 1, argv + 1); + } + + if(argc >= 2 && ::strcmp(argv[1], "s3server") == 0) + { + // Run a server + S3Simulator server; + return server.Main("doesnotexist", argc - 1, argv + 1); + } + + // Start the server + int pid = LaunchServer("./test server testfiles/httpserver.conf", "testfiles/httpserver.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid <= 0) + { + return 0; + } + + // Run the request script + TEST_THAT(::system("perl testfiles/testrequests.pl") == 0); + + signal(SIGPIPE, SIG_IGN); + + SocketStream sock; + sock.Open(Socket::TypeINET, "localhost", 1080); + + for (int i = 0; i < 4; i++) + { + HTTPRequest request(HTTPRequest::Method_GET, + "/test-one/34/341s/234?p1=vOne&p2=vTwo"); + + if (i < 2) + { + // first set of passes has keepalive off by default, + // so when i == 1 the socket has already been closed + // by the server, and we'll get -EPIPE when we try + // to send the request. + request.SetClientKeepAliveRequested(false); + } + else + { + request.SetClientKeepAliveRequested(true); + } + + if (i == 1) + { + sleep(1); // need time for our process to realise + // that the peer has died, otherwise no SIGPIPE :( + TEST_CHECK_THROWS(request.Send(sock, + IOStream::TimeOutInfinite), + ConnectionException, SocketWriteError); + sock.Close(); + sock.Open(Socket::TypeINET, "localhost", 1080); + continue; + } + else + { + request.Send(sock, IOStream::TimeOutInfinite); + } + + HTTPResponse response; + response.Receive(sock); + + TEST_THAT(response.GetResponseCode() == HTTPResponse::Code_OK); + TEST_THAT(response.GetContentType() == "text/html"); + + IOStreamGetLine getline(response); + std::string line; + + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<html>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<head><title>TEST SERVER RESPONSE</title></head>", + line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<body><h1>Test response</h1>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>URI:</b> /test-one/34/341s/234</p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Query string:</b> p1=vOne&p2=vTwo</p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Method:</b> GET </p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Decoded query:</b><br>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("PARAM:p1=vOne<br>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("PARAM:p2=vTwo<br></p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Content type:</b> </p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Content length:</b> -1</p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("<p><b>Cookies:</b><br>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("</p>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("</body>", line); + TEST_THAT(getline.GetLine(line)); + TEST_EQUAL("</html>", line); + } + + // Kill it + TEST_THAT(KillServer(pid)); + TestRemoteProcessMemLeaks("generic-httpserver.memleaks"); + + // correct, official signature should succeed + { + // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html + HTTPRequest request(HTTPRequest::Method_GET, "/photos/puppy.jpg"); + request.SetHostName("johnsmith.s3.amazonaws.com"); + request.AddHeader("Date", "Tue, 27 Mar 2007 19:36:42 +0000"); + request.AddHeader("Authorization", + "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA="); + + S3Simulator simulator; + + CollectInBufferStream response_buffer; + HTTPResponse response(&response_buffer); + + simulator.Handle(request, response); + TEST_EQUAL(200, response.GetResponseCode()); + + std::string response_data((const char *)response.GetBuffer(), + response.GetSize()); + TEST_EQUAL("omgpuppies!\n", response_data); + } + + // modified signature should fail + { + // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html + HTTPRequest request(HTTPRequest::Method_GET, "/photos/puppy.jpg"); + request.SetHostName("johnsmith.s3.amazonaws.com"); + request.AddHeader("Date", "Tue, 27 Mar 2007 19:36:42 +0000"); + request.AddHeader("Authorization", + "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbB="); + + S3Simulator simulator; + + CollectInBufferStream response_buffer; + HTTPResponse response(&response_buffer); + + simulator.Handle(request, response); + TEST_EQUAL(401, response.GetResponseCode()); + + std::string response_data((const char *)response.GetBuffer(), + response.GetSize()); + TEST_EQUAL("", response_data); + } + + // S3Client tests + { + S3Simulator simulator; + S3Client client(&simulator, "johnsmith.s3.amazonaws.com", + "0PN5J17HBGZHT7JJ3X82", + "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"); + + HTTPResponse response = client.GetObject("/photos/puppy.jpg"); + TEST_EQUAL(200, response.GetResponseCode()); + std::string response_data((const char *)response.GetBuffer(), + response.GetSize()); + TEST_EQUAL("omgpuppies!\n", response_data); + + // make sure that assigning to HTTPResponse does clear stream + response = client.GetObject("/photos/puppy.jpg"); + TEST_EQUAL(200, response.GetResponseCode()); + response_data = std::string((const char *)response.GetBuffer(), + response.GetSize()); + TEST_EQUAL("omgpuppies!\n", response_data); + + response = client.GetObject("/nonexist"); + TEST_EQUAL(404, response.GetResponseCode()); + + FileStream fs("testfiles/testrequests.pl"); + response = client.PutObject("/newfile", fs); + TEST_EQUAL(200, response.GetResponseCode()); + + response = client.GetObject("/newfile"); + TEST_EQUAL(200, response.GetResponseCode()); + TEST_THAT(fs.CompareWith(response)); + TEST_EQUAL(0, ::unlink("testfiles/newfile")); + } + + { + HTTPRequest request(HTTPRequest::Method_PUT, + "/newfile"); + request.SetHostName("quotes.s3.amazonaws.com"); + request.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:XtMYZf0hdOo4TdPYQknZk0Lz7rw="); + request.AddHeader("Content-Type", "text/plain"); + + FileStream fs("testfiles/testrequests.pl"); + fs.CopyStreamTo(request); + request.SetForReading(); + + CollectInBufferStream response_buffer; + HTTPResponse response(&response_buffer); + + S3Simulator simulator; + simulator.Handle(request, response); + + TEST_EQUAL(200, response.GetResponseCode()); + TEST_EQUAL("LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7", response.GetHeaderValue("x-amz-id-2")); + TEST_EQUAL("F2A8CCCA26B4B26D", response.GetHeaderValue("x-amz-request-id")); + TEST_EQUAL("Wed, 01 Mar 2006 12:00:00 GMT", response.GetHeaderValue("Date")); + TEST_EQUAL("Sun, 1 Jan 2006 12:00:00 GMT", response.GetHeaderValue("Last-Modified")); + TEST_EQUAL("\"828ef3fdfa96f00ad9f27c383fc9ac7f\"", response.GetHeaderValue("ETag")); + TEST_EQUAL("", response.GetContentType()); + TEST_EQUAL("AmazonS3", response.GetHeaderValue("Server")); + TEST_EQUAL(0, response.GetSize()); + + FileStream f1("testfiles/testrequests.pl"); + FileStream f2("testfiles/newfile"); + TEST_THAT(f1.CompareWith(f2)); + TEST_EQUAL(0, ::unlink("testfiles/newfile")); + } + + // Start the S3Simulator server + pid = LaunchServer("./test s3server testfiles/httpserver.conf", + "testfiles/httpserver.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid <= 0) + { + return 0; + } + + sock.Close(); + sock.Open(Socket::TypeINET, "localhost", 1080); + + { + HTTPRequest request(HTTPRequest::Method_GET, "/nonexist"); + request.SetHostName("quotes.s3.amazonaws.com"); + request.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:0cSX/YPdtXua1aFFpYmH1tc0ajA="); + request.SetClientKeepAliveRequested(true); + request.Send(sock, IOStream::TimeOutInfinite); + + HTTPResponse response; + response.Receive(sock); + std::string value; + TEST_EQUAL(404, response.GetResponseCode()); + } + + // Make file inaccessible, should cause server to return a 403 error, + // unless of course the test is run as root :) + { + TEST_THAT(chmod("testfiles/testrequests.pl", 0) == 0); + HTTPRequest request(HTTPRequest::Method_GET, + "/testrequests.pl"); + request.SetHostName("quotes.s3.amazonaws.com"); + request.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:qc1e8u8TVl2BpIxwZwsursIb8U8="); + request.SetClientKeepAliveRequested(true); + request.Send(sock, IOStream::TimeOutInfinite); + + HTTPResponse response; + response.Receive(sock); + std::string value; + TEST_EQUAL(403, response.GetResponseCode()); + TEST_THAT(chmod("testfiles/testrequests.pl", 0755) == 0); + } + + { + HTTPRequest request(HTTPRequest::Method_GET, + "/testrequests.pl"); + request.SetHostName("quotes.s3.amazonaws.com"); + request.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:qc1e8u8TVl2BpIxwZwsursIb8U8="); + request.SetClientKeepAliveRequested(true); + request.Send(sock, IOStream::TimeOutInfinite); + + HTTPResponse response; + response.Receive(sock); + std::string value; + TEST_EQUAL(200, response.GetResponseCode()); + TEST_EQUAL("qBmKRcEWBBhH6XAqsKU/eg24V3jf/kWKN9dJip1L/FpbYr9FDy7wWFurfdQOEMcY", response.GetHeaderValue("x-amz-id-2")); + TEST_EQUAL("F2A8CCCA26B4B26D", response.GetHeaderValue("x-amz-request-id")); + TEST_EQUAL("Wed, 01 Mar 2006 12:00:00 GMT", response.GetHeaderValue("Date")); + TEST_EQUAL("Sun, 1 Jan 2006 12:00:00 GMT", response.GetHeaderValue("Last-Modified")); + TEST_EQUAL("\"828ef3fdfa96f00ad9f27c383fc9ac7f\"", response.GetHeaderValue("ETag")); + TEST_EQUAL("text/plain", response.GetContentType()); + TEST_EQUAL("AmazonS3", response.GetHeaderValue("Server")); + + FileStream file("testfiles/testrequests.pl"); + TEST_THAT(file.CompareWith(response)); + } + + { + HTTPRequest request(HTTPRequest::Method_PUT, + "/newfile"); + request.SetHostName("quotes.s3.amazonaws.com"); + request.AddHeader("Date", "Wed, 01 Mar 2006 12:00:00 GMT"); + request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:kfY1m6V3zTufRy2kj92FpQGKz4M="); + request.AddHeader("Content-Type", "text/plain"); + FileStream fs("testfiles/testrequests.pl"); + HTTPResponse response; + request.SendWithStream(sock, + IOStream::TimeOutInfinite /* or 10000 milliseconds */, + &fs, response); + std::string value; + TEST_EQUAL(200, response.GetResponseCode()); + TEST_EQUAL("LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7", response.GetHeaderValue("x-amz-id-2")); + TEST_EQUAL("F2A8CCCA26B4B26D", response.GetHeaderValue("x-amz-request-id")); + TEST_EQUAL("Wed, 01 Mar 2006 12:00:00 GMT", response.GetHeaderValue("Date")); + TEST_EQUAL("Sun, 1 Jan 2006 12:00:00 GMT", response.GetHeaderValue("Last-Modified")); + TEST_EQUAL("\"828ef3fdfa96f00ad9f27c383fc9ac7f\"", response.GetHeaderValue("ETag")); + TEST_EQUAL("", response.GetContentType()); + TEST_EQUAL("AmazonS3", response.GetHeaderValue("Server")); + TEST_EQUAL(0, response.GetSize()); + + FileStream f1("testfiles/testrequests.pl"); + FileStream f2("testfiles/newfile"); + TEST_THAT(f1.CompareWith(f2)); + } + + // Kill it + TEST_THAT(KillServer(pid)); + TestRemoteProcessMemLeaks("generic-httpserver.memleaks"); + + return 0; +} + diff --git a/test/raidfile/testraidfile.cpp b/test/raidfile/testraidfile.cpp index 40703de5..f15fec27 100644 --- a/test/raidfile/testraidfile.cpp +++ b/test/raidfile/testraidfile.cpp @@ -622,7 +622,8 @@ int test(int argc, const char *argv[]) TEST_THAT(n2 != n3); TEST_THAT(n1 != n3); TEST_THAT(n1 == n4); // ie wraps around - TRACE3("Gen paths= '%s','%s',%s'\n", n1.c_str(), n2.c_str(), n3.c_str()); + BOX_TRACE("Gen paths = '" << n1 << "', '" << n2 << + "', '" << n3); } // Create a RaidFile |