summaryrefslogtreecommitdiff
path: root/test/backupstore/testbackupstore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/backupstore/testbackupstore.cpp')
-rw-r--r--test/backupstore/testbackupstore.cpp2470
1 files changed, 1598 insertions, 872 deletions
diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index 661973e0..6441d66c 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.cpp
@@ -15,17 +15,22 @@
#include "Archive.h"
#include "BackupClientCryptoKeys.h"
#include "BackupClientFileAttributes.h"
+#include "BackupProtocol.h"
#include "BackupStoreAccountDatabase.h"
#include "BackupStoreAccounts.h"
+#include "BackupStoreConfigVerify.h"
#include "BackupStoreConstants.h"
#include "BackupStoreDirectory.h"
#include "BackupStoreException.h"
-#include "BackupStoreInfo.h"
+#include "BackupStoreFile.h"
#include "BackupStoreFilenameClear.h"
+#include "BackupStoreFileEncodeStream.h"
+#include "BackupStoreInfo.h"
+#include "BackupStoreObjectMagic.h"
#include "BackupStoreRefCountDatabase.h"
-#include "BackupStoreFile.h"
#include "BoxPortsAndFiles.h"
#include "CollectInBufferStream.h"
+#include "Configuration.h"
#include "FileStream.h"
#include "HousekeepStoreAccount.h"
#include "MemBlockStream.h"
@@ -37,15 +42,27 @@
#include "ServerControl.h"
#include "Socket.h"
#include "SocketStreamTLS.h"
+#include "StoreStructure.h"
+#include "StoreTestUtils.h"
#include "TLSContext.h"
#include "Test.h"
-#include "autogen_BackupProtocol.h"
+#include "ZeroStream.h"
#include "MemLeakFindOn.h"
-
#define ENCFILE_SIZE 2765
+// Make some test attributes
+#define ATTR1_SIZE 245
+#define ATTR2_SIZE 23
+#define ATTR3_SIZE 122
+
+#define SHORT_TIMEOUT 5000
+
+int attr1[ATTR1_SIZE];
+int attr2[ATTR2_SIZE];
+int attr3[ATTR3_SIZE];
+
typedef struct
{
BackupStoreFilenameClear fn;
@@ -94,7 +111,7 @@ typedef struct
#define TEST_FILE_FOR_PATCHING_SIZE ((128*1024)+2564)
#define UPLOAD_PATCH_EN 2
-uploadtest uploads[] =
+uploadtest uploads[] =
{
{"0", BackupStoreFilenameClear(), 324, 455, 0, 0, false, false},
{"1", BackupStoreFilenameClear(), 3232432, 2674, 0, 0, true, false}, // old ver
@@ -121,11 +138,42 @@ static const char *uploads_filenames[] = {"49587fds", "cvhjhj324", "sdfcscs324",
// file which will be moved (as well as it's old version)
#define UPLOAD_FILE_TO_MOVE 8
+#define UNLINK_IF_EXISTS(filename) \
+ if (FileExists(filename)) { TEST_THAT(unlink(filename) == 0); }
+
+//! Simplifies calling setUp() with the current function name in each test.
+#define SETUP_TEST_BACKUPSTORE() \
+ SETUP(); \
+ if (ServerIsAlive(bbstored_pid)) \
+ TEST_THAT_OR(StopServer(), FAIL); \
+ ExpectedRefCounts.resize(BACKUPSTORE_ROOT_DIRECTORY_ID + 1); \
+ set_refcount(BACKUPSTORE_ROOT_DIRECTORY_ID, 1); \
+ TEST_THAT_OR(create_account(10000, 20000), FAIL);
+
+//! Checks account for errors and shuts down daemons at end of every test.
+bool teardown_test_backupstore()
+{
+ bool status = true;
+
+ if (FileExists("testfiles/0_0/backup/01234567/info.rf"))
+ {
+ TEST_THAT_OR(check_reference_counts(), status = false);
+ TEST_THAT_OR(check_account(), status = false);
+ }
+
+ return status;
+}
+
+#define TEARDOWN_TEST_BACKUPSTORE() \
+ if (ServerIsAlive(bbstored_pid)) \
+ StopServer(); \
+ TEST_THAT(teardown_test_backupstore()); \
+ TEARDOWN();
// Nice random data for testing written files
class R250 {
public:
- // Set up internal state table with 32-bit random numbers.
+ // Set up internal state table with 32-bit random numbers.
// The bizarre bit-twiddling is because rand() returns 16 bits of which
// the bottom bit is always zero! Hence, I use only some of the bits.
// You might want to do something better than this....
@@ -142,7 +190,7 @@ public:
// stir up the numbers to ensure they're random
- for (int j = 0; j != stateLen * 4; ++j)
+ for (int j = 0; j != stateLen * 4; ++j)
(void) next();
}
@@ -174,7 +222,7 @@ int SkipEntries(int e, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet)
do
{
skip = false;
-
+
if(FlagsMustBeSet != BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING)
{
if((ens[e].flags & FlagsMustBeSet) != FlagsMustBeSet)
@@ -186,20 +234,20 @@ int SkipEntries(int e, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet)
{
skip = true;
}
-
+
if(skip)
{
++e;
}
} while(skip && e < DIR_NUM);
-
+
return e;
}
void CheckEntries(BackupStoreDirectory &rDir, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet)
{
int e = 0;
-
+
BackupStoreDirectory::Iterator i(rDir);
BackupStoreDirectory::Entry *en = 0;
while((en = i.Next()) != 0)
@@ -213,16 +261,18 @@ void CheckEntries(BackupStoreDirectory &rDir, int16_t FlagsMustBeSet, int16_t Fl
TEST_THAT(en->GetName() == ens[e].fn && en->GetModificationTime() == ens[e].mod && en->GetObjectID() == ens[e].id && en->GetFlags() == ens[e].flags && en->GetSizeInBlocks() == ens[e].size);
// next
- ++e;
+ ++e;
}
-
+
// Got them all?
TEST_THAT(en == 0);
TEST_THAT(DIR_NUM == SkipEntries(e, FlagsMustBeSet, FlagsNotToBeSet));
}
-int test1(int argc, const char *argv[])
+bool test_filename_encoding()
{
+ SETUP_TEST_BACKUPSTORE();
+
// test some basics -- encoding and decoding filenames
{
// Make some filenames in various ways
@@ -232,11 +282,11 @@ int test1(int argc, const char *argv[])
BackupStoreFilenameClear fn3(fn1);
TEST_THAT(fn1 == fn2);
TEST_THAT(fn1 == fn3);
-
+
// Check that it's been encrypted
std::string name(fn2.GetEncodedFilename());
TEST_THAT(name.find("name") == name.npos);
-
+
// Bung it in a stream, get it out in a Clear filename
{
CollectInBufferStream stream;
@@ -247,6 +297,7 @@ int test1(int argc, const char *argv[])
TEST_THAT(fn4.GetClearFilename() == "filenameXYZ");
TEST_THAT(fn4 == fn1);
}
+
// Bung it in a stream, get it out in a server non-Clear filename (two of them into the same var)
{
BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
@@ -260,6 +311,7 @@ int test1(int argc, const char *argv[])
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5 == fno);
}
+
// Same again with clear strings
{
BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
@@ -273,6 +325,7 @@ int test1(int argc, const char *argv[])
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5.GetClearFilename() == "pinglet dksfnsf jksjdf ");
}
+
// Test a very big filename
{
const char *fnr = "01234567890123456789012345678901234567890123456789"
@@ -292,19 +345,23 @@ int test1(int argc, const char *argv[])
TEST_THAT(fn9.GetClearFilename() == fnr);
TEST_THAT(fn9 == fnLong);
}
+
// Test a filename which went wrong once
{
BackupStoreFilenameClear dodgy("content-negotiation.html");
}
}
- return 0;
+
+ TEARDOWN_TEST_BACKUPSTORE();
}
-int test2(int argc, const char *argv[])
+bool test_backupstore_directory()
{
+ SETUP_TEST_BACKUPSTORE();
+
{
// Now play with directories
-
+
// Fill in...
BackupStoreDirectory dir1(12, 98);
for(int e = 0; e < DIR_NUM; ++e)
@@ -313,27 +370,25 @@ int test2(int argc, const char *argv[])
}
// Got the right number
TEST_THAT(dir1.GetNumberOfEntries() == DIR_NUM);
-
+
// Stick it into a stream and get it out again
{
CollectInBufferStream stream;
dir1.WriteToStream(stream);
stream.SetForReading();
- BackupStoreDirectory dir2;
- dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir2(stream);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_NUM);
TEST_THAT(dir2.GetObjectID() == 12);
TEST_THAT(dir2.GetContainerID() == 98);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
}
-
+
// Then do selective writes and reads
{
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_File);
stream.SetForReading();
- BackupStoreDirectory dir2;
- dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir2(stream);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_FILES);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_File, BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
}
@@ -341,8 +396,7 @@ int test2(int argc, const char *argv[])
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, BackupStoreDirectory::Entry::Flags_File);
stream.SetForReading();
- BackupStoreDirectory dir2;
- dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir2(stream);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_DIRS);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_Dir, BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
}
@@ -350,12 +404,11 @@ int test2(int argc, const char *argv[])
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_File, BackupStoreDirectory::Entry::Flags_OldVersion);
stream.SetForReading();
- BackupStoreDirectory dir2;
- dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir2(stream);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_FILES - DIR_OLD);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_File, BackupStoreDirectory::Entry::Flags_OldVersion);
}
-
+
// Finally test deleting items
{
dir1.DeleteEntry(12312312321LL);
@@ -364,11 +417,10 @@ int test2(int argc, const char *argv[])
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_File);
stream.SetForReading();
- BackupStoreDirectory dir2;
- dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir2(stream);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_FILES - 1);
}
-
+
// Check attributes
{
int attrI[4] = {1, 2, 3, 4};
@@ -380,73 +432,70 @@ int test2(int argc, const char *argv[])
CollectInBufferStream stream;
d1.WriteToStream(stream);
stream.SetForReading();
- BackupStoreDirectory d2;
- d2.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory d2(stream);
TEST_THAT(d2.GetAttributes() == attr);
TEST_THAT(d2.GetAttributesModTime() == 56234987324232LL);
}
}
- return 0;
+
+ TEARDOWN_TEST_BACKUPSTORE();
}
void write_test_file(int t)
{
std::string filename("testfiles/test");
filename += uploads[t].fnextra;
- printf("%s\n", filename.c_str());
-
+ BOX_TRACE("Writing " << filename);
+
FileStream write(filename.c_str(), O_WRONLY | O_CREAT);
-
+
R250 r(uploads[t].seed);
-
+
unsigned char *data = (unsigned char*)malloc(uploads[t].size);
for(int l = 0; l < uploads[t].size; ++l)
{
data[l] = r.next() & 0xff;
}
write.Write(data, uploads[t].size);
-
+
free(data);
}
void test_test_file(int t, IOStream &rStream)
{
// Decode to a file
- BackupStoreFile::DecodeFile(rStream, "testfiles/test_download", IOStream::TimeOutInfinite);
-
+ BackupStoreFile::DecodeFile(rStream, "testfiles/test_download", SHORT_TIMEOUT);
+
// Compare...
FileStream in("testfiles/test_download");
TEST_THAT(in.BytesLeftToRead() == uploads[t].size);
-
+
R250 r(uploads[t].seed);
-
+
unsigned char *data = (unsigned char*)malloc(uploads[t].size);
TEST_THAT(in.ReadFullBuffer(data, uploads[t].size, 0 /* not interested in bytes read if this fails */));
-
+
for(int l = 0; l < uploads[t].size; ++l)
{
TEST_THAT(data[l] == (r.next() & 0xff));
}
-
+
free(data);
in.Close();
TEST_THAT(unlink("testfiles/test_download") == 0);
}
-void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
+void assert_everything_deleted(BackupProtocolCallable &protocol, int64_t DirID)
{
- printf("Test for del: %llx\n", (unsigned long long)DirID);
-
+ BOX_TRACE("Test for del: " << BOX_FORMAT_OBJECTID(DirID));
+
// Command
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
DirID,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
-
+ BackupStoreDirectory dir(protocol.ReceiveStream(), SHORT_TIMEOUT);
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
int files = 0;
@@ -457,34 +506,24 @@ void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
{
dirs++;
// Recurse
- test_everything_deleted(protocol, en->GetObjectID());
+ assert_everything_deleted(protocol, en->GetObjectID());
}
else
{
files++;
}
+
// Check it's deleted
- TEST_THAT(en->GetFlags() & BackupProtocolListDirectory::Flags_Deleted);
+ TEST_THAT(en->IsDeleted());
}
-
+
// Check there were the right number of files and directories
TEST_THAT(files == 3);
TEST_THAT(dirs == 0 || dirs == 2);
}
-std::vector<uint32_t> ExpectedRefCounts;
-
-void set_refcount(int64_t ObjectID, uint32_t RefCount = 1)
-{
- if ((int64_t)ExpectedRefCounts.size() <= ObjectID);
- {
- ExpectedRefCounts.resize(ObjectID + 1, 0);
- }
- ExpectedRefCounts[ObjectID] = RefCount;
-}
-
void create_file_in_dir(std::string name, std::string source, int64_t parentId,
- BackupProtocolClient &protocol, BackupStoreRefCountDatabase& rRefCount)
+ BackupProtocolCallable &protocol, BackupStoreRefCountDatabase* pRefCount)
{
BackupStoreFilenameClear name_encoded("file_One");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(
@@ -496,15 +535,22 @@ void create_file_in_dir(std::string name, std::string source, int64_t parentId,
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
name_encoded,
- *upload));
+ upload));
int64_t objectId = stored->GetObjectID();
- TEST_EQUAL(objectId, rRefCount.GetLastObjectIDUsed());
- TEST_EQUAL(1, rRefCount.GetRefCount(objectId))
+ if (pRefCount)
+ {
+ TEST_EQUAL(objectId, pRefCount->GetLastObjectIDUsed());
+ TEST_EQUAL(1, pRefCount->GetRefCount(objectId))
+ }
set_refcount(objectId, 1);
}
-int64_t create_test_data_subdirs(BackupProtocolClient &protocol, int64_t indir,
- const char *name, int depth, BackupStoreRefCountDatabase& rRefCount)
+const box_time_t FAKE_MODIFICATION_TIME = 0xfeedfacedeadbeefLL;
+const box_time_t FAKE_ATTR_MODIFICATION_TIME = 0xdeadbeefcafebabeLL;
+
+int64_t create_test_data_subdirs(BackupProtocolCallable &protocol,
+ int64_t indir, const char *name, int depth,
+ BackupStoreRefCountDatabase* pRefCount)
{
// Create a directory
int64_t subdirid = 0;
@@ -512,72 +558,80 @@ int64_t create_test_data_subdirs(BackupProtocolClient &protocol, int64_t indir,
{
// Create with dummy attributes
int attrS = 0;
- MemBlockStream attr(&attrS, sizeof(attrS));
+ std::auto_ptr<IOStream> attr(new MemBlockStream(&attrS, sizeof(attrS)));
std::auto_ptr<BackupProtocolSuccess> dirCreate(protocol.QueryCreateDirectory(
- indir,
- 9837429842987984LL, dirname, attr));
- subdirid = dirCreate->GetObjectID();
+ indir, FAKE_ATTR_MODIFICATION_TIME, dirname, attr));
+ subdirid = dirCreate->GetObjectID();
+ }
+
+ BOX_TRACE("Creating subdirs, depth = " << depth << ", dirid = " <<
+ BOX_FORMAT_OBJECTID(subdirid));
+
+ if (pRefCount)
+ {
+ TEST_EQUAL(subdirid, pRefCount->GetLastObjectIDUsed());
+ TEST_EQUAL(1, pRefCount->GetRefCount(subdirid))
}
-
- printf("Create subdirs, depth = %d, dirid = %llx\n", depth,
- (unsigned long long)subdirid);
- TEST_EQUAL(subdirid, rRefCount.GetLastObjectIDUsed());
- TEST_EQUAL(1, rRefCount.GetRefCount(subdirid))
set_refcount(subdirid, 1);
-
+
// Put more directories in it, if we haven't gone down too far
if(depth > 0)
{
create_test_data_subdirs(protocol, subdirid, "dir_One",
- depth - 1, rRefCount);
+ depth - 1, pRefCount);
create_test_data_subdirs(protocol, subdirid, "dir_Two",
- depth - 1, rRefCount);
+ depth - 1, pRefCount);
}
-
+
// Stick some files in it
- create_file_in_dir("file_One", "testfiles/file1", subdirid, protocol,
- rRefCount);
- create_file_in_dir("file_Two", "testfiles/file1", subdirid, protocol,
- rRefCount);
- create_file_in_dir("file_Three", "testfiles/file1", subdirid, protocol,
- rRefCount);
+ create_file_in_dir("file_One", "testfiles/test1", subdirid, protocol,
+ pRefCount);
+ create_file_in_dir("file_Two", "testfiles/test1", subdirid, protocol,
+ pRefCount);
+ create_file_in_dir("file_Three", "testfiles/test1", subdirid, protocol,
+ pRefCount);
return subdirid;
}
-
-void check_dir_after_uploads(BackupProtocolClient &protocol, const StreamableMemBlock &Attributes)
+void check_dir_after_uploads(BackupProtocolCallable &protocol,
+ const StreamableMemBlock &Attributes)
{
// Command
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
- TEST_THAT(dirreply->GetObjectID() == BackupProtocolListDirectory::RootDirectory);
+ TEST_THAT(dirreply->GetObjectID() == BACKUPSTORE_ROOT_DIRECTORY_ID);
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
- TEST_THAT(dir.GetNumberOfEntries() == UPLOAD_NUM + 1 /* for the first test file */);
+ BackupStoreDirectory dir(protocol.ReceiveStream(), SHORT_TIMEOUT);
+ TEST_EQUAL(UPLOAD_NUM, dir.GetNumberOfEntries());
TEST_THAT(!dir.HasAttributes());
// Check them!
BackupStoreDirectory::Iterator i(dir);
- // Discard first
- BackupStoreDirectory::Entry *en = i.Next();
- TEST_THAT(en != 0);
+ BackupStoreDirectory::Entry *en;
for(int t = 0; t < UPLOAD_NUM; ++t)
{
en = i.Next();
TEST_THAT(en != 0);
- TEST_THAT(en->GetName() == uploads[t].name);
- TEST_THAT(en->GetObjectID() == uploads[t].allocated_objid);
- TEST_THAT(en->GetModificationTime() == uploads[t].mod_time);
+ if (en == 0) continue;
+ TEST_LINE(uploads[t].name == en->GetName(),
+ "uploaded file " << t << " name");
+ BackupStoreFilenameClear clear(en->GetName());
+ TEST_EQUAL_LINE(uploads[t].name.GetClearFilename(),
+ clear.GetClearFilename(),
+ "uploaded file " << t << " name");
+ TEST_EQUAL_LINE(uploads[t].allocated_objid, en->GetObjectID(),
+ "uploaded file " << t << " ID");
+ TEST_EQUAL_LINE(uploads[t].mod_time, en->GetModificationTime(),
+ "uploaded file " << t << " modtime");
int correct_flags = BackupProtocolListDirectory::Flags_File;
if(uploads[t].should_be_old_version) correct_flags |= BackupProtocolListDirectory::Flags_OldVersion;
if(uploads[t].delete_file) correct_flags |= BackupProtocolListDirectory::Flags_Deleted;
- TEST_THAT(en->GetFlags() == correct_flags);
+ TEST_EQUAL_LINE(correct_flags, en->GetFlags(),
+ "uploaded file " << t << " flags");
if(t == UPLOAD_ATTRS_EN)
{
TEST_THAT(en->HasAttributes());
@@ -589,12 +643,11 @@ void check_dir_after_uploads(BackupProtocolClient &protocol, const StreamableMem
// No attributes on this one
TEST_THAT(!en->HasAttributes());
}
- }
+ }
en = i.Next();
TEST_THAT(en == 0);
}
-
typedef struct
{
int objectsNotDel;
@@ -602,7 +655,8 @@ typedef struct
int old;
} recursive_count_objects_results;
-void recursive_count_objects_r(BackupProtocolClient &protocol, int64_t id, recursive_count_objects_results &results)
+void recursive_count_objects_r(BackupProtocolCallable &protocol, int64_t id,
+ recursive_count_objects_results &results)
{
// Command
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
@@ -610,21 +664,19 @@ void recursive_count_objects_r(BackupProtocolClient &protocol, int64_t id, recur
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir(protocol.ReceiveStream(), SHORT_TIMEOUT);
// Check them!
BackupStoreDirectory::Iterator i(dir);
// Discard first
BackupStoreDirectory::Entry *en = 0;
-
+
while((en = i.Next()) != 0)
{
if((en->GetFlags() & (BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)) == 0) results.objectsNotDel++;
if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) results.deleted++;
if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) results.old++;
-
+
if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir)
{
recursive_count_objects_r(protocol, en->GetObjectID(), results);
@@ -632,27 +684,14 @@ void recursive_count_objects_r(BackupProtocolClient &protocol, int64_t id, recur
}
}
-void recursive_count_objects(const char *hostname, int64_t id, recursive_count_objects_results &results)
-{
- // Context
- TLSContext context;
- context.Initialise(false /* client */,
- "testfiles/clientCerts.pem",
- "testfiles/clientPrivKey.pem",
- "testfiles/clientTrustedCAs.pem");
+TLSContext context;
+void recursive_count_objects(int64_t id, recursive_count_objects_results &results)
+{
// Get a connection
- SocketStreamTLS connReadOnly;
- connReadOnly.Open(context, Socket::TypeINET, hostname,
- BOX_PORT_BBSTORED_TEST);
- BackupProtocolClient protocolReadOnly(connReadOnly);
+ BackupProtocolLocal2 protocolReadOnly(0x01234567, "test",
+ "backup/01234567/", 0, false);
- {
- std::auto_ptr<BackupProtocolVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
- TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
- std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolLogin::Flags_ReadOnly));
- }
-
// Count objects
recursive_count_objects_r(protocolReadOnly, id, results);
@@ -673,8 +712,8 @@ bool check_block_index(const char *encoded_file, IOStream &rBlockIndex)
{
char buffer1[2048];
char buffer2[2048];
- int s = enc.Read(buffer1, sizeof(buffer1));
- if(rBlockIndex.Read(buffer2, s) != s)
+ int s = enc.Read(buffer1, sizeof(buffer1), SHORT_TIMEOUT);
+ if(rBlockIndex.Read(buffer2, s, SHORT_TIMEOUT) != s)
{
same = false;
break;
@@ -685,19 +724,19 @@ bool check_block_index(const char *encoded_file, IOStream &rBlockIndex)
break;
}
}
-
+
if(rBlockIndex.StreamDataLeft())
{
same = false;
-
+
// Absorb all this excess data so procotol is in the first state
char buffer[2048];
while(rBlockIndex.StreamDataLeft())
{
- rBlockIndex.Read(buffer, sizeof(buffer));
+ rBlockIndex.Read(buffer, sizeof(buffer), SHORT_TIMEOUT);
}
}
-
+
return same;
}
@@ -726,18 +765,77 @@ bool check_files_same(const char *f1, const char *f2)
break;
}
}
-
+
if(f2s.StreamDataLeft())
{
same = false;
}
-
+
return same;
}
+std::auto_ptr<RaidFileRead> get_raid_file(int64_t ObjectID)
+{
+ std::string filename;
+ StoreStructure::MakeObjectFilename(ObjectID,
+ "backup/01234567/" /* mStoreRoot */, 0 /* mStoreDiscSet */,
+ filename, false /* EnsureDirectoryExists */);
+ return RaidFileRead::Open(0, filename);
+}
+
+int64_t create_directory(BackupProtocolCallable& protocol,
+ int64_t parent_dir_id = BACKUPSTORE_ROOT_DIRECTORY_ID);
+int64_t create_file(BackupProtocolCallable& protocol, int64_t subdirid,
+ const std::string& remote_filename = "");
+
+bool run_housekeeping_and_check_account(BackupProtocolLocal2& protocol)
+{
+ protocol.QueryFinished();
+ bool check_account_status;
+ TEST_THAT(check_account_status = run_housekeeping_and_check_account());
+ bool check_refcount_status;
+ TEST_THAT(check_refcount_status = check_reference_counts());
+ protocol.Reopen();
+ return check_account_status & check_refcount_status;
+}
-void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protocolReadOnly)
+bool test_temporary_refcount_db_is_independent()
{
+ SETUP_TEST_BACKUPSTORE();
+
+ std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
+ BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
+ std::auto_ptr<BackupStoreRefCountDatabase> temp(
+ BackupStoreRefCountDatabase::Create(
+ apAccounts->GetEntry(0x1234567)));
+ std::auto_ptr<BackupStoreRefCountDatabase> perm(
+ BackupStoreRefCountDatabase::Load(
+ apAccounts->GetEntry(0x1234567),
+ true // ReadOnly
+ ));
+
+ TEST_CHECK_THROWS(temp->GetRefCount(2),
+ BackupStoreException, UnknownObjectRefCountRequested);
+ TEST_CHECK_THROWS(perm->GetRefCount(2),
+ BackupStoreException, UnknownObjectRefCountRequested);
+ temp->AddReference(2);
+ TEST_EQUAL(1, temp->GetRefCount(2));
+ TEST_CHECK_THROWS(perm->GetRefCount(2),
+ BackupStoreException, UnknownObjectRefCountRequested);
+ temp->Discard();
+
+ // Need to delete perm object so it doesn't keep a filehandle open,
+ // preventing tearDown from rewriting the refcount DB and thus causing
+ // test failure.
+ perm.reset();
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_server_housekeeping()
+{
+ SETUP_TEST_BACKUPSTORE();
+
int encfile[ENCFILE_SIZE];
{
for(int l = 0; l < ENCFILE_SIZE; ++l)
@@ -747,71 +845,64 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Write this to a file
{
- FileStream f("testfiles/file1", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream f("testfiles/file1", O_WRONLY | O_CREAT);
f.Write(encfile, sizeof(encfile));
}
-
}
- // Read the root directory a few times (as it's cached, so make sure it doesn't hurt anything)
- for(int l = 0; l < 3; ++l)
- {
- // Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
- // Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
- TEST_THAT(dir.GetNumberOfEntries() == 0);
- }
+ // We need complete control over housekeeping, so use a local client
+ // instead of a network client + daemon.
- // Read the dir from the readonly connection (make sure it gets in the cache)
- {
- // Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
- // Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
- TEST_THAT(dir.GetNumberOfEntries() == 0);
- }
+ BackupProtocolLocal2 protocol(0x01234567, "test", "backup/01234567/",
+ 0, false);
+
+ int root_dir_blocks = get_raid_file(BACKUPSTORE_ROOT_DIRECTORY_ID)->GetDiscUsageInBlocks();
+ TEST_THAT(check_num_files(0, 0, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, 0, 0, 0, root_dir_blocks,
+ root_dir_blocks));
// Store a file -- first make the encoded file
- BackupStoreFilenameClear store1name("testfiles/file1");
+ BackupStoreFilenameClear store1name("file1");
{
- FileStream out("testfiles/file1_upload1", O_WRONLY | O_CREAT | O_EXCL);
- std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/file1", BackupProtocolListDirectory::RootDirectory, store1name));
+ FileStream out("testfiles/file1_upload1", O_WRONLY | O_CREAT);
+ std::auto_ptr<IOStream> encoded(
+ BackupStoreFile::EncodeFile("testfiles/file1",
+ BACKUPSTORE_ROOT_DIRECTORY_ID, store1name));
encoded->CopyStreamTo(out);
}
-// printf("SKIPPING\n");
-// goto skip; {
+ // TODO FIXME move most of the code immediately below into
+ // test_server_commands.
+
+ // TODO FIXME use COMMAND macro for all commands to check the returned
+ // object ID.
+ #define COMMAND(command, objectid) \
+ TEST_EQUAL(objectid, protocol.command->GetObjectID());
+
// Then send it
- int64_t store1objid = 0;
+ int64_t store1objid;
{
- FileStream upload("testfiles/file1_upload1");
+ std::auto_ptr<IOStream> upload(new FileStream("testfiles/file1_upload1"));
std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
store1name,
upload));
store1objid = stored->GetObjectID();
- TEST_THAT(store1objid == 2);
+ TEST_EQUAL_LINE(2, store1objid, "wrong ObjectID for newly "
+ "uploaded file");
}
+
+ // Update expected reference count of this new object
set_refcount(store1objid, 1);
+
// And retrieve it
{
// Retrieve as object
- std::auto_ptr<BackupProtocolSuccess> getfile(protocol.QueryGetObject(store1objid));
- TEST_THAT(getfile->GetObjectID() == store1objid);
+ COMMAND(QueryGetObject(store1objid), store1objid);
+
// BLOCK
{
// Get stream
@@ -821,14 +912,17 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
filestream->CopyStreamTo(f);
f.SetForReading();
// Get and decode
+ UNLINK_IF_EXISTS("testfiles/file1_upload_retrieved");
BackupStoreFile::DecodeFile(f, "testfiles/file1_upload_retrieved", IOStream::TimeOutInfinite);
}
// Retrieve as file
- std::auto_ptr<BackupProtocolSuccess> getobj(protocol.QueryGetFile(BackupProtocolListDirectory::RootDirectory, store1objid));
- TEST_THAT(getobj->GetObjectID() == store1objid);
+ COMMAND(QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID, store1objid), store1objid);
+
// BLOCK
{
+ UNLINK_IF_EXISTS("testfiles/file1_upload_retrieved_str");
+
// Get stream
std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
// Get and decode
@@ -842,13 +936,14 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
in.Read(encfile_i, sizeof(encfile_i));
TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0);
}
+
{
FileStream in("testfiles/file1_upload_retrieved_str");
int encfile_i[ENCFILE_SIZE];
in.Read(encfile_i, sizeof(encfile_i));
TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0);
}
-
+
// Retrieve the block index, by ID
{
std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByID(store1objid));
@@ -857,26 +952,26 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Check against uploaded file
TEST_THAT(check_block_index("testfiles/file1_upload1", *blockIndexStream));
}
+
// and again, by name
{
- std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByName(BackupProtocolListDirectory::RootDirectory, store1name));
+ std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByName(BACKUPSTORE_ROOT_DIRECTORY_ID, store1name));
TEST_THAT(getblockindex->GetObjectID() == store1objid);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
// Check against uploaded file
TEST_THAT(check_block_index("testfiles/file1_upload1", *blockIndexStream));
}
}
+
// Get the directory again, and see if the entry is in it
{
// Command
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir(protocol.ReceiveStream(), SHORT_TIMEOUT);
TEST_THAT(dir.GetNumberOfEntries() == 1);
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = i.Next();
@@ -888,182 +983,303 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
TEST_THAT(en->GetModificationTime() == 0x123456789abcdefLL);
TEST_THAT(en->GetAttributesHash() == 0x7362383249872dfLL);
TEST_THAT(en->GetObjectID() == store1objid);
- TEST_THAT(en->GetSizeInBlocks() < ((ENCFILE_SIZE * 4 * 3) / 2 / 2048)+2);
+ TEST_EQUAL(6, en->GetSizeInBlocks());
TEST_THAT(en->GetFlags() == BackupStoreDirectory::Entry::Flags_File);
}
}
+ int file1_blocks = get_raid_file(store1objid)->GetDiscUsageInBlocks();
+ TEST_THAT(check_num_files(1, 0, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, file1_blocks, 0, 0, root_dir_blocks,
+ file1_blocks + root_dir_blocks));
+
+ // Upload again, as a patch to the original file.
+ int64_t patch1_id = BackupStoreFile::QueryStoreFileDiff(protocol,
+ "testfiles/file1", // LocalFilename
+ BACKUPSTORE_ROOT_DIRECTORY_ID, // DirectoryObjectID
+ store1objid, // DiffFromFileID
+ 0x7362383249872dfLL, // AttributesHash
+ store1name // StoreFilename
+ );
+ TEST_EQUAL_LINE(3, patch1_id, "wrong ObjectID for newly uploaded "
+ "patch file");
+
+ // We need to check the old file's size, because it's been replaced
+ // by a reverse diff, and patch1_id is a complete file, not a diff.
+ int patch1_blocks = get_raid_file(store1objid)->GetDiscUsageInBlocks();
+
+ // It will take extra blocks, even though there are no changes, because
+ // the server code is not smart enough to realise that the file
+ // contents are identical, so it will create an empty patch.
+
+ TEST_THAT(check_num_files(1, 1, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, file1_blocks, patch1_blocks, 0,
+ root_dir_blocks, file1_blocks + patch1_blocks + root_dir_blocks));
+
+ // Change the file and upload again, as a patch to the original file.
+ {
+ FileStream out("testfiles/file1", O_WRONLY | O_APPEND);
+ std::string appendix = "appendix!";
+ out.Write(appendix.c_str(), appendix.size());
+ out.Close();
+ }
+
+ int64_t patch2_id = BackupStoreFile::QueryStoreFileDiff(protocol,
+ "testfiles/file1", // LocalFilename
+ BACKUPSTORE_ROOT_DIRECTORY_ID, // DirectoryObjectID
+ patch1_id, // DiffFromFileID
+ 0x7362383249872dfLL, // AttributesHash
+ store1name // StoreFilename
+ );
+ TEST_EQUAL_LINE(4, patch2_id, "wrong ObjectID for newly uploaded "
+ "patch file");
+
+ // How many blocks used by the new file?
+ // We need to check the old file's size, because it's been replaced
+ // by a reverse diff, and patch1_id is a complete file, not a diff.
+ int patch2_blocks = get_raid_file(patch1_id)->GetDiscUsageInBlocks();
+
+ TEST_THAT(check_num_files(1, 2, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, file1_blocks, patch1_blocks + patch2_blocks, 0,
+ root_dir_blocks, file1_blocks + patch1_blocks + patch2_blocks +
+ root_dir_blocks));
+
+ // Housekeeping should not change anything just yet
+ protocol.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+
+ TEST_THAT(check_num_files(1, 2, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, file1_blocks, patch1_blocks + patch2_blocks, 0,
+ root_dir_blocks, file1_blocks + patch1_blocks + patch2_blocks +
+ root_dir_blocks));
+
+ // Upload not as a patch, but as a completely different file. This
+ // marks the previous file as old (because the filename is the same)
+ // but used to not adjust the number of old/deleted files properly.
+ int64_t replaced_id = BackupStoreFile::QueryStoreFileDiff(protocol,
+ "testfiles/file1", // LocalFilename
+ BACKUPSTORE_ROOT_DIRECTORY_ID, // DirectoryObjectID
+ 0, // DiffFromFileID
+ 0x7362383249872dfLL, // AttributesHash
+ store1name // StoreFilename
+ );
+ TEST_EQUAL_LINE(5, replaced_id, "wrong ObjectID for newly uploaded "
+ "full file");
+
+ // How many blocks used by the new file? This time we need to check
+ // the new file, because it's not a patch.
+ int replaced_blocks = get_raid_file(replaced_id)->GetDiscUsageInBlocks();
+
+ TEST_THAT(check_num_files(1, 3, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, replaced_blocks, // current
+ file1_blocks + patch1_blocks + patch2_blocks, // old
+ 0, // deleted
+ root_dir_blocks, // directories
+ file1_blocks + patch1_blocks + patch2_blocks + replaced_blocks +
+ root_dir_blocks)); // total
+
+ // Housekeeping should not change anything just yet
+ protocol.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+
+ TEST_THAT(check_num_files(1, 3, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, replaced_blocks, // current
+ file1_blocks + patch1_blocks + patch2_blocks, // old
+ 0, // deleted
+ root_dir_blocks, // directories
+ file1_blocks + patch1_blocks + patch2_blocks + replaced_blocks +
+ root_dir_blocks)); // total
+
+ // But if we reduce the limits, then it will
+ protocol.QueryFinished();
+ TEST_THAT(change_account_limits(
+ "14B", // replaced_blocks + file1_blocks + root_dir_blocks
+ "2000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+
+ TEST_THAT(check_num_files(1, 1, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, replaced_blocks, // current
+ file1_blocks, // old
+ 0, // deleted
+ root_dir_blocks, // directories
+ file1_blocks + replaced_blocks + root_dir_blocks)); // total
+
+ // Check that deleting files is accounted for as well
+ protocol.QueryDeleteFile(
+ BACKUPSTORE_ROOT_DIRECTORY_ID, // InDirectory
+ store1name); // Filename
+
+ // The old version file is deleted as well!
+ TEST_THAT(check_num_files(0, 1, 2, 1));
+ TEST_THAT(check_num_blocks(protocol, 0, // current
+ file1_blocks, // old
+ replaced_blocks + file1_blocks, // deleted
+ root_dir_blocks, // directories
+ file1_blocks + replaced_blocks + root_dir_blocks));
+
+ // Reduce limits again, check that removed files are subtracted from
+ // block counts.
+ protocol.QueryFinished();
+ TEST_THAT(change_account_limits("0B", "2000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+
+ TEST_THAT(check_num_files(0, 0, 0, 1));
+ TEST_THAT(check_num_blocks(protocol, 0, 0, 0, root_dir_blocks, root_dir_blocks));
+
+ // Used to not consume the stream
+ std::auto_ptr<IOStream> upload(new ZeroStream(1000));
+ TEST_COMMAND_RETURNS_ERROR(protocol, QueryStoreFile(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ 0,
+ 0, /* use for attr hash too */
+ 99999, /* diff from ID */
+ uploads[0].name,
+ upload),
+ Err_DiffFromFileDoesNotExist);
+
+ // TODO FIXME These tests should not be here, but in
+ // test_server_commands. But make sure you use a network protocol,
+ // not a local one, when you move them.
+
// Try using GetFile on a directory
{
- TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolSuccess> getFile(protocol.QueryGetFile(BackupProtocolListDirectory::RootDirectory, BackupProtocolListDirectory::RootDirectory)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
+ int64_t subdirid = create_directory(protocol);
+ TEST_COMMAND_RETURNS_ERROR(protocol,
+ QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID, subdirid),
+ Err_FileDoesNotVerify);
}
-}
-void init_context(TLSContext& rContext)
-{
- rContext.Initialise(false /* client */,
- "testfiles/clientCerts.pem",
- "testfiles/clientPrivKey.pem",
- "testfiles/clientTrustedCAs.pem");
+ // Try retrieving an object that doesn't exist. That used to return
+ // BackupProtocolSuccess(NoObject) for no apparent reason.
+ TEST_COMMAND_RETURNS_ERROR(protocol, QueryGetObject(store1objid + 1),
+ Err_DoesNotExist);
+
+ // Close the protocol, so we can housekeep the account
+ protocol.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+
+ ExpectedRefCounts.resize(3); // stop test failure in teardown_test_backupstore()
+ TEARDOWN_TEST_BACKUPSTORE();
}
-std::auto_ptr<SocketStreamTLS> open_conn(const char *hostname,
- TLSContext& rContext)
+int64_t create_directory(BackupProtocolCallable& protocol, int64_t parent_dir_id)
{
- init_context(rContext);
- std::auto_ptr<SocketStreamTLS> conn(new SocketStreamTLS);
- conn->Open(rContext, Socket::TypeINET, hostname,
- BOX_PORT_BBSTORED_TEST);
- return conn;
+ // Create a directory
+ BackupStoreFilenameClear dirname("lovely_directory");
+ // Attributes
+ std::auto_ptr<IOStream> attr(new MemBlockStream(attr1, sizeof(attr1)));
+
+ std::auto_ptr<BackupProtocolSuccess> dirCreate(
+ protocol.QueryCreateDirectory2(
+ parent_dir_id, FAKE_ATTR_MODIFICATION_TIME,
+ FAKE_MODIFICATION_TIME, dirname, attr));
+
+ int64_t subdirid = dirCreate->GetObjectID();
+ set_refcount(subdirid, 1);
+ return subdirid;
}
-std::auto_ptr<BackupProtocolClient> test_server_login(const char *hostname,
- TLSContext& rContext, std::auto_ptr<SocketStreamTLS>& rapConn)
+int64_t create_file(BackupProtocolCallable& protocol, int64_t subdirid,
+ const std::string& remote_filename)
{
- rapConn = open_conn(hostname, rContext);
-
- // Make a protocol
- std::auto_ptr<BackupProtocolClient> protocol(new
- BackupProtocolClient(*rapConn));
-
- // Check the version
- std::auto_ptr<BackupProtocolVersion> serverVersion(
- protocol->QueryVersion(BACKUP_STORE_SERVER_VERSION));
- TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ // Stick a file in it
+ write_test_file(0);
- // Login
- std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(
- protocol->QueryLogin(0x01234567, 0));
+ BackupStoreFilenameClear remote_filename_encoded;
+ if (remote_filename.empty())
+ {
+ remote_filename_encoded = uploads[0].name;
+ }
+ else
+ {
+ remote_filename_encoded = remote_filename;
+ }
- return protocol;
+ std::string filename("testfiles/test0");
+ int64_t modtime;
+ std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename,
+ subdirid, remote_filename_encoded, &modtime));
+
+ std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
+ subdirid,
+ modtime,
+ modtime, /* use for attr hash too */
+ 0, /* diff from ID */
+ remote_filename_encoded,
+ upload));
+
+ int64_t subdirfileid = stored->GetObjectID();
+ set_refcount(subdirfileid, 1);
+ return subdirfileid;
}
-void run_housekeeping(BackupStoreAccountDatabase::Entry& rAccount)
+bool assert_writable_connection_fails(BackupProtocolCallable& protocol)
{
- std::string rootDir = BackupStoreAccounts::GetAccountRoot(rAccount);
- int discSet = rAccount.GetDiscSet();
-
- // Do housekeeping on this account
- HousekeepStoreAccount housekeeping(rAccount.GetID(), rootDir,
- discSet, NULL);
- housekeeping.DoHousekeeping(true /* keep trying forever */);
+ std::auto_ptr<BackupProtocolVersion> serverVersion
+ (protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ TEST_COMMAND_RETURNS_ERROR_OR(protocol, QueryLogin(0x01234567, 0),
+ Err_CannotLockStoreForWriting, return false);
+ protocol.QueryFinished();
+ return true;
}
-// Run housekeeping (for which we need to disconnect ourselves) and check
-// that it doesn't change the numbers of files.
-//
-// Also check that bbstoreaccounts doesn't change anything
+int64_t assert_readonly_connection_succeeds(BackupProtocolCallable& protocol)
+{
+ // TODO FIXME share code with test_server_login
+ std::auto_ptr<BackupProtocolVersion> serverVersion
+ (protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ std::auto_ptr<BackupProtocolLoginConfirmed> loginConf
+ (protocol.QueryLogin(0x01234567, BackupProtocolLogin::Flags_ReadOnly));
+ return loginConf->GetClientStoreMarker();
+}
-void run_housekeeping_and_check_account(const char *hostname,
- TLSContext& rContext, std::auto_ptr<SocketStreamTLS>& rapConn,
- std::auto_ptr<BackupProtocolClient>& rapProtocol)
+bool test_multiple_uploads()
{
- rapProtocol->QueryFinished();
- std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
- BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
- BackupStoreAccountDatabase::Entry account =
- apAccounts->GetEntry(0x1234567);
- run_housekeeping(account);
+ SETUP_TEST_BACKUPSTORE();
+ TEST_THAT_OR(StartServer(), FAIL);
- TEST_THAT(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf check 01234567 fix") == 0);
- TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+ std::auto_ptr<BackupProtocolCallable> apProtocol =
+ connect_and_login(context);
- rapProtocol = test_server_login(hostname, rContext, rapConn);
-}
+ // TODO FIXME replace protocolReadOnly with apProtocolReadOnly.
+ BackupProtocolLocal2 protocolReadOnly(0x01234567, "test",
+ "backup/01234567/", 0, true); // ReadOnly
-int test_server(const char *hostname)
-{
- TLSContext context;
- std::auto_ptr<SocketStreamTLS> conn;
- std::auto_ptr<BackupProtocolClient> apProtocol =
- test_server_login(hostname, context, conn);
-
- // Make some test attributes
- #define ATTR1_SIZE 245
- #define ATTR2_SIZE 23
- #define ATTR3_SIZE 122
- int attr1[ATTR1_SIZE];
- int attr2[ATTR2_SIZE];
- int attr3[ATTR3_SIZE];
+ // Read the root directory a few times (as it's cached, so make sure it doesn't hurt anything)
+ for(int l = 0; l < 3; ++l)
{
- R250 r(3465657);
- for(int l = 0; l < ATTR1_SIZE; ++l) {attr1[l] = r.next();}
- for(int l = 0; l < ATTR2_SIZE; ++l) {attr2[l] = r.next();}
- for(int l = 0; l < ATTR3_SIZE; ++l) {attr3[l] = r.next();}
+ // Command
+ apProtocol->QueryListDirectory(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */);
+ // Stream
+ BackupStoreDirectory dir(apProtocol->ReceiveStream(),
+ apProtocol->GetTimeout());
+ TEST_THAT(dir.GetNumberOfEntries() == 0);
}
- // BLOCK
- {
- // Get it logging
- FILE *protocolLog = ::fopen("testfiles/protocol.log", "w");
- TEST_THAT(protocolLog != 0);
- apProtocol->SetLogToFile(protocolLog);
-
-#ifndef WIN32
- // Check that we can't open a new connection which requests write permissions
- {
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, hostname,
- BOX_PORT_BBSTORED_TEST);
- BackupProtocolClient protocol(conn);
- std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
- TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
- TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
- protocol.QueryFinished();
- }
-#endif
-
- // Set the client store marker
- apProtocol->QuerySetClientStoreMarker(0x8732523ab23aLL);
-
-#ifndef WIN32
- // Open a new connection which is read only
- SocketStreamTLS connReadOnly;
- connReadOnly.Open(context, Socket::TypeINET, hostname,
- BOX_PORT_BBSTORED_TEST);
- BackupProtocolClient protocolReadOnly(connReadOnly);
-
- // Get it logging
- FILE *protocolReadOnlyLog = ::fopen("testfiles/protocolReadOnly.log", "w");
- TEST_THAT(protocolReadOnlyLog != 0);
- protocolReadOnly.SetLogToFile(protocolReadOnlyLog);
-
- {
- std::auto_ptr<BackupProtocolVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
- TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
- std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolLogin::Flags_ReadOnly));
-
- // Check client store marker
- TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL);
- }
-#else // WIN32
- #define protocolReadOnly (*apProtocol)
-#endif
-
- test_server_1(*apProtocol, protocolReadOnly);
-
- #define TEST_NUM_FILES(files, old, deleted, dirs) \
- { \
- std::auto_ptr<BackupStoreInfo> apInfo = \
- BackupStoreInfo::Load(0x1234567, \
- "backup/01234567/", 0, true); \
- TEST_EQUAL_LINE(files, apInfo->GetNumFiles(), \
- "num files"); \
- TEST_EQUAL_LINE(old, apInfo->GetNumOldFiles(), \
- "old files"); \
- TEST_EQUAL_LINE(deleted, apInfo->GetNumDeletedFiles(), \
- "deleted files"); \
- TEST_EQUAL_LINE(dirs, apInfo->GetNumDirectories(), \
- "directories"); \
- }
+ // Read the dir from the readonly connection (make sure it gets in the cache)
+ // Command
+ protocolReadOnly.QueryListDirectory(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes */);
+ // Stream
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ protocolReadOnly.GetTimeout());
+ TEST_THAT(dir.GetNumberOfEntries() == 0);
- TEST_NUM_FILES(1, 0, 0, 1);
- run_housekeeping_and_check_account(hostname, context,
- conn, apProtocol);
- TEST_NUM_FILES(1, 0, 0, 1);
+ // TODO FIXME dedent
+ {
+ TEST_THAT(check_num_files(0, 0, 0, 1));
// sleep to ensure that the timestamp on the file will change
::safe_sleep(1);
@@ -1078,16 +1294,16 @@ int test_server(const char *hostname)
filename += uploads[t].fnextra;
int64_t modtime = 0;
- std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), BackupProtocolListDirectory::RootDirectory, uploads[t].name, &modtime));
+ std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), BACKUPSTORE_ROOT_DIRECTORY_ID, uploads[t].name, &modtime));
TEST_THAT(modtime != 0);
-
+
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
modtime,
modtime, /* use it for attr hash too */
0, /* diff from ID */
uploads[t].name,
- *upload));
+ upload));
uploads[t].allocated_objid = stored->GetObjectID();
uploads[t].mod_time = modtime;
if(maxID < stored->GetObjectID()) maxID = stored->GetObjectID();
@@ -1095,35 +1311,73 @@ int test_server(const char *hostname)
BOX_TRACE("wrote file " << filename << " to server "
"as object " <<
BOX_FORMAT_OBJECTID(stored->GetObjectID()));
- TEST_NUM_FILES(t + 2, 0, 0, 1);
- run_housekeeping_and_check_account(hostname, context,
- conn, apProtocol);
- TEST_NUM_FILES(t + 2, 0, 0, 1);
+ // Some of the uploaded files replace old ones, increasing
+ // the old file count instead of the current file count.
+ int expected_num_old_files = 0;
+ if (t >= 8) expected_num_old_files++;
+ if (t >= 12) expected_num_old_files++;
+ if (t >= 13) expected_num_old_files++;
+ int expected_num_current_files = t + 1 - expected_num_old_files;
+
+ TEST_THAT(check_num_files(expected_num_current_files,
+ expected_num_old_files, 0, 1));
+
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol = connect_and_login(context);
+ protocolReadOnly.Reopen();
+
+ TEST_THAT(check_num_files(expected_num_current_files,
+ expected_num_old_files, 0, 1));
}
// Add some attributes onto one of them
{
- TEST_NUM_FILES(UPLOAD_NUM + 1, 0, 0, 1);
- MemBlockStream attrnew(attr3, sizeof(attr3));
+ TEST_THAT(check_num_files(UPLOAD_NUM - 3, 3, 0, 1));
+ std::auto_ptr<IOStream> attrnew(
+ new MemBlockStream(attr3, sizeof(attr3)));
std::auto_ptr<BackupProtocolSuccess> set(apProtocol->QuerySetReplacementFileAttributes(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
32498749832475LL,
uploads[UPLOAD_ATTRS_EN].name,
attrnew));
TEST_THAT(set->GetObjectID() == uploads[UPLOAD_ATTRS_EN].allocated_objid);
- TEST_NUM_FILES(UPLOAD_NUM + 1, 0, 0, 1);
+ TEST_THAT(check_num_files(UPLOAD_NUM - 3, 3, 0, 1));
}
-
+
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol = connect_and_login(context);
+ protocolReadOnly.Reopen();
+
// Delete one of them (will implicitly delete an old version)
{
std::auto_ptr<BackupProtocolSuccess> del(apProtocol->QueryDeleteFile(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
uploads[UPLOAD_DELETE_EN].name));
TEST_THAT(del->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
- TEST_NUM_FILES(UPLOAD_NUM, 0, 1, 1);
+ TEST_THAT(check_num_files(UPLOAD_NUM - 4, 3, 2, 1));
}
+#ifdef _MSC_VER
+ BOX_TRACE("1");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol = connect_and_login(context);
+ protocolReadOnly.Reopen();
+
+#ifdef _MSC_VER
+ BOX_TRACE("2");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+
// Check that the block index can be obtained by name even though it's been deleted
{
// Fetch the raw object
@@ -1131,11 +1385,11 @@ int test_server(const char *hostname)
FileStream out("testfiles/downloaddelobj", O_WRONLY | O_CREAT);
std::auto_ptr<BackupProtocolSuccess> getobj(apProtocol->QueryGetObject(uploads[UPLOAD_DELETE_EN].allocated_objid));
std::auto_ptr<IOStream> objstream(apProtocol->ReceiveStream());
- objstream->CopyStreamTo(out);
+ objstream->CopyStreamTo(out, apProtocol->GetTimeout());
}
// query index and test
std::auto_ptr<BackupProtocolSuccess> getblockindex(apProtocol->QueryGetBlockIndexByName(
- BackupProtocolListDirectory::RootDirectory, uploads[UPLOAD_DELETE_EN].name));
+ BACKUPSTORE_ROOT_DIRECTORY_ID, uploads[UPLOAD_DELETE_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(apProtocol->ReceiveStream());
TEST_THAT(check_block_index("testfiles/downloaddelobj", *blockIndexStream));
@@ -1145,12 +1399,17 @@ int test_server(const char *hostname)
for(int t = 0; t < UPLOAD_NUM; ++t)
{
printf("%d\n", t);
- std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BackupProtocolListDirectory::RootDirectory, uploads[t].allocated_objid));
+ std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID, uploads[t].allocated_objid));
TEST_THAT(getFile->GetObjectID() == uploads[t].allocated_objid);
std::auto_ptr<IOStream> filestream(apProtocol->ReceiveStream());
test_test_file(t, *filestream);
}
+#ifdef _MSC_VER
+ BOX_TRACE("3");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+
{
StreamableMemBlock attrtest(attr3, sizeof(attr3));
@@ -1161,10 +1420,15 @@ int test_server(const char *hostname)
// And on the read/write one
check_dir_after_uploads(*apProtocol, attrtest);
}
-
+
// sleep to ensure that the timestamp on the file will change
::safe_sleep(1);
+#ifdef _MSC_VER
+ BOX_TRACE("4");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+
// Check diffing and rsync like stuff...
// Build a modified file
{
@@ -1172,7 +1436,7 @@ int test_server(const char *hostname)
TEST_THAT(TestGetFileSize(TEST_FILE_FOR_PATCHING) == TEST_FILE_FOR_PATCHING_SIZE);
FileStream in(TEST_FILE_FOR_PATCHING);
void *buf = ::malloc(TEST_FILE_FOR_PATCHING_SIZE);
- FileStream out(TEST_FILE_FOR_PATCHING ".mod", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream out(TEST_FILE_FOR_PATCHING ".mod", O_WRONLY | O_CREAT);
TEST_THAT(in.Read(buf, TEST_FILE_FOR_PATCHING_PATCH_AT) == TEST_FILE_FOR_PATCHING_PATCH_AT);
out.Write(buf, TEST_FILE_FOR_PATCHING_PATCH_AT);
char insert[13] = "INSERTINSERT";
@@ -1182,51 +1446,66 @@ int test_server(const char *hostname)
::free(buf);
}
- TEST_NUM_FILES(UPLOAD_NUM, 0, 1, 1);
+ TEST_THAT(check_num_files(UPLOAD_NUM - 4, 3, 2, 1));
// Run housekeeping (for which we need to disconnect
// ourselves) and check that it doesn't change the numbers
// of files
+
+#ifdef _MSC_VER
+ BOX_TRACE("5");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+
apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+
std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
BackupStoreAccountDatabase::Entry account =
apAccounts->GetEntry(0x1234567);
- run_housekeeping(account);
+#ifdef _MSC_VER
+ BOX_TRACE("6");
+ system("dir testfiles\\0_0\\backup\\01234567");
+#endif
+ TEST_EQUAL(0, run_housekeeping(account));
- // Also check that bbstoreaccounts doesn't change anything
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf check 01234567 fix") == 0);
+ // Also check that bbstoreaccounts doesn't change anything,
+ // using an external process instead of the internal one.
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf check 01234567 fix") == 0,
+ FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
- apProtocol = test_server_login(hostname, context, conn);
+ apProtocol = connect_and_login(context);
+ protocolReadOnly.Reopen();
- TEST_NUM_FILES(UPLOAD_NUM, 0, 1, 1);
+ TEST_THAT(check_num_files(UPLOAD_NUM - 4, 3, 2, 1));
{
// Fetch the block index for this one
std::auto_ptr<BackupProtocolSuccess> getblockindex(apProtocol->QueryGetBlockIndexByName(
- BackupProtocolListDirectory::RootDirectory, uploads[UPLOAD_PATCH_EN].name));
+ BACKUPSTORE_ROOT_DIRECTORY_ID, uploads[UPLOAD_PATCH_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_PATCH_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(apProtocol->ReceiveStream());
-
+
// Do the patching
bool isCompletelyDifferent = false;
int64_t modtime;
std::auto_ptr<IOStream> patchstream(
BackupStoreFile::EncodeFileDiff(
- TEST_FILE_FOR_PATCHING ".mod",
- BackupProtocolListDirectory::RootDirectory,
- uploads[UPLOAD_PATCH_EN].name,
- uploads[UPLOAD_PATCH_EN].allocated_objid,
+ TEST_FILE_FOR_PATCHING ".mod",
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ uploads[UPLOAD_PATCH_EN].name,
+ uploads[UPLOAD_PATCH_EN].allocated_objid,
*blockIndexStream,
- IOStream::TimeOutInfinite,
+ SHORT_TIMEOUT,
NULL, // pointer to DiffTimer impl
&modtime, &isCompletelyDifferent));
TEST_THAT(isCompletelyDifferent == false);
// Sent this to a file, so we can check the size, rather than uploading it directly
{
- FileStream patch(TEST_FILE_FOR_PATCHING ".patch", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream patch(TEST_FILE_FOR_PATCHING ".patch", O_WRONLY | O_CREAT);
patchstream->CopyStreamTo(patch);
}
// Make sure the stream is a plausible size for a patch containing only one new block
@@ -1234,9 +1513,9 @@ int test_server(const char *hostname)
// Upload it
int64_t patchedID = 0;
{
- FileStream uploadpatch(TEST_FILE_FOR_PATCHING ".patch");
+ std::auto_ptr<IOStream> uploadpatch(new FileStream(TEST_FILE_FOR_PATCHING ".patch"));
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
- BackupProtocolListDirectory::RootDirectory,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
modtime,
modtime, /* use it for attr hash too */
uploads[UPLOAD_PATCH_EN].allocated_objid, /* diff from ID */
@@ -1250,71 +1529,81 @@ int test_server(const char *hostname)
set_refcount(patchedID, 1);
// Then download it to check it's OK
- std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BackupProtocolListDirectory::RootDirectory, patchedID));
+ std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID, patchedID));
TEST_THAT(getFile->GetObjectID() == patchedID);
std::auto_ptr<IOStream> filestream(apProtocol->ReceiveStream());
- BackupStoreFile::DecodeFile(*filestream, TEST_FILE_FOR_PATCHING ".downloaded", IOStream::TimeOutInfinite);
+ BackupStoreFile::DecodeFile(*filestream,
+ TEST_FILE_FOR_PATCHING ".downloaded", SHORT_TIMEOUT);
// Check it's the same
TEST_THAT(check_files_same(TEST_FILE_FOR_PATCHING ".downloaded", TEST_FILE_FOR_PATCHING ".mod"));
-
- TEST_NUM_FILES(UPLOAD_NUM, 1, 1, 1);
+ TEST_THAT(check_num_files(UPLOAD_NUM - 4, 4, 2, 1));
}
+ }
- // Create a directory
- int64_t subdirid = 0;
- BackupStoreFilenameClear dirname("lovely_directory");
- {
- // Attributes
- MemBlockStream attr(attr1, sizeof(attr1));
- std::auto_ptr<BackupProtocolSuccess> dirCreate(apProtocol->QueryCreateDirectory(
- BackupProtocolListDirectory::RootDirectory,
- 9837429842987984LL, dirname, attr));
- subdirid = dirCreate->GetObjectID();
- TEST_THAT(subdirid == maxID + 1);
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
- TEST_NUM_FILES(UPLOAD_NUM, 1, 1, 2);
- }
+ TEARDOWN_TEST_BACKUPSTORE();
+}
- set_refcount(subdirid, 1);
+bool test_server_commands()
+{
+ SETUP_TEST_BACKUPSTORE();
- // Stick a file in it
- int64_t subdirfileid = 0;
- {
- std::string filename("testfiles/test0");
- int64_t modtime;
- std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), subdirid, uploads[0].name, &modtime));
+ std::auto_ptr<BackupProtocolLocal2> apProtocol(
+ new BackupProtocolLocal2(0x01234567, "test",
+ "backup/01234567/", 0, false));
- std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
- subdirid,
- modtime,
- modtime, /* use for attr hash too */
- 0, /* diff from ID */
- uploads[0].name,
- *upload));
- subdirfileid = stored->GetObjectID();
+ // Try using GetFile on an object ID that doesn't exist in the directory
+ {
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BACKUPSTORE_ROOT_DIRECTORY_ID),
+ Err_DoesNotExistInDirectory);
+ }
- TEST_NUM_FILES(UPLOAD_NUM + 1, 1, 1, 2);
+ // BLOCK
+ // TODO FIXME dedent this block.
+ {
+ // Create a directory
+ int64_t subdirid = create_directory(*apProtocol);
+ TEST_THAT(check_num_files(0, 0, 0, 2));
+
+ // Try using GetFile on the directory
+ {
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryGetFile(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ subdirid),
+ Err_FileDoesNotVerify);
}
- set_refcount(subdirfileid, 1);
+ // Stick a file in it
+ int64_t subdirfileid = create_file(*apProtocol, subdirid);
+ TEST_THAT(check_num_files(1, 0, 0, 2));
+
+ BackupProtocolLocal2 protocolReadOnly(0x01234567, "test",
+ "backup/01234567/", 0, true); // read-only
- printf("\n==== Checking upload using read-only connection\n");
- // Check the directories on the read only connection
+ BOX_TRACE("Checking root directory using read-only connection");
{
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */)); // Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
- TEST_THAT(dir.GetNumberOfEntries() == UPLOAD_NUM + 3 /* for the first test file, the patched upload, and this new dir */);
+ protocolReadOnly.QueryListDirectory(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes! */); // Stream
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
+
+ // UPLOAD_NUM test files, patch uploaded and new dir
+ TEST_EQUAL(1, dir.GetNumberOfEntries());
// Check the last one...
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
BackupStoreDirectory::Entry *t = 0;
+ BackupStoreFilenameClear dirname("lovely_directory");
+
while((t = i.Next()) != 0)
{
if(en != 0)
@@ -1325,158 +1614,214 @@ int test_server(const char *hostname)
}
en = t;
}
- // Does it look right?
+
+ // Check that the last entry looks right
+ TEST_EQUAL(subdirid, en->GetObjectID());
TEST_THAT(en->GetName() == dirname);
- TEST_THAT(en->GetFlags() == BackupProtocolListDirectory::Flags_Dir);
- TEST_THAT(en->GetObjectID() == subdirid);
- TEST_THAT(en->GetModificationTime() == 0); // dirs don't have modification times.
+ TEST_EQUAL(BackupProtocolListDirectory::Flags_Dir, en->GetFlags());
+ int64_t actual_size = get_raid_file(subdirid)->GetDiscUsageInBlocks();
+ TEST_EQUAL(actual_size, en->GetSizeInBlocks());
+ TEST_EQUAL(FAKE_MODIFICATION_TIME, en->GetModificationTime());
}
+ BOX_TRACE("Checking subdirectory using read-only connection");
{
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ TEST_EQUAL(subdirid,
+ protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, true /* get attributes */));
- TEST_THAT(dirreply->GetObjectID() == subdirid);
- // Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ true /* get attributes */)->GetObjectID());
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
TEST_THAT(dir.GetNumberOfEntries() == 1);
- // Check the last one...
+ // Check the (only) one...
BackupStoreDirectory::Iterator i(dir);
- // Discard first
BackupStoreDirectory::Entry *en = i.Next();
TEST_THAT(en != 0);
- // Does it look right?
+
+ // Check that it looks right
+ TEST_EQUAL(subdirfileid, en->GetObjectID());
TEST_THAT(en->GetName() == uploads[0].name);
- TEST_THAT(en->GetFlags() == BackupProtocolListDirectory::Flags_File);
- TEST_THAT(en->GetObjectID() == subdirfileid);
+ TEST_EQUAL(BackupProtocolListDirectory::Flags_File, en->GetFlags());
+ int64_t actual_size = get_raid_file(subdirfileid)->GetDiscUsageInBlocks();
+ TEST_EQUAL(actual_size, en->GetSizeInBlocks());
TEST_THAT(en->GetModificationTime() != 0);
// Attributes
TEST_THAT(dir.HasAttributes());
- TEST_THAT(dir.GetAttributesModTime() == 9837429842987984LL);
+ TEST_EQUAL(FAKE_ATTR_MODIFICATION_TIME,
+ dir.GetAttributesModTime());
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
+ BOX_TRACE("Checking that we don't get attributes if we don't ask for them");
{
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- subdirid,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */));
+ protocolReadOnly.QueryListDirectory(
+ subdirid,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes! */);
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
TEST_THAT(!dir.HasAttributes());
}
- // sleep to ensure that the timestamp on the file will change
+ // Sleep to ensure that the timestamp on the file will change,
+ // invalidating the read-only connection's cache of the
+ // directory, and forcing it to be reloaded.
::safe_sleep(1);
// Change attributes on the directory
{
- MemBlockStream attrnew(attr2, sizeof(attr2));
+ std::auto_ptr<IOStream> attrnew(
+ new MemBlockStream(attr2, sizeof(attr2)));
std::auto_ptr<BackupProtocolSuccess> changereply(apProtocol->QueryChangeDirAttributes(
subdirid,
329483209443598LL,
attrnew));
TEST_THAT(changereply->GetObjectID() == subdirid);
}
+
// Check the new attributes
{
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- subdirid,
- 0, // no flags
- BackupProtocolListDirectory::Flags_EXCLUDE_EVERYTHING, true /* get attributes */));
+ protocolReadOnly.QueryListDirectory(
+ subdirid,
+ 0, // no flags
+ BackupProtocolListDirectory::Flags_EXCLUDE_EVERYTHING,
+ true /* get attributes */);
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
TEST_THAT(dir.GetNumberOfEntries() == 0);
// Attributes
TEST_THAT(dir.HasAttributes());
- TEST_THAT(dir.GetAttributesModTime() == 329483209443598LL);
+ TEST_EQUAL(329483209443598LL, dir.GetAttributesModTime());
StreamableMemBlock attrtest(attr2, sizeof(attr2));
TEST_THAT(dir.GetAttributes() == attrtest);
}
-
- // sleep to ensure that the timestamp on the file will change
+
+ BackupStoreFilenameClear& oldName(uploads[0].name);
+ int64_t root_file_id = create_file(*apProtocol, BACKUPSTORE_ROOT_DIRECTORY_ID);
+ TEST_THAT(check_num_files(2, 0, 0, 2));
+
+ // Upload a new version of the file as well, to ensure that the
+ // old version is moved along with the current version.
+ root_file_id = BackupStoreFile::QueryStoreFileDiff(*apProtocol,
+ "testfiles/test0", BACKUPSTORE_ROOT_DIRECTORY_ID,
+ 0, // DiffFromFileID
+ 0, // AttributesHash
+ oldName);
+ set_refcount(root_file_id, 1);
+ TEST_THAT(check_num_files(2, 1, 0, 2));
+
+ // Check that it's in the root directory (it won't be for long)
+ protocolReadOnly.QueryListDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ 0, 0, false);
+ TEST_THAT(BackupStoreDirectory(protocolReadOnly.ReceiveStream())
+ .FindEntryByID(root_file_id) != NULL);
+
+ BackupStoreFilenameClear newName("moved-files");
+
+ // Sleep before modifying the root directory, to ensure that
+ // the timestamp on the file it's stored in will change when
+ // we modify it, invalidating the read-only connection's cache
+ // and forcing it to reload the root directory, next time we
+ // ask for its contents.
::safe_sleep(1);
// Test moving a file
{
- BackupStoreFilenameClear newName("moved-files");
-
- std::auto_ptr<BackupProtocolSuccess> rep(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
- BackupProtocolListDirectory::RootDirectory,
+ std::auto_ptr<BackupProtocolSuccess> rep(apProtocol->QueryMoveObject(root_file_id,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName));
- TEST_THAT(rep->GetObjectID() == uploads[UPLOAD_FILE_TO_MOVE].allocated_objid);
+ TEST_EQUAL(root_file_id, rep->GetObjectID());
}
// Try some dodgy renames
{
+ // File doesn't exist at all
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryMoveObject(-1,
+ BACKUPSTORE_ROOT_DIRECTORY_ID, subdirid,
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ Err_DoesNotExistInDirectory);
BackupStoreFilenameClear newName("moved-files");
- TEST_CHECK_THROWS(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryMoveObject(
+ uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolListDirectory::RootDirectory,
- subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName),
- ConnectionException, Conn_Protocol_UnexpectedReply);
- TEST_CHECK_THROWS(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
subdirid,
- subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName),
- ConnectionException, Conn_Protocol_UnexpectedReply);
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ Err_DoesNotExistInDirectory);
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryMoveObject(
+ uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ subdirid,
+ subdirid,
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ Err_DoesNotExistInDirectory);
}
- // Rename within a directory
- {
- BackupStoreFilenameClear newName("moved-files-x");
- apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ // File exists, but not in this directory (we just moved it)
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryMoveObject(root_file_id,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
subdirid,
- subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName);
- }
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ Err_DoesNotExistInDirectory);
+
+ // Moving file to same directory that it's already in,
+ // with the same name
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryMoveObject(root_file_id,
+ subdirid,
+ subdirid,
+ BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName),
+ Err_TargetNameExists);
- // Check it's all gone from the root directory...
+ // Rename within a directory (successfully)
{
- // Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
- // Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
- // Read all entries
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = 0;
- while((en = i.Next()) != 0)
- {
- TEST_THAT(en->GetName() != uploads[UPLOAD_FILE_TO_MOVE].name);
- }
+ BackupStoreFilenameClear newName2("moved-files-x");
+ apProtocol->QueryMoveObject(root_file_id, subdirid,
+ subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName,
+ newName2);
}
+ // Check it's all gone from the root directory...
+ protocolReadOnly.QueryListDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ 0, 0, false);
+ TEST_THAT(BackupStoreDirectory(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT).FindEntryByID(root_file_id) == NULL);
+
// Check the old and new versions are in the other directory
{
+ BackupStoreFilenameClear notThere("moved-files");
BackupStoreFilenameClear lookFor("moved-files-x");
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- subdirid,
- BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+ protocolReadOnly.QueryListDirectory(
+ subdirid,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes */);
+
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
+
// Check entries
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
@@ -1484,6 +1829,10 @@ int test_server(const char *hostname)
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;
@@ -1501,52 +1850,63 @@ int test_server(const char *hostname)
int64_t subsubdirid = 0;
int64_t subsubfileid = 0;
{
+ // TODO FIXME use create_dir() and create_file() instead.
BackupStoreFilenameClear nd("sub2");
// Attributes
- MemBlockStream attr(attr1, sizeof(attr1));
- std::auto_ptr<BackupProtocolSuccess> dirCreate(apProtocol->QueryCreateDirectory(
- subdirid,
- 9837429842987984LL, nd, attr));
- subsubdirid = dirCreate->GetObjectID();
+ std::auto_ptr<IOStream> attr(new MemBlockStream(attr1,
+ sizeof(attr1)));
+ subsubdirid = apProtocol->QueryCreateDirectory(subdirid,
+ FAKE_ATTR_MODIFICATION_TIME, nd, attr)->GetObjectID();
+
+ write_test_file(2);
- FileStream upload("testfiles/file1_upload1");
- BackupStoreFilenameClear nf("file2");
+ BackupStoreFilenameClear file2("file2");
+ std::auto_ptr<IOStream> upload(
+ BackupStoreFile::EncodeFile("testfiles/test2",
+ BACKUPSTORE_ROOT_DIRECTORY_ID, file2));
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
subsubdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
- nf,
+ file2,
upload));
subsubfileid = stored->GetObjectID();
}
set_refcount(subsubdirid, 1);
set_refcount(subsubfileid, 1);
+ TEST_THAT(check_num_files(3, 1, 0, 3));
+
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ apProtocol->Reopen();
+ protocolReadOnly.Reopen();
// Query names -- test that invalid stuff returns not found OK
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(3248972347823478927LL, subsubdirid));
- TEST_THAT(nameRep->GetNumNameElements() == 0);
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(subsubfileid, 2342378424LL));
- TEST_THAT(nameRep->GetNumNameElements() == 0);
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(38947234789LL, 2342378424LL));
- TEST_THAT(nameRep->GetNumNameElements() == 0);
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(BackupProtocolGetObjectName::ObjectID_DirectoryOnly, 2234342378424LL));
- TEST_THAT(nameRep->GetNumNameElements() == 0);
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
}
// Query names... first, get info for the file
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(subsubfileid, subsubdirid));
std::auto_ptr<IOStream> namestream(apProtocol->ReceiveStream());
-
+
TEST_THAT(nameRep->GetNumNameElements() == 3);
TEST_THAT(nameRep->GetFlags() == BackupProtocolListDirectory::Flags_File);
TEST_THAT(nameRep->GetModificationTime() == 0x123456789abcdefLL);
@@ -1564,7 +1924,7 @@ int test_server(const char *hostname)
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(BackupProtocolGetObjectName::ObjectID_DirectoryOnly, subsubdirid));
std::auto_ptr<IOStream> namestream(apProtocol->ReceiveStream());
-
+
TEST_THAT(nameRep->GetNumNameElements() == 2);
TEST_THAT(nameRep->GetFlags() == BackupProtocolListDirectory::Flags_Dir);
static const char *testnames[] = {"sub2","lovely_directory"};
@@ -1575,82 +1935,348 @@ int test_server(const char *hostname)
TEST_THAT(fn.GetClearFilename() == testnames[l]);
}
}
-
+
//} skip:
- std::auto_ptr<BackupStoreRefCountDatabase> apRefCount(
- BackupStoreRefCountDatabase::Load(
- apAccounts->GetEntry(0x1234567), true));
-
// Create some nice recursive directories
- int64_t dirtodelete = create_test_data_subdirs(*apProtocol,
- BackupProtocolListDirectory::RootDirectory,
- "test_delete", 6 /* depth */, *apRefCount);
-
+ TEST_THAT(check_reference_counts());
+
+ write_test_file(1);
+ int64_t dirtodelete;
+
+ {
+ std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
+ BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
+ std::auto_ptr<BackupStoreRefCountDatabase> apRefCount(
+ BackupStoreRefCountDatabase::Load(
+ apAccounts->GetEntry(0x1234567), true));
+
+
+ dirtodelete = create_test_data_subdirs(*apProtocol,
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ "test_delete", 6 /* depth */, apRefCount.get());
+ }
+
+ TEST_THAT(check_reference_counts());
+
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ TEST_THAT(check_reference_counts());
+
// And delete them
+ apProtocol->Reopen();
+ protocolReadOnly.Reopen();
+
{
std::auto_ptr<BackupProtocolSuccess> dirdel(apProtocol->QueryDeleteDirectory(
dirtodelete));
TEST_THAT(dirdel->GetObjectID() == dirtodelete);
}
+ apProtocol->QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(run_housekeeping_and_check_account());
+ TEST_THAT(check_reference_counts());
+ protocolReadOnly.Reopen();
+
// Get the root dir, checking for deleted items
{
// Command
- std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
- BackupProtocolListDirectory::RootDirectory,
- BackupProtocolListDirectory::Flags_Dir | BackupProtocolListDirectory::Flags_Deleted,
- BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+ protocolReadOnly.QueryListDirectory(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ BackupProtocolListDirectory::Flags_Dir |
+ BackupProtocolListDirectory::Flags_Deleted,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes */);
// Stream
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
- dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
-
+ BackupStoreDirectory dir(protocolReadOnly.ReceiveStream(),
+ SHORT_TIMEOUT);
+
// Check there's only that one entry
TEST_THAT(dir.GetNumberOfEntries() == 1);
-
+
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = i.Next();
TEST_THAT(en != 0);
if(en)
{
- TEST_THAT(en->GetObjectID() == dirtodelete);
+ TEST_EQUAL(dirtodelete, en->GetObjectID());
BackupStoreFilenameClear n("test_delete");
TEST_THAT(en->GetName() == n);
}
-
+
// Then... check everything's deleted
- test_everything_deleted(protocolReadOnly, dirtodelete);
+ 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();
-
- // Close logs
-#ifndef WIN32
- ::fclose(protocolReadOnlyLog);
-#endif
- ::fclose(protocolLog);
+ protocolReadOnly.QueryFinished();
+
+ TEST_THAT(run_housekeeping_and_check_account());
+ TEST_THAT(check_reference_counts());
}
-
- return 0;
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+int get_object_size(BackupProtocolCallable& protocol, int64_t ObjectID,
+ int64_t ContainerID)
+{
+ // Get the root directory cached in the read-only connection
+ protocol.QueryListDirectory(ContainerID, 0, // FlagsMustBeSet
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+ false /* no attributes */);
+
+ BackupStoreDirectory dir(protocol.ReceiveStream());
+ BackupStoreDirectory::Entry *en = dir.FindEntryByID(ObjectID);
+ TEST_THAT_OR(en != 0, return -1);
+ TEST_EQUAL_OR(ObjectID, en->GetObjectID(), return -1);
+ return en->GetSizeInBlocks();
+}
+
+bool write_dir(BackupStoreDirectory& dir)
+{
+ std::string rfn;
+ StoreStructure::MakeObjectFilename(dir.GetObjectID(),
+ "backup/01234567/" /* mStoreRoot */, 0 /* mStoreDiscSet */,
+ rfn, false); // EnsureDirectoryExists
+ RaidFileWrite rfw(0, rfn);
+ rfw.Open(true); // AllowOverwrite
+ dir.WriteToStream(rfw);
+ rfw.Commit(/* ConvertToRaidNow */ true);
+ return true;
+}
+
+bool test_directory_parent_entry_tracks_directory_size()
+{
+ SETUP_TEST_BACKUPSTORE();
+
+ BackupProtocolLocal2 protocol(0x01234567, "test", "backup/01234567/",
+ 0, false);
+ BackupProtocolLocal2 protocolReadOnly(0x01234567, "test",
+ "backup/01234567/", 0, true); // read only
+
+ int64_t subdirid = create_directory(protocol);
+
+ // Get the root directory cached in the read-only connection, and
+ // test that the initial size is correct.
+ int old_size = get_raid_file(subdirid)->GetDiscUsageInBlocks();
+ TEST_THAT(old_size > 0);
+ TEST_EQUAL(old_size, 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);
+
+ // Start adding files until the size on disk increases. This is
+ // guaranteed to happen eventually :)
+ int new_size = old_size;
+ int64_t last_added_file_id = 0;
+ std::string last_added_filename;
+
+ for (int i = 0; new_size == old_size; i++)
+ {
+ std::ostringstream name;
+ name << "testfile_" << i;
+ last_added_filename = name.str();
+ last_added_file_id = create_file(protocol, subdirid, name.str());
+ new_size = get_raid_file(subdirid)->GetDiscUsageInBlocks();
+ }
+
+ // Check that the root directory entry has been updated
+ TEST_EQUAL(new_size, get_object_size(protocolReadOnly, subdirid,
+ BACKUPSTORE_ROOT_DIRECTORY_ID));
+
+ // Now delete an entry, and check that the size is reduced
+ protocol.QueryDeleteFile(subdirid,
+ BackupStoreFilenameClear(last_added_filename));
+ ExpectedRefCounts[last_added_file_id] = 0;
+
+ // Reduce the limits, to remove it permanently from the store
+ protocol.QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(change_account_limits("0B", "20000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
+ set_refcount(last_added_file_id, 0);
+ protocol.Reopen();
+ protocolReadOnly.Reopen();
+
+ TEST_EQUAL(old_size, get_raid_file(subdirid)->GetDiscUsageInBlocks());
+
+ // Check that the entry in the root directory was updated too
+ TEST_EQUAL(old_size, get_object_size(protocolReadOnly, subdirid,
+ BACKUPSTORE_ROOT_DIRECTORY_ID));
+
+ // Push the limits back up
+ protocol.QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(change_account_limits("1000B", "20000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+ protocolReadOnly.Reopen();
+
+ // Now modify the root directory to remove its entry for this one
+ BackupStoreDirectory root(*get_raid_file(BACKUPSTORE_ROOT_DIRECTORY_ID),
+ IOStream::TimeOutInfinite);
+ BackupStoreDirectory::Entry *en = root.FindEntryByID(subdirid);
+ TEST_THAT_OR(en, return false);
+ BackupStoreDirectory::Entry enCopy(*en);
+ root.DeleteEntry(subdirid);
+ TEST_THAT(write_dir(root));
+
+ // Add a directory, this should try to push the object size back up,
+ // which will try to modify the subdir's entry in its parent, which
+ // no longer exists, which should just log an error instead of
+ // aborting/segfaulting.
+ create_directory(protocol, subdirid);
+
+ // Repair the error ourselves, as bbstoreaccounts can't.
+ protocol.QueryFinished();
+ enCopy.SetSizeInBlocks(get_raid_file(subdirid)->GetDiscUsageInBlocks());
+ root.AddEntry(enCopy);
+ TEST_THAT(write_dir(root));
+
+ // We also have to remove the entry for lovely_directory created by
+ // create_directory(), because otherwise we can't create it again.
+ // (Perhaps it should not have been committed because we failed to
+ // update the parent, but currently it is.)
+ BackupStoreDirectory subdir(*get_raid_file(subdirid),
+ IOStream::TimeOutInfinite);
+ {
+ BackupStoreDirectory::Iterator i(subdir);
+ en = i.FindMatchingClearName(
+ BackupStoreFilenameClear("lovely_directory"));
+ }
+ TEST_THAT_OR(en, return false);
+ protocol.Reopen();
+ protocol.QueryDeleteDirectory(en->GetObjectID());
+ set_refcount(en->GetObjectID(), 0);
+
+ // This should have fixed the error, so we should be able to add the
+ // entry now. This should push the object size back up.
+ int64_t dir2id = create_directory(protocol, subdirid);
+ TEST_EQUAL(new_size, get_raid_file(subdirid)->GetDiscUsageInBlocks());
+ TEST_EQUAL(new_size, get_object_size(protocolReadOnly, subdirid,
+ BACKUPSTORE_ROOT_DIRECTORY_ID));
+
+ // Delete it again, which should reduce the object size again
+ protocol.QueryDeleteDirectory(dir2id);
+ set_refcount(dir2id, 0);
+
+ // Reduce the limits, to remove it permanently from the store
+ protocol.QueryFinished();
+ protocolReadOnly.QueryFinished();
+ TEST_THAT(change_account_limits("0B", "20000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
+ protocol.Reopen();
+ protocolReadOnly.Reopen();
+
+ // Check that the entry in the root directory was updated
+ TEST_EQUAL(old_size, get_raid_file(subdirid)->GetDiscUsageInBlocks());
+ TEST_EQUAL(old_size, get_object_size(protocolReadOnly, subdirid,
+ BACKUPSTORE_ROOT_DIRECTORY_ID));
+
+ // Check that bbstoreaccounts check fix will detect and repair when
+ // a directory's parent entry has the wrong size for the directory.
+
+ protocol.QueryFinished();
+
+ root.ReadFromStream(*get_raid_file(BACKUPSTORE_ROOT_DIRECTORY_ID),
+ IOStream::TimeOutInfinite);
+ 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);
+
+ protocolReadOnly.QueryFinished();
+ TEST_EQUAL(1, check_account_for_errors());
+
+ protocolReadOnly.Reopen();
+ TEST_EQUAL(old_size, get_object_size(protocolReadOnly, subdirid,
+ BACKUPSTORE_ROOT_DIRECTORY_ID));
+ protocolReadOnly.QueryFinished();
+
+ TEARDOWN_TEST_BACKUPSTORE();
}
-int test3(int argc, const char *argv[])
+bool test_cannot_open_multiple_writable_connections()
+{
+ SETUP_TEST_BACKUPSTORE();
+
+ // First try a local protocol. This works even on Windows.
+ BackupProtocolLocal2 protocolWritable(0x01234567, "test",
+ "backup/01234567/", 0, false); // Not read-only
+
+ // Set the client store marker
+ protocolWritable.QuerySetClientStoreMarker(0x8732523ab23aLL);
+
+ // First try a local protocol. This works even on Windows.
+ {
+ BackupStoreContext bsContext(0x01234567, (HousekeepingInterface *)NULL, "test");
+ bsContext.SetClientHasAccount("backup/01234567/", 0);
+ BackupProtocolLocal protocolWritable2(bsContext);
+ TEST_THAT(assert_writable_connection_fails(protocolWritable2));
+ }
+
+ {
+ 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.
+ TEST_THAT_OR(StartServer(), return false);
+
+ BackupProtocolClient protocolWritable3(open_conn("localhost", context));
+ TEST_THAT(assert_writable_connection_fails(protocolWritable3));
+
+ // Do not dedent. Object needs to go out of scope to release lock
+ {
+ BackupProtocolClient protocolReadOnly2(open_conn("localhost", context));
+ TEST_EQUAL(0x8732523ab23aLL,
+ assert_readonly_connection_succeeds(protocolReadOnly2));
+ }
+
+ protocolWritable.QueryFinished();
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_encoding()
{
// Now test encoded files
// TODO: This test needs to check failure situations as well as everything working,
// but this will be saved for the full implementation.
+
+ SETUP_TEST_BACKUPSTORE();
+
int encfile[ENCFILE_SIZE];
{
for(int l = 0; l < ENCFILE_SIZE; ++l)
{
encfile[l] = l * 173;
}
-
+
// Encode and decode a small block (shouldn't be compressed)
{
#define SMALL_BLOCK_SIZE 251
@@ -1658,14 +2284,14 @@ int test3(int argc, const char *argv[])
TEST_THAT(encBlockSize > SMALL_BLOCK_SIZE);
BackupStoreFile::EncodingBuffer encoded;
encoded.Allocate(encBlockSize / 8); // make sure reallocation happens
-
+
// Encode!
int encSize = BackupStoreFile::EncodeChunk(encfile, SMALL_BLOCK_SIZE, encoded);
// Check the header says it's not been compressed
TEST_THAT((encoded.mpBuffer[0] & 1) == 0);
// Check the output size has been inflated (no compression)
TEST_THAT(encSize > SMALL_BLOCK_SIZE);
-
+
// Decode it
int decBlockSize = BackupStoreFile::OutputBufferSizeForKnownOutputSize(SMALL_BLOCK_SIZE);
TEST_THAT(decBlockSize > SMALL_BLOCK_SIZE);
@@ -1673,10 +2299,10 @@ int test3(int argc, const char *argv[])
int decSize = BackupStoreFile::DecodeChunk(encoded.mpBuffer, encSize, decoded, decBlockSize);
TEST_THAT(decSize < decBlockSize);
TEST_THAT(decSize == SMALL_BLOCK_SIZE);
-
+
// Check it came out of the wash the same
TEST_THAT(::memcmp(encfile, decoded, SMALL_BLOCK_SIZE) == 0);
-
+
free(decoded);
}
@@ -1686,14 +2312,14 @@ int test3(int argc, const char *argv[])
TEST_THAT(encBlockSize > ENCFILE_SIZE);
BackupStoreFile::EncodingBuffer encoded;
encoded.Allocate(encBlockSize / 8); // make sure reallocation happens
-
+
// Encode!
int encSize = BackupStoreFile::EncodeChunk(encfile, ENCFILE_SIZE, encoded);
// Check the header says it's compressed
TEST_THAT((encoded.mpBuffer[0] & 1) == 1);
// Check the output size make it likely that it's compressed (is very compressible data)
TEST_THAT(encSize < ENCFILE_SIZE);
-
+
// Decode it
int decBlockSize = BackupStoreFile::OutputBufferSizeForKnownOutputSize(ENCFILE_SIZE);
TEST_THAT(decBlockSize > ENCFILE_SIZE);
@@ -1704,37 +2330,74 @@ int test3(int argc, const char *argv[])
// Check it came out of the wash the same
TEST_THAT(::memcmp(encfile, decoded, ENCFILE_SIZE) == 0);
-
+
free(decoded);
}
-
+
// The test block to a file
{
- FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT);
f.Write(encfile, sizeof(encfile));
}
-
+
// Encode it
{
- FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT);
BackupStoreFilenameClear name("testfiles/testenc1");
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name));
encoded->CopyStreamTo(out);
}
-
+
// Verify it
{
FileStream enc("testfiles/testenc1_enc");
TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true);
+
+ // And using the stream-based interface, writing different
+ // block sizes at a time.
+ CollectInBufferStream contents;
+ enc.Seek(0, IOStream::SeekType_Absolute);
+ enc.CopyStreamTo(contents);
+ contents.SetForReading();
+
+ enc.Seek(0, IOStream::SeekType_End);
+ size_t file_size = enc.GetPosition();
+ TEST_EQUAL(file_size, contents.GetSize());
+
+ for(int buffer_size = 1; ; buffer_size <<= 1)
+ {
+ enc.Seek(0, IOStream::SeekType_Absolute);
+ CollectInBufferStream temp_copy;
+ BackupStoreFile::VerifyStream verifier(&temp_copy);
+ enc.CopyStreamTo(verifier, IOStream::TimeOutInfinite,
+ buffer_size);
+
+ // The block index is only validated on Close(), which
+ // CopyStreamTo() doesn't do.
+ verifier.Close();
+
+ temp_copy.SetForReading();
+ TEST_EQUAL(file_size, temp_copy.GetSize());
+ TEST_THAT(memcmp(contents.GetBuffer(),
+ temp_copy.GetBuffer(), file_size) == 0);
+
+ // Keep doubling buffer size until we've copied the
+ // entire encoded file in a single pass, then stop.
+ if(buffer_size > file_size)
+ {
+ break;
+ }
+ }
}
-
+
// Decode it
{
+ UNLINK_IF_EXISTS("testfiles/testenc1_orig");
FileStream enc("testfiles/testenc1_enc");
BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite);
}
-
+
// Read in rebuilt original, and compare contents
{
TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile));
@@ -1743,7 +2406,7 @@ int test3(int argc, const char *argv[])
in.Read(encfile_i, sizeof(encfile_i));
TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0);
}
-
+
// Check how many blocks it had, and test the stream based interface
{
FileStream enc("testfiles/testenc1_enc");
@@ -1756,11 +2419,11 @@ int test3(int argc, const char *argv[])
TEST_THAT(decoded->GetNumBlocks() == 3);
}
-
+
// Test that the last block in a file, if less than 256 bytes, gets put into the last block
{
#define FILE_SIZE_JUST_OVER ((4096*2)+58)
- FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL);
+ FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT);
f.Write(encfile + 2, FILE_SIZE_JUST_OVER);
BackupStoreFilenameClear name("testenc2");
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name));
@@ -1772,11 +2435,11 @@ int test3(int argc, const char *argv[])
decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 879 /* buffer block size */);
d.SetForReading();
TEST_THAT(d.GetSize() == FILE_SIZE_JUST_OVER);
- TEST_THAT(memcmp(encfile + 2, d.GetBuffer(), FILE_SIZE_JUST_OVER) == 0);
+ TEST_THAT(memcmp(encfile + 2, d.GetBuffer(), FILE_SIZE_JUST_OVER) == 0);
TEST_THAT(decoded->GetNumBlocks() == 2);
}
-
+
// Test that reordered streams work too
{
FileStream enc("testfiles/testenc1_enc");
@@ -1790,25 +2453,39 @@ int test3(int argc, const char *argv[])
TEST_THAT(decoded->GetNumBlocks() == 3);
}
-
+ }
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_symlinks()
+{
+ SETUP_TEST_BACKUPSTORE();
+
#ifndef WIN32 // no symlinks on Win32
- // Try out doing this on a symlink
- {
- TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0);
- BackupStoreFilenameClear name("testsymlink");
- std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testsymlink", 32, name));
- // Can't decode it from the stream, because it's in file order, and doesn't have the
- // required properties to be able to reorder it. So buffer it...
- CollectInBufferStream b;
- encoded->CopyStreamTo(b);
- b.SetForReading();
- // Decode it
- BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite);
- }
+ UNLINK_IF_EXISTS("testfiles/testsymlink");
+ TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0);
+ BackupStoreFilenameClear name("testsymlink");
+ std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testsymlink", 32, name));
+
+ // Can't decode it from the stream, because it's in file order, and doesn't have the
+ // required properties to be able to reorder it. So buffer it...
+ CollectInBufferStream b;
+ encoded->CopyStreamTo(b);
+ b.SetForReading();
+
+ // Decode it
+ UNLINK_IF_EXISTS("testfiles/testsymlink_2");
+ BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite);
#endif
- }
- // Store info
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_store_info()
+{
+ SETUP_TEST_BACKUPSTORE();
+
{
RaidFileWrite::CreateDirectory(0, "test-info");
BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL);
@@ -1841,6 +2518,7 @@ int test3(int argc, const char *argv[])
TEST_CHECK_THROWS(info->RemovedDeletedDirectory(9), BackupStoreException, StoreInfoDirNotInList);
info->Save();
}
+
{
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, true));
TEST_THAT(info->GetBlocksUsed() == 7);
@@ -1855,68 +2533,79 @@ int test3(int argc, const char *argv[])
TEST_THAT(delfiles[1] == 4);
}
-//printf("SKIPPINGTESTS---------\n");
-//return 0;
-
- // Context
- TLSContext context;
- context.Initialise(false /* client */,
- "testfiles/clientCerts.pem",
- "testfiles/clientPrivKey.pem",
- "testfiles/clientTrustedCAs.pem");
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+bool test_login_without_account()
+{
// First, try logging in without an account having been created... just make sure login fails.
- std::string cmd = BBSTORED " " + bbstored_args +
- " testfiles/bbstored.conf";
- int pid = LaunchServer(cmd.c_str(), "testfiles/bbstored.pid");
-
- TEST_THAT(pid != -1 && pid != 0);
- if(pid <= 0)
- {
- return 1;
- }
-
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+ SETUP_TEST_BACKUPSTORE();
+ delete_account();
+ TEST_THAT_OR(StartServer(), FAIL);
// BLOCK
{
// Open a connection to the server
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost",
- BOX_PORT_BBSTORED_TEST);
-
- // Make a protocol
- BackupProtocolClient protocol(conn);
+ BackupProtocolClient protocol(open_conn("localhost", context));
// Check the version
std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
- TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
-
+ TEST_COMMAND_RETURNS_ERROR(protocol, QueryLogin(0x01234567, 0),
+ Err_BadLogin);
+
// Finish the connection
protocol.QueryFinished();
}
- // Create an account for the test client
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf create 01234567 0 "
- "10000B 20000B") == 0);
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_bbstoreaccounts_create()
+{
+ SETUP_TEST_BACKUPSTORE();
+
+ // Delete the account, and create it again using bbstoreaccounts
+ delete_account();
+
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf -Wwarning create 01234567 0 "
+ "10000B 20000B") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_bbstoreaccounts_delete()
+{
+ SETUP_TEST_BACKUPSTORE();
+ 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(create_account(10000, 20000));
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+// Test that login fails on a disabled account
+bool test_login_with_disabled_account()
+{
+ SETUP_TEST_BACKUPSTORE();
+ TEST_THAT_OR(StartServer(), FAIL);
+
TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567"));
TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8);
+
// make sure something is written to it
-
std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
-
std::auto_ptr<BackupStoreRefCountDatabase> apReferences(
BackupStoreRefCountDatabase::Load(
apAccounts->GetEntry(0x1234567), true));
@@ -1924,224 +2613,193 @@ int test3(int argc, const char *argv[])
apReferences->GetLastObjectIDUsed());
TEST_EQUAL(1, apReferences->GetRefCount(BACKUPSTORE_ROOT_DIRECTORY_ID))
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 login fails on a disabled account
+ TEST_THAT_OR(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf enabled 01234567 no") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+
// BLOCK
{
// Open a connection to the server
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost",
- BOX_PORT_BBSTORED_TEST);
-
- // Make a protocol
- BackupProtocolClient protocol(conn);
+ BackupProtocolClient protocol(open_conn("localhost", context));
// Check the version
std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
- TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolLoginConfirmed>
- loginConf(protocol.QueryLogin(0x01234567, 0)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
- int type, subType;
- TEST_EQUAL_LINE(true, protocol.GetLastError(type, subType),
- "expected a protocol error");
- TEST_EQUAL_LINE(BackupProtocolError::ErrorType, type,
- "expected a BackupProtocolError");
- TEST_EQUAL_LINE(BackupProtocolError::Err_DisabledAccount, subType,
- "expected an Err_DisabledAccount");
-
+ TEST_COMMAND_RETURNS_ERROR(protocol, QueryLogin(0x01234567, 0),
+ Err_DisabledAccount);
+
// Finish the connection
protocol.QueryFinished();
}
- // Re-enable the account so that subsequent logins should succeed
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf enabled 01234567 yes") == 0);
- TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+ TEARDOWN_TEST_BACKUPSTORE();
+}
- // Delete the refcount database and log in again,
- // check that it is recreated automatically but with
- // no objects in it, to ensure seamless upgrade.
- TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.db.rfw"));
+bool test_login_with_no_refcount_db()
+{
+ SETUP_TEST_BACKUPSTORE();
- std::auto_ptr<SocketStreamTLS> conn;
- test_server_login("localhost", context, conn)->QueryFinished();
+ // 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
+ // we're locked out of the account until housekeeping has recreated
+ // the refcount db.
+ TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.rdb.rfw"));
+ TEST_CHECK_THROWS(BackupProtocolLocal2 protocolLocal(0x01234567,
+ "test", "backup/01234567/", 0, false), // Not read-only
+ BackupStoreException, CorruptReferenceCountDatabase);
+
+ // Run housekeeping, check that it fixes the refcount db
+ std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
+ BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
BackupStoreAccountDatabase::Entry account =
apAccounts->GetEntry(0x1234567);
- apReferences = BackupStoreRefCountDatabase::Load(account, true);
- TEST_EQUAL(0, apReferences->GetLastObjectIDUsed());
-
- TEST_THAT(ServerIsAlive(pid));
+ 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"));
- run_housekeeping(account);
+ // 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
- TEST_EQUAL(BACKUPSTORE_ROOT_DIRECTORY_ID,
- apReferences->GetLastObjectIDUsed());
- TEST_EQUAL(1, apReferences->GetRefCount(BACKUPSTORE_ROOT_DIRECTORY_ID))
+ TEST_THAT(check_reference_counts());
- TEST_THAT(ServerIsAlive(pid));
+ // 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);
- set_refcount(BACKUPSTORE_ROOT_DIRECTORY_ID, 1);
+ TEST_THAT(ServerIsAlive(bbstored_pid));
- TEST_THAT(test_server("localhost") == 0);
+ // 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());
- // test that all object reference counts have the
- // expected values
- 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));
- }
+ // And that we can log in afterwards
+ connect_and_login(context)->QueryFinished();
- // 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.db.rfw"));
- run_housekeeping(account);
- apReferences = BackupStoreRefCountDatabase::Load(account, true);
+ TEARDOWN_TEST_BACKUPSTORE();
+}
- 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));
- }
-
+bool test_housekeeping_deletes_files()
+{
// Test the deletion of objects by the housekeeping system
+
+ SETUP_TEST_BACKUPSTORE();
+
+ BackupProtocolLocal2 protocolLocal(0x01234567, "test",
+ "backup/01234567/", 0, false); // Not read-only
+
+ // Create some nice recursive directories
+ write_test_file(1);
+ int64_t dirtodelete = create_test_data_subdirs(protocolLocal,
+ BACKUPSTORE_ROOT_DIRECTORY_ID, "test_delete", 6 /* depth */,
+ NULL /* pRefCount */);
+
+ TEST_EQUAL(dirtodelete,
+ protocolLocal.QueryDeleteDirectory(dirtodelete)->GetObjectID());
+ assert_everything_deleted(protocolLocal, dirtodelete);
+ protocolLocal.QueryFinished();
+
// First, things as they are now.
+ TEST_THAT_OR(StartServer(), FAIL);
recursive_count_objects_results before = {0,0,0};
+ recursive_count_objects(BACKUPSTORE_ROOT_DIRECTORY_ID, before);
- recursive_count_objects("localhost", BackupProtocolListDirectory::RootDirectory, before);
-
- TEST_THAT(before.objectsNotDel != 0);
+ TEST_EQUAL(0, before.objectsNotDel);
TEST_THAT(before.deleted != 0);
TEST_THAT(before.old != 0);
// Kill it
- TEST_THAT(KillServer(pid));
- ::sleep(1);
- TEST_THAT(!ServerIsAlive(pid));
-
- #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
- // soft limit.
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf setlimit 01234567 "
- "10B 20000B") == 0);
- TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
-
- // Start things up
- pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
- "testfiles/bbstored.pid");
+ TEST_THAT(StopServer());
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
-
- // wait for housekeeping to happen
- printf("waiting for housekeeping:\n");
- for(int l = 0; l < 30; ++l)
- {
- ::sleep(1);
- printf(".");
- fflush(stdout);
- }
- printf("\n");
+ // Reduce the store limits, so housekeeping will remove all old files.
+ // Leave the hard limit high, so we know that housekeeping's target
+ // for freeing space is the soft limit.
+ TEST_THAT(change_account_limits("0B", "20000B"));
+ TEST_THAT(run_housekeeping_and_check_account());
// Count the objects again
recursive_count_objects_results after = {0,0,0};
- recursive_count_objects("localhost",
- BackupProtocolListDirectory::RootDirectory,
- after);
-
- // If these tests fail then try increasing the timeout above
- TEST_THAT(after.objectsNotDel == before.objectsNotDel);
- TEST_THAT(after.deleted == 0);
- TEST_THAT(after.old == 0);
-
+ recursive_count_objects(BACKUPSTORE_ROOT_DIRECTORY_ID, after);
+ TEST_EQUAL(before.objectsNotDel, after.objectsNotDel);
+ TEST_EQUAL(0, after.deleted);
+ TEST_EQUAL(0, after.old);
+
+ // Adjust reference counts on deleted files, so that the final checks in
+ // teardown_test_backupstore() don't fail.
+ ExpectedRefCounts.resize(2);
+
+ // Delete the account to stop teardown_test_backupstore from checking it.
+ // TODO FIXME investigate the block count mismatch that teardown_test_backupstore
+ // catches if we don't delete the account.
+ delete_account();
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+bool test_account_limits_respected()
+{
+ SETUP_TEST_BACKUPSTORE();
+ 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 "
- "10B 20B") == 0);
+ "2B 2B") == 0, FAIL);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
- // Try to upload a file and create a directory, and check an error is generated
+ // Try to upload a file and create a directory, both of which would exceed the
+ // current account limits, and check that each command returns an error.
{
- // Open a connection to the server
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost",
- BOX_PORT_BBSTORED_TEST);
-
- // Make a protocol
- BackupProtocolClient protocol(conn);
-
- // Check the version
- std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
- TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ write_test_file(3);
- // Login
- std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0));
-
- int64_t modtime = 0;
-
+ // 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(std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
- BackupProtocolListDirectory::RootDirectory,
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryStoreFile(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
modtime,
modtime, /* use it for attr hash too */
- 0, /* diff from ID */
+ 0, /* diff from ID */
fnx,
- *upload)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
+ upload),
+ Err_StorageLimitExceeded);
- MemBlockStream attr(&modtime, sizeof(modtime));
+ // This currently causes a fatal error on the server, which
+ // 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(std::auto_ptr<BackupProtocolSuccess> dirCreate(protocol.QueryCreateDirectory(
- BackupProtocolListDirectory::RootDirectory,
- 9837429842987984LL, fnxd, attr)),
- ConnectionException, Conn_Protocol_UnexpectedReply);
-
+ TEST_COMMAND_RETURNS_ERROR(*apProtocol,
+ QueryCreateDirectory(
+ BACKUPSTORE_ROOT_DIRECTORY_ID,
+ FAKE_ATTR_MODIFICATION_TIME, fnxd, attr),
+ Err_StorageLimitExceeded);
- // Finish the connection
- protocol.QueryFinished();
+ // Finish the connection.
+ apProtocol->QueryFinished();
}
- // Kill it again
- TEST_THAT(KillServer(pid));
- ::sleep(1);
- TEST_THAT(!ServerIsAlive(pid));
-
- #ifdef WIN32
- TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
- #else
- TestRemoteProcessMemLeaks("bbstored.memleaks");
- #endif
-
- return 0;
+ TEARDOWN_TEST_BACKUPSTORE();
}
int multi_server()
@@ -2149,14 +2807,14 @@ 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.
- int pid = LaunchServer(BBSTORED " testfiles/bbstored_multi.conf",
+ int pid = LaunchServer(BBSTORED " testfiles/bbstored_multi.conf",
"testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
@@ -2172,43 +2830,33 @@ int multi_server()
printf("Terminating server...\n");
// Kill it
- TEST_THAT(KillServer(pid));
- ::sleep(1);
- TEST_THAT(!ServerIsAlive(pid));
-
- #ifdef WIN32
- TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
- #else
- TestRemoteProcessMemLeaks("bbstored.memleaks");
- #endif
+ TEST_THAT(StopServer());
}
-
return 0;
}
-void test_open_files_with_limited_win32_permissions()
+bool test_open_files_with_limited_win32_permissions()
{
#ifdef WIN32
// this had better work, or bbstored will die when combining diffs
- char* file = "foo";
+ const char* file = "foo";
- DWORD accessRights = FILE_READ_ATTRIBUTES |
+ DWORD accessRights = FILE_READ_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES |
FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/;
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
HANDLE h1 = CreateFileA(file, accessRights, shareMode,
- NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- assert(h1 != INVALID_HANDLE_VALUE);
+ NULL, OPEN_ALWAYS, // create file if it doesn't exist
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
TEST_THAT(h1 != INVALID_HANDLE_VALUE);
- accessRights = FILE_READ_ATTRIBUTES |
+ accessRights = FILE_READ_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_READ_EA;
HANDLE h2 = CreateFileA(file, accessRights, shareMode,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- assert(h2 != INVALID_HANDLE_VALUE);
TEST_THAT(h2 != INVALID_HANDLE_VALUE);
CloseHandle(h2);
@@ -2221,6 +2869,8 @@ void test_open_files_with_limited_win32_permissions()
CloseHandle(h2);
CloseHandle(h1);
#endif
+
+ return true;
}
void compare_backupstoreinfo_values_to_expected
@@ -2280,20 +2930,18 @@ void compare_backupstoreinfo_values_to_expected
TEST_EQUAL_LINE(expected_account_enabled, actual.IsAccountEnabled(),
test_phase << " AccountEnabled");
- TEST_EQUAL_LINE(extra_data.GetSize(), actual.GetExtraData().GetSize(),
+ TEST_EQUAL_LINE(extra_data.GetSize(), actual.GetExtraData().GetSize(),
test_phase << " extra data has wrong size");
TEST_EQUAL_LINE(0, memcmp(extra_data.GetBuffer(),
actual.GetExtraData().GetBuffer(), extra_data.GetSize()),
test_phase << " extra data has wrong contents");
}
-int test_read_old_backupstoreinfo_files()
+bool test_read_old_backupstoreinfo_files()
{
+ SETUP_TEST_BACKUPSTORE();
+
// Create an account for the test client
- TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
- " -c testfiles/bbstored.conf create 01234567 0 "
- "10000B 20000B") == 0);
- TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
std::auto_ptr<BackupStoreInfo> apInfo = BackupStoreInfo::Load(0x1234567,
"backup/01234567/", 0, /* ReadOnly */ false);
TEST_EQUAL_LINE(true, apInfo->IsAccountEnabled(),
@@ -2326,7 +2974,7 @@ int test_read_old_backupstoreinfo_files()
apArchive->Write((int64_t) 14);
rfw->Commit(/* ConvertToRaidNow */ true);
rfw.reset();
-
+
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0,
/* ReadOnly */ false);
compare_backupstoreinfo_values_to_expected("loaded from v1", info_v1,
@@ -2334,10 +2982,10 @@ int test_read_old_backupstoreinfo_files()
true /* enabled by default */);
apInfo->SetAccountName("bonk");
-
+
// Save the info again
apInfo->Save(/* allowOverwrite */ true);
-
+
// Check that it was saved in the new Archive format
std::auto_ptr<RaidFileRead> rfr(RaidFileRead::Open(0, info_filename, 0));
int32_t magic;
@@ -2356,7 +3004,7 @@ int test_read_old_backupstoreinfo_files()
/* ReadOnly */ false);
compare_backupstoreinfo_values_to_expected("loaded in v1, resaved in v2",
info_v1, *apInfo, "bonk", true);
-
+
// Check that the new AccountEnabled flag is saved properly
apInfo->SetAccountEnabled(false);
apInfo->Save(/* allowOverwrite */ true);
@@ -2375,7 +3023,7 @@ int test_read_old_backupstoreinfo_files()
// Now save the info in v2 format without the AccountEnabled flag
// (boxbackup 0.11 format) and check that the flag is set to true
// for backwards compatibility
-
+
rfw.reset(new RaidFileWrite(0, info_filename));
rfw->Open(/* allowOverwrite */ true);
magic = htonl(INFO_MAGIC_VALUE_2);
@@ -2392,7 +3040,7 @@ int test_read_old_backupstoreinfo_files()
apArchive->Write(apInfo->GetBlocksInDirectories());
apArchive->Write(apInfo->GetBlocksSoftLimit());
apArchive->Write(apInfo->GetBlocksHardLimit());
- apArchive->Write(apInfo->GetNumFiles());
+ apArchive->Write(apInfo->GetNumCurrentFiles());
apArchive->Write(apInfo->GetNumOldFiles());
apArchive->Write(apInfo->GetNumDeletedFiles());
apArchive->Write(apInfo->GetNumDirectories());
@@ -2401,7 +3049,7 @@ int test_read_old_backupstoreinfo_files()
apArchive->Write(apInfo->GetDeletedDirectories()[1]);
rfw->Commit(/* ConvertToRaidNow */ true);
rfw.reset();
-
+
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0,
/* ReadOnly */ false);
compare_backupstoreinfo_values_to_expected("saved in v2 without "
@@ -2411,7 +3059,7 @@ int test_read_old_backupstoreinfo_files()
// Rewrite using full length, so that the first 4 bytes of extra data
// doesn't get swallowed by "extra data".
apInfo->Save(/* allowOverwrite */ true);
-
+
// Append some extra data after the known account values, to simulate a
// new addition to the store format. Check that this extra data is loaded
// and resaved with the info file. We made the mistake of deleting it in
@@ -2431,7 +3079,7 @@ int test_read_old_backupstoreinfo_files()
rfw.reset();
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0,
/* ReadOnly */ false);
- TEST_EQUAL_LINE(extra_data.GetSize(), apInfo->GetExtraData().GetSize(),
+ TEST_EQUAL_LINE(extra_data.GetSize(), apInfo->GetExtraData().GetSize(),
"wrong amount of extra data loaded from info file");
TEST_EQUAL_LINE(0, memcmp(extra_data.GetBuffer(),
apInfo->GetExtraData().GetBuffer(), extra_data.GetSize()),
@@ -2441,16 +3089,16 @@ int test_read_old_backupstoreinfo_files()
apInfo = BackupStoreInfo::Load(0x1234567, "backup/01234567/", 0, true);
compare_backupstoreinfo_values_to_expected("saved in future format "
"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(),
@@ -2489,48 +3137,119 @@ int test_read_old_backupstoreinfo_files()
"BackupStoreInfo::CreateForRegeneration and reloaded", info_v1,
*apInfo, "spurtle", false /* AccountEnabled */, extra_data);
- // Delete the account to leave the store in the same state as before
+ // 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");
-
- return 0;
+ TEST_THAT(delete_account());
+
+ TEARDOWN_TEST_BACKUPSTORE();
+}
+
+// Test that attributes can be correctly read from and written to the standard
+// format, for compatibility with other servers and clients. See
+// http://mailman.uk.freebsd.org/pipermail../public/boxbackup/2010-November/005818.html and
+// http://lists.boxbackup.org/pipermail/boxbackup/2011-February/005978.html for
+// details of the problems with packed structs.
+bool test_read_write_attr_streamformat()
+{
+ SETUP_TEST_BACKUPSTORE();
+
+ // Construct a minimal valid directory with 1 entry in memory using Archive, and
+ // try to read it back.
+ CollectInBufferStream buf;
+ Archive darc(buf, IOStream::TimeOutInfinite);
+
+ // Write a dir_StreamFormat structure
+ darc.Write((int32_t)OBJECTMAGIC_DIR_MAGIC_VALUE); // mMagicValue
+ darc.Write((int32_t)1); // mNumEntries
+ darc.Write((int64_t)0x0123456789abcdef); // mObjectID
+ darc.Write((int64_t)0x0000000000000001); // mContainerID
+ darc.Write((uint64_t)0x23456789abcdef01); // mAttributesModTime
+ darc.Write((int32_t)BackupStoreDirectory::Option_DependencyInfoPresent);
+ // mOptionsPresent
+ // 36 bytes to here
+
+ // Write fake attributes to make it valid.
+ StreamableMemBlock attr;
+ attr.WriteToStream(buf);
+ // 40 bytes to here
+
+ // Write a single entry in an en_StreamFormat structure
+ darc.Write((uint64_t)0x3456789012345678); // mModificationTime
+ darc.Write((int64_t)0x0000000000000002); // mObjectID
+ darc.Write((int64_t)0x0000000000000003); // mSizeInBlocks
+ darc.Write((uint64_t)0x0000000000000004); // mAttributesHash
+ darc.WriteInt16((int16_t)0x3141); // mFlags
+ // 74 bytes to here
+
+ // Then a BackupStoreFilename
+ BackupStoreFilename fn;
+ fn.SetAsClearFilename("hello");
+ fn.WriteToStream(buf);
+ // 81 bytes to here
+
+ // Then a StreamableMemBlock for attributes
+ attr.WriteToStream(buf);
+ // 85 bytes to here
+
+ // Then an en_StreamFormatDepends for dependency info.
+ darc.Write((uint64_t)0x0000000000000005); // mDependsNewer
+ darc.Write((uint64_t)0x0000000000000006); // mDependsOlder
+ // 101 bytes to here
+
+ // Make sure none of the fields was expanded in transit by Archive.
+ TEST_EQUAL(101, buf.GetSize());
+
+ buf.SetForReading();
+ BackupStoreDirectory dir(buf);
+
+ TEST_EQUAL(1, dir.GetNumberOfEntries());
+ TEST_EQUAL(0x0123456789abcdef, dir.GetObjectID());
+ TEST_EQUAL(0x0000000000000001, dir.GetContainerID());
+ TEST_EQUAL(0x23456789abcdef01, dir.GetAttributesModTime());
+
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry* pen = i.Next();
+ TEST_THAT_OR(pen != NULL, FAIL);
+ TEST_EQUAL(0x3456789012345678, pen->GetModificationTime());
+ TEST_EQUAL(0x0000000000000002, pen->GetObjectID());
+ TEST_EQUAL(0x0000000000000003, pen->GetSizeInBlocks());
+ TEST_EQUAL(0x0000000000000004, pen->GetAttributesHash());
+ TEST_EQUAL(0x0000000000000005, pen->GetDependsNewer());
+ TEST_EQUAL(0x0000000000000006, pen->GetDependsOlder());
+ TEST_EQUAL(0x3141, pen->GetFlags());
+
+ CollectInBufferStream buf2;
+ dir.WriteToStream(buf2);
+ buf2.SetForReading();
+ buf.Seek(0, IOStream::SeekType_Absolute);
+ TEST_EQUAL(101, buf2.GetSize());
+ TEST_EQUAL(buf.GetSize(), buf2.GetSize());
+
+ // Test that the stream written out for the Directory is exactly the same as the
+ // one we hand-crafted earlier.
+ TEST_EQUAL(0, memcmp(buf.GetBuffer(), buf2.GetBuffer(), buf.GetSize()));
+
+ TEARDOWN_TEST_BACKUPSTORE();
}
int test(int argc, const char *argv[])
{
- test_open_files_with_limited_win32_permissions();
+ TEST_THAT(test_open_files_with_limited_win32_permissions());
// Initialise the raid file controller
RaidFileController &rcontroller = RaidFileController::GetController();
rcontroller.Initialise("testfiles/raidfile.conf");
-
- int ret = test_read_old_backupstoreinfo_files();
- if (ret != 0)
- {
- return ret;
- }
-
+
+ TEST_THAT(test_read_old_backupstoreinfo_files());
+
// SSL library
SSLLib::Initialise();
-
- // Give a test key for the filenames
-// BackupStoreFilenameClear::SetBlowfishKey(FilenameEncodingKey, sizeof(FilenameEncodingKey));
- // And set the encoding to blowfish
-// BackupStoreFilenameClear::SetEncodingMethod(BackupStoreFilename::Encoding_Blowfish);
-
- // And for directory attributes -- need to set it, as used in file encoding
-// BackupClientFileAttributes::SetBlowfishKey(AttributesEncodingKey, sizeof(AttributesEncodingKey));
-
- // And finally for file encoding
-// BackupStoreFile::SetBlowfishKeys(FileEncodingKey, sizeof(FileEncodingKey), FileBlockEntryEncodingKey, sizeof(FileBlockEntryEncodingKey));
// Use the setup crypto command to set up all these keys, so that the bbackupquery command can be used
// for seeing what's going on.
- BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
-
- // encode in some filenames -- can't do static initialisation
+ BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
+
+ // encode in some filenames -- can't do static initialisation
// because the key won't be set up when these are initialised
{
MEMLEAKFINDER_NO_LEAKS
@@ -2544,36 +3263,43 @@ int test(int argc, const char *argv[])
uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]);
}
}
-
+
// Trace errors out
SET_DEBUG_SSLLIB_TRACE_ERRORS
- if(argc == 2 && strcmp(argv[1], "server") == 0)
- {
- return multi_server();
- }
- if(argc == 3 && strcmp(argv[1], "client") == 0)
{
- return test_server(argv[2]);
+ R250 r(3465657);
+ for(int l = 0; l < ATTR1_SIZE; ++l) {attr1[l] = r.next();}
+ for(int l = 0; l < ATTR2_SIZE; ++l) {attr2[l] = r.next();}
+ for(int l = 0; l < ATTR3_SIZE; ++l) {attr3[l] = r.next();}
}
-// large file test
-/* {
- int64_t modtime = 0;
- std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("/Users/ben/temp/large.tar",
- BackupProtocolListDirectory::RootDirectory, uploads[0].name, &modtime));
- TEST_THAT(modtime != 0);
- FileStream write("testfiles/large.enc", O_WRONLY | O_CREAT);
- upload->CopyStreamTo(write);
- }
-printf("SKIPPING TESTS ------------------------------------------------------\n");
-return 0;*/
- int r = 0;
- r = test1(argc, argv);
- if(r != 0) return r;
- r = test2(argc, argv);
- if(r != 0) return r;
- r = test3(argc, argv);
- if(r != 0) return r;
- return 0;
+
+ TEST_THAT(test_filename_encoding());
+ TEST_THAT(test_temporary_refcount_db_is_independent());
+ TEST_THAT(test_bbstoreaccounts_create());
+ 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());
+
+ context.Initialise(false /* client */,
+ "testfiles/clientCerts.pem",
+ "testfiles/clientPrivKey.pem",
+ "testfiles/clientTrustedCAs.pem");
+
+ TEST_THAT(test_login_without_account());
+ TEST_THAT(test_login_with_disabled_account());
+ TEST_THAT(test_login_with_no_refcount_db());
+ TEST_THAT(test_server_housekeeping());
+ TEST_THAT(test_server_commands());
+ TEST_THAT(test_account_limits_respected());
+ TEST_THAT(test_multiple_uploads());
+ TEST_THAT(test_housekeeping_deletes_files());
+ TEST_THAT(test_read_write_attr_streamformat());
+
+ return finish_test_suite();
}