📄 clienttest.cpp
字号:
// check that exactly this number of items is listed as new
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->beginSync());
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countNewItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countUpdatedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countDeletedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
// delete all items
deleteAll(createSourceA);
// verify again
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countNewItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countUpdatedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countDeletedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
SyncTests::SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA) :
CppUnit::TestSuite(name),
client(cl) {
sourceArray = new int[sourceIndices.size() + 1];
for (std::vector<int>::iterator it = sourceIndices.begin();
it != sourceIndices.end();
++it) {
ClientTest::Config config;
client.getSourceConfig(*it, config);
if (config.sourceName) {
sourceArray[sources.size()] = *it;
sources.push_back(std::pair<int,LocalTests *>(*it, cl.createLocalTests(config.sourceName, *it, config)));
}
}
sourceArray[sources.size()] = -1;
// check whether we have a second client
ClientTest *clientB = cl.getClientB();
if (clientB) {
accessClientB = clientB->createSyncTests(name, sourceIndices, false);
} else {
accessClientB = 0;
}
}
SyncTests::~SyncTests() {
for (source_it it = sources.begin();
it != sources.end();
++it) {
delete it->second;
}
delete [] sourceArray;
if (accessClientB) {
delete accessClientB;
}
}
/** adds the supported tests to the instance itself */
void SyncTests::addTests() {
if (sources.size()) {
const ClientTest::Config &config(sources[0].second->config);
// run this test first, even if it is more complex:
// if it works, all the following tests will run with
// the server in a deterministic state
if (config.createSourceA) {
if (config.insertItem) {
ADD_TEST(SyncTests, testDeleteAllRefresh);
}
}
ADD_TEST(SyncTests, testTwoWaySync);
ADD_TEST(SyncTests, testSlowSync);
ADD_TEST(SyncTests, testRefreshFromServerSync);
ADD_TEST(SyncTests, testRefreshFromClientSync);
if (config.createSourceA) {
if (config.insertItem) {
ADD_TEST(SyncTests, testRefreshSemantic);
ADD_TEST(SyncTests, testRefreshStatus);
if (accessClientB &&
config.dump &&
config.compare) {
ADD_TEST(SyncTests, testCopy);
ADD_TEST(SyncTests, testDelete);
ADD_TEST(SyncTests, testAddUpdate);
ADD_TEST(SyncTests, testManyItems);
if (config.updateItem) {
ADD_TEST(SyncTests, testUpdate);
}
if (config.complexUpdateItem) {
ADD_TEST(SyncTests, testComplexUpdate);
}
if (config.mergeItem1 && config.mergeItem2) {
ADD_TEST(SyncTests, testMerge);
}
if (config.import) {
ADD_TEST(SyncTests, testTwinning);
ADD_TEST(SyncTests, testItems);
}
if (config.templateItem) {
ADD_TEST(SyncTests, testMaxMsg);
ADD_TEST(SyncTests, testLargeObject);
ADD_TEST(SyncTests, testLargeObjectBin);
if (client.isB64Enabled()) {
ADD_TEST(SyncTests, testLargeObjectEncoded);
}
ADD_TEST(SyncTests, testOneWayFromServer);
ADD_TEST(SyncTests, testOneWayFromClient);
}
}
}
}
}
}
/** compare databases of first and second client */
void SyncTests::compareDatabases() {
source_it it1;
source_it it2;
CPPUNIT_ASSERT(accessClientB);
for (it1 = sources.begin(), it2 = accessClientB->sources.begin();
it1 != sources.end() && it2 != accessClientB->sources.end();
++it1, ++it2) {
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(it2->second->createSourceB()));
it1->second->compareDatabases(NULL, *copy.get());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
CPPUNIT_ASSERT(it1 == sources.end());
CPPUNIT_ASSERT(it2 == accessClientB->sources.end());
}
/** deletes all items locally and on server */
void SyncTests::deleteAll(DeleteAllMode mode) {
source_it it;
switch(mode) {
case DELETE_ALL_SYNC:
// a refresh from server would slightly reduce the amount of data exchanged, but not all servers support it
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
sync(SYNC_SLOW, ".deleteall.init");
// now that client and server are in sync, delete locally and sync again
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
sync(SYNC_TWO_WAY, ".deleteall.twoway", CheckSyncReport(0,0,0, 0,0,-1));
break;
case DELETE_ALL_REFRESH:
// delete locally and then tell the server to "copy" the empty databases
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
sync(SYNC_REFRESH_FROM_CLIENT, ".deleteall.refreshserver", CheckSyncReport(0,0,0, 0,0,-1));
break;
}
}
/** get both clients in sync with empty server, then copy one item from client A to B */
void SyncTests::doCopy() {
// check requirements
CPPUNIT_ASSERT(accessClientB);
deleteAll();
accessClientB->deleteAll();
// insert into first database, copy to server
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testSimpleInsert();
}
sync(SYNC_TWO_WAY, ".send", CheckSyncReport(0,0,0, 1,0,0));
// copy into second database
accessClientB->sync(SYNC_TWO_WAY, ".recv", CheckSyncReport(1,0,0, 0,0,0));
compareDatabases();
}
/**
* replicate server database locally: same as SYNC_REFRESH_FROM_SERVER,
* but done with explicit local delete and then a SYNC_SLOW because some
* servers do no support SYNC_REFRESH_FROM_SERVER
*/
void SyncTests::refreshClient() {
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
sync(SYNC_SLOW, ".refresh", CheckSyncReport(-1,0,0, 0,0,0));
}
// delete all items, locally and on server using refresh-from-client sync
void SyncTests::testDeleteAllRefresh() {
source_it it;
// copy something to server first; doesn't matter whether it has the
// item already or not, as long as it exists there afterwards
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testSimpleInsert();
}
sync(SYNC_SLOW, ".insert");
// now ensure we can delete it
deleteAll(DELETE_ALL_SYNC);
// nothing stored locally?
for (it = sources.begin(); it != sources.end(); ++it) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceA()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
// make sure server really deleted everything
sync(SYNC_SLOW, ".check", CheckSyncReport(0,0,0, 0,0,0));
for (it = sources.begin(); it != sources.end(); ++it) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceA()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// test that a refresh sync of an empty server leads to an empty datatbase
void SyncTests::testRefreshSemantic() {
source_it it;
// clean client and server
deleteAll();
// insert item, then refresh from empty server
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testSimpleInsert();
}
sync(SYNC_REFRESH_FROM_SERVER, "", CheckSyncReport(0,0,-1, 0,0,0));
// check
for (it = sources.begin(); it != sources.end(); ++it) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceA()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// tests the following sequence of events:
// - insert item
// - delete all items
// - insert one other item
// - refresh from client
// => no items should now be listed as new, updated or deleted for this client during another sync
void SyncTests::testRefreshStatus() {
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testSimpleInsert();
}
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testSimpleInsert();
}
sync(SYNC_REFRESH_FROM_CLIENT, ".refresh-from-client", CheckSyncReport(0,0,0 /* 1,0,0 - not sure exactly what the server will be told */));
sync(SYNC_TWO_WAY, ".two-way", CheckSyncReport(0,0,0, 0,0,0));
}
// test that a two-way sync copies updates from database to the other client,
// using simple data commonly supported by servers
void SyncTests::testUpdate() {
CPPUNIT_ASSERT(sources.begin() != sources.end());
CPPUNIT_ASSERT(sources.begin()->second->config.updateItem);
// setup client A, B and server so that they all contain the same item
doCopy();
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->update(it->second->createSourceA, it->second->config.updateItem);
}
sync(SYNC_TWO_WAY, ".update", CheckSyncReport(0,0,0, 0,1,0));
accessClientB->sync(SYNC_TWO_WAY, ".update", CheckSyncReport(0,1,0, 0,0,0));
compareDatabases();
}
// test that a two-way sync copies updates from database to the other client,
// using data that some, but not all servers support, like adding a second
// phone number to a contact
void SyncTests::testComplexUpdate() {
// setup client A, B and server so that they all contain the same item
doCopy();
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->update(it->second->createSourceA, it->second->config.complexUpdateItem);
}
sync(SYNC_TWO_WAY, ".update", CheckSyncReport(0,0,0, 0,1,0));
accessClientB->sync(SYNC_TWO_WAY, ".update", CheckSyncReport(0,1,0, 0,0,0));
compareDatabases();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -