// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
//
// --------------------------------------------------------------------------
//
// File
// Name: testbackupstore.cpp
// Purpose: Test backup store server
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
#include "Box.h"
#include <stdlib.h>
#include <string.h>
#include "Test.h"
#include "autogen_BackupProtocolClient.h"
#include "SSLLib.h"
#include "TLSContext.h"
#include "SocketStreamTLS.h"
#include "BoxPortsAndFiles.h"
#include "BackupStoreConstants.h"
#include "Socket.h"
#include "BackupStoreFilenameClear.h"
#include "CollectInBufferStream.h"
#include "BackupStoreDirectory.h"
#include "BackupStoreFile.h"
#include "FileStream.h"
#include "RaidFileController.h"
#include "RaidFileWrite.h"
#include "BackupStoreInfo.h"
#include "BackupStoreException.h"
#include "RaidFileException.h"
#include "MemBlockStream.h"
#include "BackupClientFileAttributes.h"
#include "BackupClientCryptoKeys.h"
#include "MemLeakFindOn.h"
#define ENCFILE_SIZE 2765
typedef struct
{
BackupStoreFilenameClear fn;
box_time_t mod;
int64_t id;
int64_t size;
int16_t flags;
box_time_t attrmod;
} dirtest;
static dirtest ens[] =
{
{BackupStoreFilenameClear(), 324324, 3432, 324, BackupStoreDirectory::Entry::Flags_File, 458763243422LL},
{BackupStoreFilenameClear(), 3432, 32443245645LL, 78, BackupStoreDirectory::Entry::Flags_Dir, 3248972347LL},
{BackupStoreFilenameClear(), 544435, 234234, 23324, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_Deleted, 2348974782LL},
{BackupStoreFilenameClear(), 234, 235436, 6523, BackupStoreDirectory::Entry::Flags_File, 32458923175634LL},
{BackupStoreFilenameClear(), 0x3242343532144LL, 8978979789LL, 21345, BackupStoreDirectory::Entry::Flags_File, 329483243432LL},
{BackupStoreFilenameClear(), 324265765734LL, 12312312321LL, 324987324329874LL, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_Deleted, 32489747234LL},
{BackupStoreFilenameClear(), 3452134, 7868578768LL, 324243, BackupStoreDirectory::Entry::Flags_Dir, 34786457432LL},
{BackupStoreFilenameClear(), 43543543, 324234, 21432, BackupStoreDirectory::Entry::Flags_Dir | BackupStoreDirectory::Entry::Flags_Deleted, 3489723478327LL},
{BackupStoreFilenameClear(), 325654765874324LL, 4353543, 1, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 32489734789237LL},
{BackupStoreFilenameClear(), 32144325, 436547657, 9, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 234897347234LL}
};
static const char *ens_filenames[] = {"obj1ertewt", "obj2", "obj3", "obj4dfedfg43", "obj5", "obj6dfgs", "obj7", "obj8xcvbcx", "obj9", "obj10fgjhfg"};
#define DIR_NUM 10
#define DIR_DIRS 3
#define DIR_FILES 7
#define DIR_OLD 2
#define DIR_DELETED 3
typedef struct
{
char *fnextra;
BackupStoreFilenameClear name;
int seed;
int size;
box_time_t mod_time;
int64_t allocated_objid;
bool should_be_old_version;
bool delete_file;
} uploadtest;
#define TEST_FILE_FOR_PATCHING "testfiles/test2"
// a few bytes will be inserted at this point:
#define TEST_FILE_FOR_PATCHING_PATCH_AT ((64*1024)-128)
#define TEST_FILE_FOR_PATCHING_SIZE ((128*1024)+2564)
#define UPLOAD_PATCH_EN 2
uploadtest uploads[] =
{
{"0", BackupStoreFilenameClear(), 324, 455, 0, 0, false, false},
{"1", BackupStoreFilenameClear(), 3232432, 2674, 0, 0, true, false}, // old ver
{"2", BackupStoreFilenameClear(), 234, TEST_FILE_FOR_PATCHING_SIZE, 0, 0, false, false},
{"3", BackupStoreFilenameClear(), 324324, 6763, 0, 0, false, false},
{"4", BackupStoreFilenameClear(), 23456, 124, 0, 0, true, false}, // old ver
{"5", BackupStoreFilenameClear(), 675745, 1, 0, 0, false, false}, // will upload new attrs for this one!
{"6", BackupStoreFilenameClear(), 345213, 0, 0, 0, false, false},
{"7", BackupStoreFilenameClear(), 12313, 3246, 0, 0, true, true}, // old ver, will get deleted
{"8", BackupStoreFilenameClear(), 457, 3434, 0, 0, false, false}, // overwrites
{"9", BackupStoreFilenameClear(), 12315, 446, 0, 0, false, false},
{"a", BackupStoreFilenameClear(), 3476, 2466, 0, 0, false, false},
{"b", BackupStoreFilenameClear(), 124334, 4562, 0, 0, false, false},
{"c", BackupStoreFilenameClear(), 45778, 234, 0, 0, false, false}, // overwrites
{"d", BackupStoreFilenameClear(), 2423425, 435, 0, 0, false, true} // overwrites, will be deleted
};
static const char *uploads_filenames[] = {"49587fds", "cvhjhj324", "sdfcscs324", "dsfdsvsdc3214", "XXsfdsdf2342", "dsfdsc232",
"sfdsdce2345", "YYstfbdtrdf76", "cvhjhj324", "fbfd098.ycy", "dfs98732hj", "svd987kjsad", "XXsfdsdf2342", "YYstfbdtrdf76"};
#define UPLOAD_NUM 14
#define UPLOAD_LATEST_FILES 12
// file we'll upload some new attributes for
#define UPLOAD_ATTRS_EN 5
#define UPLOAD_DELETE_EN 13
// file which will be moved (as well as it's old version)
#define UPLOAD_FILE_TO_MOVE 8
// Nice random data for testing written files
class R250 {
public:
// 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....
R250(int seed) : posn1(0), posn2(103)
{
// populate the state and incr tables
srand(seed);
for (int i = 0; i != stateLen; ++i) {
state[i] = ((rand() >> 2) << 19) ^ ((rand() >> 2) << 11) ^ (rand() >> 2);
incrTable[i] = i == stateLen - 1 ? 0 : i + 1;
}
// stir up the numbers to ensure they're random
for (int j = 0; j != stateLen * 4; ++j)
(void) next();
}
// Returns the next random number. Xor together two elements separated
// by 103 mod 250, replacing the first element with the result. Then
// increment the two indices mod 250.
inline int next()
{
int ret = (state[posn1] ^= state[posn2]); // xor and replace element
posn1 = incrTable[posn1]; // increment indices using lookup table
posn2 = incrTable[posn2];
return ret;
}
private:
enum { stateLen = 250 }; // length of the state table
int state[stateLen]; // holds the random number state
int incrTable[stateLen]; // lookup table: maps i to (i+1) % stateLen
int posn1, posn2; // indices into the state table
};
int SkipEntries(int e, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet)
{
if(e >= DIR_NUM) return e;
bool skip = false;
do
{
skip = false;
if(FlagsMustBeSet != BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING)
{
if((ens[e].flags & FlagsMustBeSet) != FlagsMustBeSet)
{
skip = true;
}
}
if((ens[e].flags & FlagsNotToBeSet) != 0)
{
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)
{
TEST_THAT(e < DIR_NUM);
// Skip to entry in the ens array which matches
e = SkipEntries(e, FlagsMustBeSet, FlagsNotToBeSet);
// Does it match?
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;
}
// Got them all?
TEST_THAT(en == 0);
TEST_THAT(DIR_NUM == SkipEntries(e, FlagsMustBeSet, FlagsNotToBeSet));
}
int test1(int argc, const char *argv[])
{
// Initialise the raid file controller
RaidFileController &rcontroller = RaidFileController::GetController();
rcontroller.Initialise("testfiles/raidfile.conf");
// test some basics -- encoding and decoding filenames
{
// Make some filenames in various ways
BackupStoreFilenameClear fn1;
fn1.SetClearFilename(std::string("filenameXYZ"));
BackupStoreFilenameClear fn2(std::string("filenameXYZ"));
BackupStoreFilenameClear fn3(fn1);
TEST_THAT(fn1 == fn2);
TEST_THAT(fn1 == fn3);
// Check that it's been encrypted
TEST_THAT(fn2.find("name") == fn2.npos);
// Bung it in a stream, get it out in a Clear filename
{
CollectInBufferStream stream;
fn1.WriteToStream(stream);
stream.SetForReading();
BackupStoreFilenameClear fn4;
fn4.ReadFromStream(stream, IOStream::TimeOutInfinite);
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 ");
CollectInBufferStream stream;
fn1.WriteToStream(stream);
fno.WriteToStream(stream);
stream.SetForReading();
BackupStoreFilename fn5;
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5 == fn1);
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5 == fno);
}
// Same again with clear strings
{
BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
CollectInBufferStream stream;
fn1.WriteToStream(stream);
fno.WriteToStream(stream);
stream.SetForReading();
BackupStoreFilenameClear fn5;
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5.GetClearFilename() == "filenameXYZ");
fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn5.GetClearFilename() == "pinglet dksfnsf jksjdf ");
}
// Test a very big filename
{
const char *fnr = "01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789";
BackupStoreFilenameClear fnLong(fnr);
CollectInBufferStream stream;
fnLong.WriteToStream(stream);
stream.SetForReading();
BackupStoreFilenameClear fn9;
fn9.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(fn9.GetClearFilename() == fnr);
TEST_THAT(fn9 == fnLong);
}
// Test a filename which went wrong once
{
BackupStoreFilenameClear dodgy("content-negotiation.html");
}
}
return 0;
}
int test2(int argc, const char *argv[])
{
{
// Now play with directories
// Fill in...
BackupStoreDirectory dir1(12, 98);
for(int e = 0; e < DIR_NUM; ++e)
{
dir1.AddEntry(ens[e].fn, ens[e].mod, ens[e].id, ens[e].size, ens[e].flags, ens[e].attrmod);
}
// 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);
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);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_FILES);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_File, BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
}
{
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, BackupStoreDirectory::Entry::Flags_File);
stream.SetForReading();
BackupStoreDirectory dir2;
dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_DIRS);
CheckEntries(dir2, BackupStoreDirectory::Entry::Flags_Dir, BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
}
{
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_File, BackupStoreDirectory::Entry::Flags_OldVersion);
stream.SetForReading();
BackupStoreDirectory dir2;
dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
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);
// Verify
TEST_THAT(dir1.GetNumberOfEntries() == DIR_NUM - 1);
CollectInBufferStream stream;
dir1.WriteToStream(stream, BackupStoreDirectory::Entry::Flags_File);
stream.SetForReading();
BackupStoreDirectory dir2;
dir2.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(dir2.GetNumberOfEntries() == DIR_FILES - 1);
}
// Check attributes
{
int attrI[4] = {1, 2, 3, 4};
StreamableMemBlock attr(attrI, sizeof(attrI));
BackupStoreDirectory d1(16, 546);
d1.SetAttributes(attr, 56234987324232LL);
TEST_THAT(d1.GetAttributes() == attr);
TEST_THAT(d1.GetAttributesModTime() == 56234987324232LL);
CollectInBufferStream stream;
d1.WriteToStream(stream);
stream.SetForReading();
BackupStoreDirectory d2;
d2.ReadFromStream(stream, IOStream::TimeOutInfinite);
TEST_THAT(d2.GetAttributes() == attr);
TEST_THAT(d2.GetAttributesModTime() == 56234987324232LL);
}
}
return 0;
}
void write_test_file(int t)
{
std::string filename("testfiles/test");
filename += uploads[t].fnextra;
printf("%s\n", filename.c_str());
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);
// 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);
unlink("testfiles/test_download");
}
void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
{
printf("Test for del: %llx\n", DirID);
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
DirID,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
int files = 0;
int dirs = 0;
while((en = i.Next()) != 0)
{
if(en->GetFlags() & BackupProtocolClientListDirectory::Flags_Dir)
{
dirs++;
// Recurse
test_everything_deleted(protocol, en->GetObjectID());
}
else
{
files++;
}
// Check it's deleted
TEST_THAT(en->GetFlags() & BackupProtocolClientListDirectory::Flags_Deleted);
}
// Check there were the right number of files and directories
TEST_THAT(files == 3);
TEST_THAT(dirs == 0 || dirs == 2);
}
int64_t create_test_data_subdirs(BackupProtocolClient &protocol, int64_t indir, const char *name, int depth)
{
// Create a directory
int64_t subdirid = 0;
BackupStoreFilenameClear dirname(name);
{
// Create with dummy attributes
int attrS = 0;
MemBlockStream attr(&attrS, sizeof(attrS));
std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
indir,
9837429842987984LL, dirname, attr));
subdirid = dirCreate->GetObjectID();
}
printf("Create subdirs, depth = %d, dirid = %llx\n", depth, subdirid);
// 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);
create_test_data_subdirs(protocol, subdirid, "dir_Two", depth - 1);
}
// Stick some files in it
{
BackupStoreFilenameClear name("file_One");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/file1", subdirid, name));
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
subdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
name,
*upload));
}
{
BackupStoreFilenameClear name("file_Two");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/file1", subdirid, name));
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
subdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
name,
*upload));
}
{
BackupStoreFilenameClear name("file_Three");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/file1", subdirid, name));
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
subdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
name,
*upload));
}
return subdirid;
}
void check_dir_after_uploads(BackupProtocolClient &protocol, const StreamableMemBlock &Attributes)
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
TEST_THAT(dirreply->GetObjectID() == BackupProtocolClientListDirectory::RootDirectory);
// 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 */);
TEST_THAT(!dir.HasAttributes());
// Check them!
BackupStoreDirectory::Iterator i(dir);
// Discard first
BackupStoreDirectory::Entry *en = i.Next();
TEST_THAT(en != 0);
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);
int correct_flags = BackupProtocolClientListDirectory::Flags_File;
if(uploads[t].should_be_old_version) correct_flags |= BackupProtocolClientListDirectory::Flags_OldVersion;
if(uploads[t].delete_file) correct_flags |= BackupProtocolClientListDirectory::Flags_Deleted;
TEST_THAT(en->GetFlags() == correct_flags);
if(t == UPLOAD_ATTRS_EN)
{
TEST_THAT(en->HasAttributes());
TEST_THAT(en->GetAttributesHash() == 32498749832475LL);
TEST_THAT(en->GetAttributes() == Attributes);
}
else
{
// No attributes on this one
TEST_THAT(!en->HasAttributes());
}
}
en = i.Next();
TEST_THAT(en == 0);
}
typedef struct
{
int objectsNotDel;
int deleted;
int old;
} recursive_count_objects_results;
void recursive_count_objects_r(BackupProtocolClient &protocol, int64_t id, recursive_count_objects_results &results)
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
id,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
// 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);
}
}
}
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");
// Get a connection
SocketStreamTLS connReadOnly;
connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
BackupProtocolClient protocolReadOnly(connReadOnly);
{
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
}
// Count objects
recursive_count_objects_r(protocolReadOnly, id, results);
// Close it
protocolReadOnly.QueryFinished();
}
bool check_block_index(const char *encoded_file, IOStream &rBlockIndex)
{
// Open file, and move to the right position
FileStream enc(encoded_file);
BackupStoreFile::MoveStreamPositionToBlockIndex(enc);
bool same = true;
// Now compare the two...
while(enc.StreamDataLeft())
{
char buffer1[2048];
char buffer2[2048];
int s = enc.Read(buffer1, sizeof(buffer1));
if(rBlockIndex.Read(buffer2, s) != s)
{
same = false;
break;
}
if(::memcmp(buffer1, buffer2, s) != 0)
{
same = false;
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));
}
}
return same;
}
bool check_files_same(const char *f1, const char *f2)
{
// Open file, and move to the right position
FileStream f1s(f1);
FileStream f2s(f2);
bool same = true;
// Now compare the two...
while(f1s.StreamDataLeft())
{
char buffer1[2048];
char buffer2[2048];
int s = f1s.Read(buffer1, sizeof(buffer1));
if(f2s.Read(buffer2, s) != s)
{
same = false;
break;
}
if(::memcmp(buffer1, buffer2, s) != 0)
{
same = false;
break;
}
}
if(f2s.StreamDataLeft())
{
same = false;
}
return same;
}
void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protocolReadOnly)
{
int encfile[ENCFILE_SIZE];
{
for(int l = 0; l < ENCFILE_SIZE; ++l)
{
encfile[l] = l * 173;
}
// Write this to a file
{
FileStream f("testfiles/file1", O_WRONLY | O_CREAT | O_EXCL);
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<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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);
}
// Read the dir from the readonly connection (make sure it gets in the cache)
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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);
}
// Store a file -- first make the encoded file
BackupStoreFilenameClear store1name("testfiles/file1");
{
FileStream out("testfiles/file1_upload1", O_WRONLY | O_CREAT | O_EXCL);
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/file1", BackupProtocolClientListDirectory::RootDirectory, store1name));
encoded->CopyStreamTo(out);
}
// printf("SKIPPING\n");
// goto skip; {
// Then send it
int64_t store1objid = 0;
{
FileStream upload("testfiles/file1_upload1");
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
BackupProtocolClientListDirectory::RootDirectory,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
store1name,
upload));
store1objid = stored->GetObjectID();
TEST_THAT(store1objid == 2);
}
// And retrieve it
{
// Retrieve as object
std::auto_ptr<BackupProtocolClientSuccess> getfile(protocol.QueryGetObject(store1objid));
TEST_THAT(getfile->GetObjectID() == store1objid);
// BLOCK
{
// Get stream
std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
// Need to put it in another stream, because it's not in stream order
CollectInBufferStream f;
filestream->CopyStreamTo(f);
f.SetForReading();
// Get and decode
BackupStoreFile::DecodeFile(f, "testfiles/file1_upload_retrieved", IOStream::TimeOutInfinite);
}
// Retrieve as file
std::auto_ptr<BackupProtocolClientSuccess> getobj(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, store1objid));
TEST_THAT(getobj->GetObjectID() == store1objid);
// BLOCK
{
// Get stream
std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
// Get and decode
BackupStoreFile::DecodeFile(*filestream, "testfiles/file1_upload_retrieved_str", IOStream::TimeOutInfinite);
}
// Read in rebuilt original, and compare contents
{
FileStream in("testfiles/file1_upload_retrieved");
int encfile_i[ENCFILE_SIZE];
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<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByID(store1objid));
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));
}
// and again, by name
{
std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(BackupProtocolClientListDirectory::RootDirectory, 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<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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() == 1);
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = i.Next();
TEST_THAT(en != 0);
TEST_THAT(i.Next() == 0);
if(en != 0)
{
TEST_THAT(en->GetName() == store1name);
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_THAT(en->GetFlags() == BackupStoreDirectory::Entry::Flags_File);
}
}
// Try using GetFile on a directory
{
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, BackupProtocolClientListDirectory::RootDirectory)),
ConnectionException, Conn_Protocol_UnexpectedReply);
}
}
int test_server(const char *hostname)
{
// Context
TLSContext context;
context.Initialise(false /* client */,
"testfiles/clientCerts.pem",
"testfiles/clientPrivKey.pem",
"testfiles/clientTrustedCAs.pem");
// 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];
{
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();}
}
// BLOCK
{
// Open a connection to the server
SocketStreamTLS conn;
conn.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
// Make a protocol
BackupProtocolClient protocol(conn);
// Get it logging
FILE *protocolLog = ::fopen("testfiles/protocol.log", "w");
TEST_THAT(protocolLog != 0);
protocol.SetLogToFile(protocolLog);
// Check the version
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0));
// Check marker is 0
TEST_THAT(loginConf->GetClientStoreMarker() == 0);
// Check that we can't open a new connection which requests write permissions
{
SocketStreamTLS conn;
conn.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
BackupProtocolClient protocol(conn);
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
ConnectionException, Conn_Protocol_UnexpectedReply);
protocol.QueryFinished();
}
// Set the client store marker
protocol.QuerySetClientStoreMarker(0x8732523ab23aLL);
// Open a new connection which is read only
SocketStreamTLS connReadOnly;
connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
BackupProtocolClient protocolReadOnly(connReadOnly);
// Get it logging
FILE *protocolReadOnlyLog = ::fopen("testfiles/protocolReadOnly.log", "w");
TEST_THAT(protocolReadOnlyLog != 0);
protocolReadOnly.SetLogToFile(protocolReadOnlyLog);
{
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
// Check client store marker
TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL);
}
test_server_1(protocol, protocolReadOnly);
// Create and upload some test files
int64_t maxID = 0;
for(int t = 0; t < UPLOAD_NUM; ++t)
{
write_test_file(t);
std::string filename("testfiles/test");
filename += uploads[t].fnextra;
int64_t modtime = 0;
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), BackupProtocolClientListDirectory::RootDirectory, uploads[t].name, &modtime));
TEST_THAT(modtime != 0);
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
BackupProtocolClientListDirectory::RootDirectory,
modtime,
modtime, /* use it for attr hash too */
0, /* diff from ID */
uploads[t].name,
*upload));
uploads[t].allocated_objid = stored->GetObjectID();
uploads[t].mod_time = modtime;
if(maxID < stored->GetObjectID()) maxID = stored->GetObjectID();
}
// Add some attributes onto one of them
{
MemBlockStream attrnew(attr3, sizeof(attr3));
std::auto_ptr<BackupProtocolClientSuccess> set(protocol.QuerySetReplacementFileAttributes(
BackupProtocolClientListDirectory::RootDirectory,
32498749832475LL,
uploads[UPLOAD_ATTRS_EN].name,
attrnew));
TEST_THAT(set->GetObjectID() == uploads[UPLOAD_ATTRS_EN].allocated_objid);
}
// Delete one of them (will implicitly delete an old version)
{
std::auto_ptr<BackupProtocolClientSuccess> del(protocol.QueryDeleteFile(
BackupProtocolClientListDirectory::RootDirectory,
uploads[UPLOAD_DELETE_EN].name));
TEST_THAT(del->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
}
// Check that the block index can be obtained by name even though it's been deleted
{
// Fetch the raw object
{
FileStream out("testfiles/downloaddelobj", O_WRONLY | O_CREAT);
std::auto_ptr<BackupProtocolClientSuccess> getobj(protocol.QueryGetObject(uploads[UPLOAD_DELETE_EN].allocated_objid));
std::auto_ptr<IOStream> objstream(protocol.ReceiveStream());
objstream->CopyStreamTo(out);
}
// query index and test
std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(
BackupProtocolClientListDirectory::RootDirectory, uploads[UPLOAD_DELETE_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
TEST_THAT(check_block_index("testfiles/downloaddelobj", *blockIndexStream));
}
// Download them all... (even deleted files)
for(int t = 0; t < UPLOAD_NUM; ++t)
{
printf("%d\n", t);
std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, uploads[t].allocated_objid));
TEST_THAT(getFile->GetObjectID() == uploads[t].allocated_objid);
std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
test_test_file(t, *filestream);
}
{
StreamableMemBlock attrtest(attr3, sizeof(attr3));
// Use the read only connection to verify that the directory is as we expect
check_dir_after_uploads(protocolReadOnly, attrtest);
// And on the read/write one
check_dir_after_uploads(protocol, attrtest);
}
// Check diffing and rsync like stuff...
// Build a modified file
{
// Basically just insert a bit in the middle
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);
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";
out.Write(insert, sizeof(insert));
TEST_THAT(in.Read(buf, TEST_FILE_FOR_PATCHING_SIZE - TEST_FILE_FOR_PATCHING_PATCH_AT) == TEST_FILE_FOR_PATCHING_SIZE - TEST_FILE_FOR_PATCHING_PATCH_AT);
out.Write(buf, TEST_FILE_FOR_PATCHING_SIZE - TEST_FILE_FOR_PATCHING_PATCH_AT);
::free(buf);
}
{
// Fetch the block index for this one
std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(
BackupProtocolClientListDirectory::RootDirectory, uploads[UPLOAD_PATCH_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_PATCH_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
// Do the patching
bool isCompletelyDifferent = false;
int64_t modtime;
std::auto_ptr<IOStream> patchstream(
BackupStoreFile::EncodeFileDiff(
TEST_FILE_FOR_PATCHING ".mod",
BackupProtocolClientListDirectory::RootDirectory,
uploads[UPLOAD_PATCH_EN].name,
uploads[UPLOAD_PATCH_EN].allocated_objid,
*blockIndexStream,
IOStream::TimeOutInfinite,
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);
patchstream->CopyStreamTo(patch);
}
// Make sure the stream is a plausible size for a patch containing only one new block
TEST_THAT(TestGetFileSize(TEST_FILE_FOR_PATCHING ".patch") < (8*1024));
// Upload it
int64_t patchedID = 0;
{
FileStream uploadpatch(TEST_FILE_FOR_PATCHING ".patch");
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
BackupProtocolClientListDirectory::RootDirectory,
modtime,
modtime, /* use it for attr hash too */
uploads[UPLOAD_PATCH_EN].allocated_objid, /* diff from ID */
uploads[UPLOAD_PATCH_EN].name,
uploadpatch));
TEST_THAT(stored->GetObjectID() > 0);
if(maxID < stored->GetObjectID()) maxID = stored->GetObjectID();
patchedID = stored->GetObjectID();
}
// Then download it to check it's OK
std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, patchedID));
TEST_THAT(getFile->GetObjectID() == patchedID);
std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
BackupStoreFile::DecodeFile(*filestream, TEST_FILE_FOR_PATCHING ".downloaded", IOStream::TimeOutInfinite);
// Check it's the same
TEST_THAT(check_files_same(TEST_FILE_FOR_PATCHING ".downloaded", TEST_FILE_FOR_PATCHING ".mod"));
}
// Create a directory
int64_t subdirid = 0;
BackupStoreFilenameClear dirname("lovely_directory");
{
// Attributes
MemBlockStream attr(attr1, sizeof(attr1));
std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
BackupProtocolClientListDirectory::RootDirectory,
9837429842987984LL, dirname, attr));
subdirid = dirCreate->GetObjectID();
TEST_THAT(subdirid == maxID + 1);
}
// 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<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
subdirid,
modtime,
modtime, /* use for attr hash too */
0, /* diff from ID */
uploads[0].name,
*upload));
subdirfileid = stored->GetObjectID();
}
// Check the directories on the read only connection
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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 */);
// Check the last one...
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
BackupStoreDirectory::Entry *t = 0;
while((t = i.Next()) != 0)
{
if(en != 0)
{
// here for all but last object
TEST_THAT(en->GetObjectID() != subdirid);
TEST_THAT(en->GetName() != dirname);
}
en = t;
}
// Does it look right?
TEST_THAT(en->GetName() == dirname);
TEST_THAT(en->GetFlags() == BackupProtocolClientListDirectory::Flags_Dir);
TEST_THAT(en->GetObjectID() == subdirid);
TEST_THAT(en->GetModificationTime() == 0); // dirs don't have modification times.
}
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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);
TEST_THAT(dir.GetNumberOfEntries() == 1);
// Check the last one...
BackupStoreDirectory::Iterator i(dir);
// Discard first
BackupStoreDirectory::Entry *en = i.Next();
TEST_THAT(en != 0);
// Does it look right?
TEST_THAT(en->GetName() == uploads[0].name);
TEST_THAT(en->GetFlags() == BackupProtocolClientListDirectory::Flags_File);
TEST_THAT(en->GetObjectID() == subdirfileid);
TEST_THAT(en->GetModificationTime() != 0);
// Attributes
TEST_THAT(dir.HasAttributes());
TEST_THAT(dir.GetAttributesModTime() == 9837429842987984LL);
StreamableMemBlock attr(attr1, sizeof(attr1));
TEST_THAT(dir.GetAttributes() == attr);
}
// Check that we don't get attributes if we don't ask for them
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
TEST_THAT(!dir.HasAttributes());
}
// Change attributes on the directory
{
MemBlockStream attrnew(attr2, sizeof(attr2));
std::auto_ptr<BackupProtocolClientSuccess> changereply(protocol.QueryChangeDirAttributes(
subdirid,
329483209443598LL,
attrnew));
TEST_THAT(changereply->GetObjectID() == subdirid);
}
// Check the new attributes
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
0, // no flags
BackupProtocolClientListDirectory::Flags_EXCLUDE_EVERYTHING, true /* get attributes */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
TEST_THAT(dir.GetNumberOfEntries() == 0);
// Attributes
TEST_THAT(dir.HasAttributes());
TEST_THAT(dir.GetAttributesModTime() == 329483209443598LL);
StreamableMemBlock attrtest(attr2, sizeof(attr2));
TEST_THAT(dir.GetAttributes() == attrtest);
}
// Test moving a file
{
BackupStoreFilenameClear newName("moved-files");
std::auto_ptr<BackupProtocolClientSuccess> rep(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolClientListDirectory::RootDirectory,
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName));
TEST_THAT(rep->GetObjectID() == uploads[UPLOAD_FILE_TO_MOVE].allocated_objid);
}
// Try some dodgy renames
{
BackupStoreFilenameClear newName("moved-files");
TEST_CHECK_THROWS(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolClientListDirectory::RootDirectory,
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName),
ConnectionException, Conn_Protocol_UnexpectedReply);
TEST_CHECK_THROWS(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
subdirid,
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName),
ConnectionException, Conn_Protocol_UnexpectedReply);
}
// Rename within a directory
{
BackupStoreFilenameClear newName("moved-files-x");
protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
subdirid,
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName);
}
// Check it's all gone from the root directory...
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::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);
}
}
// Check the old and new versions are in the other directory
{
BackupStoreFilenameClear lookFor("moved-files-x");
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
// Check entries
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
bool foundCurrent = false;
bool foundOld = false;
while((en = i.Next()) != 0)
{
if(en->GetName() == lookFor)
{
if(en->GetFlags() == (BackupStoreDirectory::Entry::Flags_File)) foundCurrent = true;
if(en->GetFlags() == (BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion)) foundOld = true;
}
}
TEST_THAT(foundCurrent);
TEST_THAT(foundOld);
}
// make a little bit more of a thing to look at
int64_t subsubdirid = 0;
int64_t subsubfileid = 0;
{
BackupStoreFilenameClear nd("sub2");
// Attributes
MemBlockStream attr(attr1, sizeof(attr1));
std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
subdirid,
9837429842987984LL, nd, attr));
subsubdirid = dirCreate->GetObjectID();
FileStream upload("testfiles/file1_upload1");
BackupStoreFilenameClear nf("file2");
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
subsubdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
nf,
upload));
subsubfileid = stored->GetObjectID();
}
// Query names -- test that invalid stuff returns not found OK
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(3248972347823478927LL, subsubdirid));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(subsubfileid, 2342378424LL));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(38947234789LL, 2342378424LL));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, 2234342378424LL));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
// Query names... first, get info for the file
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(subsubfileid, subsubdirid));
std::auto_ptr<IOStream> namestream(protocol.ReceiveStream());
TEST_THAT(nameRep->GetNumNameElements() == 3);
TEST_THAT(nameRep->GetFlags() == BackupProtocolClientListDirectory::Flags_File);
TEST_THAT(nameRep->GetModificationTime() == 0x123456789abcdefLL);
TEST_THAT(nameRep->GetAttributesHash() == 0x7362383249872dfLL);
static const char *testnames[] = {"file2","sub2","lovely_directory"};
for(int l = 0; l < nameRep->GetNumNameElements(); ++l)
{
BackupStoreFilenameClear fn;
fn.ReadFromStream(*namestream, 10000);
TEST_THAT(fn.GetClearFilename() == testnames[l]);
}
}
// Query names... secondly, for the directory
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, subsubdirid));
std::auto_ptr<IOStream> namestream(protocol.ReceiveStream());
TEST_THAT(nameRep->GetNumNameElements() == 2);
TEST_THAT(nameRep->GetFlags() == BackupProtocolClientListDirectory::Flags_Dir);
static const char *testnames[] = {"sub2","lovely_directory"};
for(int l = 0; l < nameRep->GetNumNameElements(); ++l)
{
BackupStoreFilenameClear fn;
fn.ReadFromStream(*namestream, 10000);
TEST_THAT(fn.GetClearFilename() == testnames[l]);
}
}
//} skip:
// Create some nice recursive directories
int64_t dirtodelete = create_test_data_subdirs(protocol,
BackupProtocolClientListDirectory::RootDirectory, "test_delete", 6 /* depth */);
// And delete them
{
std::auto_ptr<BackupProtocolClientSuccess> dirdel(protocol.QueryDeleteDirectory(
dirtodelete));
TEST_THAT(dirdel->GetObjectID() == dirtodelete);
}
// Get the root dir, checking for deleted items
{
// Command
std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolClientListDirectory::RootDirectory,
BackupProtocolClientListDirectory::Flags_Dir | BackupProtocolClientListDirectory::Flags_Deleted,
BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
// 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);
BackupStoreFilenameClear n("test_delete");
TEST_THAT(en->GetName() == n);
}
// Then... check everything's deleted
test_everything_deleted(protocolReadOnly, dirtodelete);
}
// Finish the connections
protocolReadOnly.QueryFinished();
protocol.QueryFinished();
// Close logs
::fclose(protocolReadOnlyLog);
::fclose(protocolLog);
}
return 0;
}
int test3(int argc, const char *argv[])
{
// 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.
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
int encBlockSize = BackupStoreFile::MaxBlockSizeForChunkSize(SMALL_BLOCK_SIZE);
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);
uint8_t *decoded = (uint8_t*)malloc(decBlockSize);
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);
}
// Encode and decode a big block (should be compressed)
{
int encBlockSize = BackupStoreFile::MaxBlockSizeForChunkSize(ENCFILE_SIZE);
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);
uint8_t *decoded = (uint8_t*)malloc(decBlockSize);
int decSize = BackupStoreFile::DecodeChunk(encoded.mpBuffer, encSize, decoded, decBlockSize);
TEST_THAT(decSize < decBlockSize);
TEST_THAT(decSize == ENCFILE_SIZE);
// 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);
f.Write(encfile, sizeof(encfile));
}
// Encode it
{
FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL);
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);
}
// Decode it
{
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));
FileStream in("testfiles/testenc1_orig");
int encfile_i[ENCFILE_SIZE];
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");
std::auto_ptr<BackupStoreFile::DecodedStream> decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite));
CollectInBufferStream d;
decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */);
d.SetForReading();
TEST_THAT(d.GetSize() == sizeof(encfile));
TEST_THAT(memcmp(encfile, d.GetBuffer(), sizeof(encfile)) == 0);
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);
f.Write(encfile + 2, FILE_SIZE_JUST_OVER);
BackupStoreFilenameClear name("testenc2");
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name));
CollectInBufferStream e;
encoded->CopyStreamTo(e);
e.SetForReading();
std::auto_ptr<BackupStoreFile::DecodedStream> decoded(BackupStoreFile::DecodeFileStream(e, IOStream::TimeOutInfinite));
CollectInBufferStream d;
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(decoded->GetNumBlocks() == 2);
}
// Test that reordered streams work too
{
FileStream enc("testfiles/testenc1_enc");
std::auto_ptr<IOStream> reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false));
std::auto_ptr<BackupStoreFile::DecodedStream> decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite));
CollectInBufferStream d;
decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */);
d.SetForReading();
TEST_THAT(d.GetSize() == sizeof(encfile));
TEST_THAT(memcmp(encfile, d.GetBuffer(), sizeof(encfile)) == 0);
TEST_THAT(decoded->GetNumBlocks() == 3);
}
// 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);
}
}
// Store info
{
RaidFileWrite::CreateDirectory(0, "test-info");
BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL);
TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile);
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, true));
TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->ChangeBlocksInDeletedFiles(1), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->RemovedDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly);
}
{
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, false));
info->ChangeBlocksUsed(8);
info->ChangeBlocksInOldFiles(9);
info->ChangeBlocksInDeletedFiles(10);
info->ChangeBlocksUsed(-1);
info->ChangeBlocksInOldFiles(-4);
info->ChangeBlocksInDeletedFiles(-9);
TEST_CHECK_THROWS(info->ChangeBlocksUsed(-100), BackupStoreException, StoreInfoBlockDeltaMakesValueNegative);
TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(-100), BackupStoreException, StoreInfoBlockDeltaMakesValueNegative);
TEST_CHECK_THROWS(info->ChangeBlocksInDeletedFiles(-100), BackupStoreException, StoreInfoBlockDeltaMakesValueNegative);
info->AddDeletedDirectory(2);
info->AddDeletedDirectory(3);
info->AddDeletedDirectory(4);
info->RemovedDeletedDirectory(3);
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);
TEST_THAT(info->GetBlocksInOldFiles() == 5);
TEST_THAT(info->GetBlocksInDeletedFiles() == 1);
TEST_THAT(info->GetBlocksSoftLimit() == 3461231233455433LL);
TEST_THAT(info->GetBlocksHardLimit() == 2934852487LL);
const std::vector<int64_t> &delfiles(info->GetDeletedDirectories());
TEST_THAT(delfiles.size() == 2);
TEST_THAT(delfiles[0] == 2);
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");
// First, try logging in without an account having been created... just make sure login fails.
int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
::sleep(1);
TEST_THAT(ServerIsAlive(pid));
// BLOCK
{
// Open a connection to the server
SocketStreamTLS conn;
conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
// Make a protocol
BackupProtocolClient protocol(conn);
// Check the version
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
ConnectionException, Conn_Protocol_UnexpectedReply);
// Finish the connection
protocol.QueryFinished();
}
// Create an account for the test client
TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567"));
TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); // make sure something is written to it
TEST_THAT(ServerIsAlive(pid));
TEST_THAT(test_server("localhost") == 0);
// Test the deletion of objects by the housekeeping system
// First, things as they are now.
recursive_count_objects_results before = {0,0,0};
recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, before);
TEST_THAT(before.objectsNotDel != 0);
TEST_THAT(before.deleted != 0);
TEST_THAT(before.old != 0);
// Kill it
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
TestRemoteProcessMemLeaks("bbstored.memleaks");
// Set a new limit on the account -- leave the hard limit high to make sure the target for
// freeing space is the soft limit.
TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Start things up
pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
::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");
// Count the objects again
recursive_count_objects_results after = {0,0,0};
recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, after);
printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after.deleted, after.old);
// 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);
// Set a really small hard limit
TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Try to upload a file and create a directory, and check an error is generated
{
// Open a connection to the server
SocketStreamTLS conn;
conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
// Make a protocol
BackupProtocolClient protocol(conn);
// Check the version
std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0));
int64_t modtime = 0;
BackupStoreFilenameClear fnx("exceed-limit");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/test3", BackupProtocolClientListDirectory::RootDirectory, fnx, &modtime));
TEST_THAT(modtime != 0);
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
BackupProtocolClientListDirectory::RootDirectory,
modtime,
modtime, /* use it for attr hash too */
0, /* diff from ID */
fnx,
*upload)),
ConnectionException, Conn_Protocol_UnexpectedReply);
MemBlockStream attr(&modtime, sizeof(modtime));
BackupStoreFilenameClear fnxd("exceed-limit-dir");
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
BackupProtocolClientListDirectory::RootDirectory,
9837429842987984LL, fnxd, attr)),
ConnectionException, Conn_Protocol_UnexpectedReply);
// Finish the connection
protocol.QueryFinished();
}
// Kill it again
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
TestRemoteProcessMemLeaks("bbstored.memleaks");
}
return 0;
}
int multi_server()
{
printf("Starting server for connection from remote machines...\n");
// Create an account for the test client
TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// First, try logging in without an account having been created... just make sure login fails.
int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
::sleep(1);
TEST_THAT(ServerIsAlive(pid));
// Wait for a keypress
printf("Press ENTER to terminate the server\n");
char line[512];
fgets(line, 512, stdin);
printf("Terminating server...\n");
// Kill it
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
TestRemoteProcessMemLeaks("bbstored.memleaks");
}
return 0;
}
int test(int argc, const char *argv[])
{
// 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 because the key won't be set up when these are initialised
for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l)
{
ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]);
}
for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l)
{
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]);
}
// large file test
/* {
int64_t modtime = 0;
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("/Users/ben/temp/large.tar",
BackupProtocolClientListDirectory::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;
}
syntax highlighted by Code2HTML, v. 0.9.1