📄 clienttest.cpp
字号:
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 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 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));
}
// do a two-way sync without additional checks
void testTwoWaySync() {
sync(SYNC_TWO_WAY);
}
// do a slow sync without additional checks
void testSlowSync() {
sync(SYNC_SLOW);
}
// do a refresh from server sync without additional checks
void testRefreshFromServerSync() {
sync(SYNC_REFRESH_FROM_SERVER);
}
// do a refresh from client sync without additional checks
void testRefreshFromClientSync() {
sync(SYNC_REFRESH_FROM_CLIENT);
}
// delete all items, locally and on server using two-way sync
void testDeleteAllSync() {
deleteAll(DELETE_ALL_SYNC);
}
// delete all items, locally and on server using refresh-from-client sync
void 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 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 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 an item from one address book into the other
void testCopy() {
doCopy();
compareDatabases();
}
// test that a two-way sync copies updates from database to the other client,
// using simple data commonly supported by servers
void 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 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();
}
// test that a two-way sync deletes the copy of an item in the other database
void testDelete() {
// setup client A, B and server so that they all contain the same item
doCopy();
// delete it on A
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
// transfer change from A to server to B
sync(SYNC_TWO_WAY, ".delete", CheckSyncReport(0,0,0, 0,0,1));
accessClientB->sync(SYNC_TWO_WAY, ".delete", CheckSyncReport(0,0,1, 0,0,0));
// check client B: shouldn't have any items now
for (it = sources.begin(); it != sources.end(); ++it) {
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(it->second->createSourceA()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->beginSync());
SOURCE_ASSERT_EQUAL(copy.get(), 0, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
}
// test what the server does when it finds that different
// fields of the same item have been modified
void testMerge() {
// setup client A, B and server so that they all contain the same item
doCopy();
// update in client A
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->update(it->second->createSourceA, it->second->config.mergeItem1);
}
// update in client B
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
it->second->update(it->second->createSourceA, it->second->config.mergeItem2);
}
// send change to server from client A (no conflict), then from B (conflict)
sync(SYNC_TWO_WAY, ".send", CheckSyncReport(0,0,0, 0,1,0));
sync(SYNC_TWO_WAY, ".recv");
// figure out how the conflict during ".recv" was handled
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(it->second->createSourceA()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->beginSync());
int numItems;
SOURCE_ASSERT_NO_FAILURE(copy.get(), numItems = countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT(numItems >= 1);
CPPUNIT_ASSERT(numItems <= 2);
std::cout << " " << it->second->config.sourceName << ": " << (numItems == 1 ? "conflicting items were merged" : "both of the conflicting items were preserved") << " ";
std::cout.flush();
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
}
// test what the server does when it has to execute a slow sync
// with identical data on client and server:
// expected behaviour is that nothing changes
void testTwinning() {
// clean server and client A
deleteAll();
// import test data
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testImport();
}
// send to server
sync(SYNC_TWO_WAY, ".send");
// ensure that client has the same data, thus ignoring data conversion
// issues (those are covered by testItems())
refreshClient();
// copy to client B to have another copy
accessClientB->refreshClient();
// slow sync should not change anything
sync(SYNC_TWO_WAY, ".twinning");
// check
compareDatabases();
}
// tests one-way sync from server:
// - get both clients and server in sync with no items anywhere
// - add one item on first client, copy to server
// - add a different item on second client, one-way-from-server
// - two-way sync with first client
// => one item on first client, two on second
// - delete on first client, sync that to second client
// via two-way sync + one-way-from-server
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -