summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlib/server/makeprotocol.pl.in27
-rw-r--r--test/backupstore/testbackupstore.cpp232
2 files changed, 165 insertions, 94 deletions
diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in
index 348c85d3..7d318258 100755
--- a/lib/server/makeprotocol.pl.in
+++ b/lib/server/makeprotocol.pl.in
@@ -1068,17 +1068,30 @@ void $server_or_client_class\::DoServer($context_class &rContext)
std::auto_ptr<$message_base_class> preply;
// Run the command
- if(pobj->HasStreamWithCommand())
+ try
{
- std::auto_ptr<IOStream> apDataStream = ReceiveStream();
- SelfFlushingStream autoflush(*apDataStream);
- preply = pobj->DoCommand(*this, rContext, *apDataStream);
+ if(pobj->HasStreamWithCommand())
+ {
+ std::auto_ptr<IOStream> apDataStream = ReceiveStream();
+ SelfFlushingStream autoflush(*apDataStream);
+ preply = pobj->DoCommand(*this, rContext, *apDataStream);
+ }
+ else
+ {
+ preply = pobj->DoCommand(*this, rContext);
+ }
}
- else
+ catch (std::exception &e)
{
- preply = pobj->DoCommand(*this, rContext);
+ Send($cmd_classes{$error_message}());
+ throw;
}
-
+ catch (...)
+ {
+ Send($cmd_classes{$error_message}());
+ throw;
+ }
+
// Send the reply
Send(*preply);
diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index c19618ec..481f535d 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.cpp
@@ -256,6 +256,12 @@ bool teardown_test_backupstore()
return status;
}
+#define FAIL { \
+ std::ostringstream os; \
+ os << "failed at " << __FUNCTION__ << ":" << __LINE__; \
+ return fail(); \
+}
+
bool test_filename_encoding()
{
SETUP();
@@ -1187,7 +1193,7 @@ int64_t assert_readonly_connection_succeeds(BackupProtocolCallable& protocol)
bool test_multiple_uploads()
{
SETUP();
- TEST_THAT_THROWONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), FAIL);
std::auto_ptr<BackupProtocolCallable> apProtocol =
connect_and_login(context);
@@ -1299,6 +1305,10 @@ bool test_multiple_uploads()
TEST_THAT(check_num_files(UPLOAD_NUM - 3, 3, 0, 1));
}
+ apProtocol->QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol = connect_and_login(context);
+
// Delete one of them (will implicitly delete an old version)
{
std::auto_ptr<BackupProtocolSuccess> del(apProtocol->QueryDeleteFile(
@@ -1308,6 +1318,10 @@ bool test_multiple_uploads()
TEST_THAT(check_num_files(UPLOAD_NUM - 4, 3, 2, 1));
}
+ apProtocol->QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol = connect_and_login(context);
+
// Check that the block index can be obtained by name even though it's been deleted
{
// Fetch the raw object
@@ -1380,8 +1394,9 @@ bool test_multiple_uploads()
// Also check that bbstoreaccounts doesn't change anything,
// using an external process instead of the internal one.
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf check 01234567 fix") == 0);
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf check 01234567 fix") == 0,
+ FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
apProtocol = connect_and_login(context);
@@ -1462,6 +1477,14 @@ bool test_server_commands()
new BackupProtocolLocal2(0x01234567, "test",
"backup/01234567/", 0, false));
+ // Try using GetFile on a directory
+ {
+ TEST_CHECK_THROWS(apProtocol->QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BACKUPSTORE_ROOT_DIRECTORY_ID),
+ ConnectionException, Protocol_UnexpectedReply);
+ }
+
+ // BLOCK
// TODO FIXME dedent this block.
{
// Create a directory
@@ -1637,6 +1660,13 @@ bool test_server_commands()
// Try some dodgy renames
{
+ // File doesn't exist at all
+ TEST_CHECK_THROWS(
+ apProtocol->QueryMoveObject(-1,
+ BACKUPSTORE_ROOT_DIRECTORY_ID, subdirid,
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ ConnectionException, Protocol_UnexpectedReply);
BackupStoreFilenameClear newName("moved-files");
TEST_CHECK_THROWS(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolListDirectory::RootDirectory,
@@ -1648,6 +1678,21 @@ bool test_server_commands()
ConnectionException, Protocol_UnexpectedReply);
}
+ // File exists, but not in this directory (we just moved it)
+ TEST_CHECK_THROWS(apProtocol->QueryMoveObject(root_file_id,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ ConnectionException, Protocol_UnexpectedReply);
+
+ // Moving file to same directory that it's already in,
+ // with the same name
+ TEST_CHECK_THROWS(apProtocol->QueryMoveObject(root_file_id,
+ subdirid, subdirid,
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ ConnectionException, Protocol_UnexpectedReply);
+
// Rename within a directory (successfully)
{
BackupStoreFilenameClear newName2("moved-files-x");
@@ -1664,6 +1709,7 @@ bool test_server_commands()
// Check the old and new versions are in the other directory
{
+ BackupStoreFilenameClear notThere("moved-files");
BackupStoreFilenameClear lookFor("moved-files-x");
// Command
@@ -1683,6 +1729,10 @@ bool test_server_commands()
bool foundOld = false;
while((en = i.Next()) != 0)
{
+ // If we find the old name, then the rename
+ // operation didn't work.
+ TEST_THAT(en->GetName() != notThere);
+
if(en->GetName() == lookFor)
{
if(en->GetFlags() == (BackupStoreDirectory::Entry::Flags_File)) foundCurrent = true;
@@ -1846,11 +1896,16 @@ bool test_server_commands()
assert_everything_deleted(protocolReadOnly, dirtodelete);
}
+ // Undelete and check that block counts are restored properly
+ apProtocol->Reopen();
+ TEST_EQUAL(dirtodelete,
+ apProtocol->QueryUndeleteDirectory(dirtodelete)->GetObjectID());
+
// Finish the connections
-#ifndef WIN32
- protocolReadOnly.QueryFinished();
-#endif
apProtocol->QueryFinished();
+
+ TEST_THAT(run_housekeeping_and_check_account());
+ TEST_THAT(check_reference_counts());
}
return teardown_test_backupstore();
@@ -1866,10 +1921,8 @@ int get_object_size(BackupProtocolCallable& protocol, int64_t ObjectID,
BackupStoreDirectory dir(protocol.ReceiveStream());
BackupStoreDirectory::Entry *en = dir.FindEntryByID(ObjectID);
- TEST_THAT(en != 0);
- if (!en) return -1;
-
- TEST_EQUAL(ObjectID, en->GetObjectID());
+ TEST_THAT_OR(en != 0, return -1);
+ TEST_EQUAL_OR(ObjectID, en->GetObjectID(), return -1);
return en->GetSizeInBlocks();
}
@@ -2025,10 +2078,19 @@ bool test_directory_parent_entry_tracks_directory_size()
en = root.FindEntryByID(subdirid);
TEST_THAT_OR(en != 0, return false);
en->SetSizeInBlocks(1234);
+
+ // Sleep to ensure that the directory file timestamp changes, so that
+ // the read-only connection will discard its cached copy.
+ safe_sleep(1);
TEST_THAT(write_dir(root));
TEST_EQUAL(1234, get_object_size(protocolReadOnly, subdirid,
BACKUPSTORE_ROOT_DIRECTORY_ID));
+
+ // Sleep to ensure that the directory file timestamp changes, so that
+ // the read-only connection will discard its cached copy.
+ safe_sleep(1);
+
TEST_EQUAL(1, check_account_for_errors());
TEST_EQUAL(old_size, get_object_size(protocolReadOnly, subdirid,
BACKUPSTORE_ROOT_DIRECTORY_ID));
@@ -2041,7 +2103,7 @@ bool test_directory_parent_entry_tracks_directory_size()
bool test_cannot_open_multiple_writable_connections()
{
SETUP();
- TEST_THAT_THROWONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), return false);
// First try a local protocol. This works even on Windows.
BackupProtocolLocal2 protocolWritable(0x01234567, "test",
@@ -2051,14 +2113,20 @@ bool test_cannot_open_multiple_writable_connections()
protocolWritable.QuerySetClientStoreMarker(0x8732523ab23aLL);
// First try a local protocol. This works even on Windows.
- BackupProtocolLocal2 protocolWritable2(0x01234567, "test",
- "backup/01234567/", 0, false); // Not read-only
- assert_writable_connection_fails(protocolWritable2);
+ {
+ BackupStoreContext bsContext(0x01234567, (HousekeepingInterface *)NULL, "test");
+ bsContext.SetClientHasAccount("backup/01234567/", 0);
+ BackupProtocolLocal protocolWritable2(bsContext);
+ TEST_THAT(assert_writable_connection_fails(protocolWritable2));
+ }
- BackupProtocolLocal2 protocolReadOnly(0x01234567, "test",
- "backup/01234567/", 0, true); // Read-only
- TEST_EQUAL(0x8732523ab23aLL,
- assert_readonly_connection_succeeds(protocolReadOnly));
+ {
+ BackupStoreContext bsContext(0x01234567, (HousekeepingInterface *)NULL, "test");
+ bsContext.SetClientHasAccount("backup/01234567/", 0);
+ BackupProtocolLocal protocolReadOnly(bsContext);
+ TEST_EQUAL(0x8732523ab23aLL,
+ assert_readonly_connection_succeeds(protocolReadOnly));
+ }
// Try network connections too.
@@ -2323,7 +2391,7 @@ bool test_login_without_account()
SETUP();
delete_account();
- TEST_THAT_THROWONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), FAIL);
// BLOCK
{
@@ -2355,9 +2423,9 @@ bool test_bbstoreaccounts_create()
// Delete the account, and create it again using bbstoreaccounts
delete_account();
- TEST_THAT_THROWONFAIL(::system(BBSTOREACCOUNTS
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
" -c testfiles/bbstored.conf -Wwarning create 01234567 0 "
- "10000B 20000B") == 0);
+ "10000B 20000B") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
return teardown_test_backupstore();
@@ -2366,12 +2434,12 @@ bool test_bbstoreaccounts_create()
bool test_bbstoreaccounts_delete()
{
SETUP();
- TEST_THAT_THROWONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf -Wwarning delete 01234567 yes") == 0);
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf -Wwarning delete 01234567 yes") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Recreate the account so that teardown_test_backupstore() doesn't freak out
- TEST_THAT_THROWONFAIL(create_account(10000, 20000));
+ TEST_THAT(create_account(10000, 20000));
return teardown_test_backupstore();
}
@@ -2380,7 +2448,7 @@ bool test_bbstoreaccounts_delete()
bool test_login_with_disabled_account()
{
SETUP();
- TEST_THAT_THROWONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), FAIL);
TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
@@ -2400,8 +2468,8 @@ bool test_login_with_disabled_account()
apReferences.reset();
// Test that login fails on a disabled account
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf enabled 01234567 no") == 0);
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf enabled 01234567 no") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// BLOCK
@@ -2427,14 +2495,10 @@ bool test_login_with_disabled_account()
bool test_login_with_no_refcount_db()
{
SETUP();
- TEST_THAT_THROWONFAIL(StartServer());
-
- // It's easier to test this if we disable housekeeping, so run
- // without a server.
- // TEST_THAT_THROWONFAIL(StartServer());
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf enabled 01234567 yes") == 0);
+ // The account is already enabled, but doing it again shouldn't hurt
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf enabled 01234567 yes") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Delete the refcount database and try to log in again. Check that
@@ -2450,40 +2514,35 @@ bool test_login_with_no_refcount_db()
BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
BackupStoreAccountDatabase::Entry account =
apAccounts->GetEntry(0x1234567);
- run_housekeeping(account);
+ TEST_EQUAL_LINE(1, run_housekeeping(account),
+ "Housekeeping should report 1 error if the refcount db is missing");
+ TEST_THAT(FileExists("testfiles/0_0/backup/01234567/refcount.rdb.rfw"));
+
+ // And that we can log in afterwards
+ BackupProtocolLocal2(0x01234567, "test", "backup/01234567/", 0,
+ false).QueryFinished(); // Not read-only
// Check that housekeeping fixed the ref counts
- std::auto_ptr<BackupStoreRefCountDatabase> apReferences =
- BackupStoreRefCountDatabase::Load(account, true);
- TEST_EQUAL(BACKUPSTORE_ROOT_DIRECTORY_ID,
- apReferences->GetLastObjectIDUsed());
- TEST_EQUAL(1, apReferences->GetRefCount(BACKUPSTORE_ROOT_DIRECTORY_ID))
- apReferences.reset();
+ TEST_THAT(check_reference_counts());
+
+ // Start a server and try again, remotely. This is difficult to debug
+ // because housekeeping may fix the refcount database while we're
+ // stepping through.
+ TEST_THAT_THROWONFAIL(StartServer());
+ TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.rdb.rfw"));
+ TEST_CHECK_THROWS(connect_and_login(context),
+ ConnectionException, Protocol_UnexpectedReply);
TEST_THAT(ServerIsAlive(bbstored_pid));
- // test that all object reference counts have the
- // expected values
- apReferences = BackupStoreRefCountDatabase::Load(account, true);
- set_refcount(BACKUPSTORE_ROOT_DIRECTORY_ID, 1);
- TEST_EQUAL(ExpectedRefCounts.size() - 1,
- apReferences->GetLastObjectIDUsed());
- for (unsigned int i = BACKUPSTORE_ROOT_DIRECTORY_ID;
- i < ExpectedRefCounts.size(); i++)
- {
- TEST_EQUAL_LINE(ExpectedRefCounts[i],
- apReferences->GetRefCount(i),
- "object " << BOX_FORMAT_OBJECTID(i));
- }
+ // Run housekeeping, check that it fixes the refcount db
+ TEST_EQUAL_LINE(1, run_housekeeping(account),
+ "Housekeeping should report 1 error if the refcount db is missing");
+ TEST_THAT(FileExists("testfiles/0_0/backup/01234567/refcount.rdb.rfw"));
+ TEST_THAT(check_reference_counts());
- // Delete the refcount database again, and let
- // housekeeping recreate it and fix the ref counts.
- // This could also happen after upgrade, if a housekeeping
- // runs before the user logs in.
- apReferences.reset();
- TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.rdb.rfw"));
- run_housekeeping(account);
- apReferences = BackupStoreRefCountDatabase::Load(account, true);
+ // And that we can log in afterwards
+ connect_and_login(context)->QueryFinished();
return teardown_test_backupstore();
}
@@ -2509,7 +2568,7 @@ bool test_housekeeping_deletes_files()
protocolLocal.QueryFinished();
// First, things as they are now.
- TEST_THAT_ABORTONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), FAIL);
recursive_count_objects_results before = {0,0,0};
recursive_count_objects(BACKUPSTORE_ROOT_DIRECTORY_ID, before);
@@ -2548,28 +2607,28 @@ bool test_housekeeping_deletes_files()
bool test_account_limits_respected()
{
SETUP();
- TEST_THAT_THROWONFAIL(StartServer());
+ TEST_THAT_OR(StartServer(), FAIL);
// Set a really small hard limit
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
" -c testfiles/bbstored.conf setlimit 01234567 "
- "2B 2B") == 0);
+ "2B 2B") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Try to upload a file and create a directory, and check an error is generated
{
- // Open a connection to the server
- BackupProtocolClient protocol(open_conn("localhost", context));
-
- int64_t modtime = 0;
-
write_test_file(3);
+
+ // Open a connection to the server
+ std::auto_ptr<BackupProtocolCallable> apProtocol(
+ connect_and_login(context));
BackupStoreFilenameClear fnx("exceed-limit");
- std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/test3", BackupProtocolListDirectory::RootDirectory, fnx, &modtime));
+ int64_t modtime = 0;
+ std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/test3", BACKUPSTORE_ROOT_DIRECTORY_ID, fnx, &modtime));
TEST_THAT(modtime != 0);
- TEST_CHECK_THROWS(protocol.QueryStoreFile(
- BackupProtocolListDirectory::RootDirectory,
+ TEST_CHECK_THROWS(apProtocol->QueryStoreFile(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
modtime,
modtime, /* use it for attr hash too */
0, /* diff from ID */
@@ -2581,13 +2640,13 @@ bool test_account_limits_respected()
// kills the connection. TODO FIXME return an error instead.
std::auto_ptr<IOStream> attr(new MemBlockStream(&modtime, sizeof(modtime)));
BackupStoreFilenameClear fnxd("exceed-limit-dir");
- TEST_CHECK_THROWS(protocol.QueryCreateDirectory(
+ TEST_CHECK_THROWS(apProtocol->QueryCreateDirectory(
BACKUPSTORE_ROOT_DIRECTORY_ID,
FAKE_ATTR_MODIFICATION_TIME, fnxd, attr),
ConnectionException, Protocol_UnexpectedReply);
- // Finish the connection. TODO FIXME reinstate this.
- protocol.QueryFinished();
+ // Finish the connection.
+ apProtocol->QueryFinished();
}
return teardown_test_backupstore();
@@ -2598,9 +2657,9 @@ int multi_server()
printf("Starting server for connection from remote machines...\n");
// Create an account for the test client
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
" -c testfiles/bbstored.conf create 01234567 0 "
- "30000B 40000B") == 0);
+ "30000B 40000B") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// First, try logging in without an account having been created... just make sure login fails.
@@ -2883,14 +2942,14 @@ bool test_read_old_backupstoreinfo_files()
"with extra_data", info_v1, *apInfo, "test", true, extra_data);
// Check that the new bbstoreaccounts command sets the flag properly
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf enabled 01234567 no") == 0);
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf enabled 01234567 no") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0, true);
TEST_EQUAL_LINE(false, apInfo->IsAccountEnabled(),
"'bbstoreaccounts disabled no' should have reset AccountEnabled flag");
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf enabled 01234567 yes") == 0);
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf enabled 01234567 yes") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0, true);
TEST_EQUAL_LINE(true, apInfo->IsAccountEnabled(),
@@ -2931,9 +2990,7 @@ bool test_read_old_backupstoreinfo_files()
// Delete the account to stop teardown_test_backupstore checking it for errors.
apInfo.reset();
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf delete 01234567 yes") == 0);
- TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+ TEST_THAT(delete_account());
return teardown_test_backupstore();
}
@@ -2985,6 +3042,7 @@ int test(int argc, const char *argv[])
TEST_THAT(test_bbstoreaccounts_delete());
TEST_THAT(test_backupstore_directory());
TEST_THAT(test_directory_parent_entry_tracks_directory_size());
+ TEST_THAT(test_cannot_open_multiple_writable_connections());
TEST_THAT(test_encoding());
TEST_THAT(test_symlinks());
TEST_THAT(test_store_info());
@@ -3003,6 +3061,6 @@ int test(int argc, const char *argv[])
TEST_THAT(test_multiple_uploads());
TEST_THAT(test_housekeeping_deletes_files());
- return 0;
+ return (failures == 0);
}