📄 clienttest.cpp
字号:
// test that a two-way sync deletes the copy of an item in the other database
void SyncTests::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 SyncTests::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 SyncTests::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
// => one item left on second client (the one inserted locally)
void SyncTests::testOneWayFromServer() {
// no items anywhere
deleteAll();
accessClientB->refreshClient();
// check that everything is empty, also resets change tracking
// in second sources of each client
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
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());
}
}
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
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());
}
}
// add one item on first client, copy to server, and check change tracking via second source
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->insertManyItems(it->second->createSourceA, 1, 1);
}
sync(SYNC_TWO_WAY, ".send", CheckSyncReport(0,0,0, 1,0,0));
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// add a different item on second client, one-way-from-server
// => one item added locally, none sent to server
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
it->second->insertManyItems(it->second->createSourceA, 2, 1);
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
accessClientB->sync(SYNC_ONE_WAY_FROM_SERVER, ".recv", CheckSyncReport(1,0,0, 0,0,0));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 2, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// two-way sync with first client for verification
// => no changes
sync(SYNC_TWO_WAY, ".check", CheckSyncReport(0,0,0, 0,0,0));
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// delete items on clientA, sync to server
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
sync(SYNC_TWO_WAY, ".delete", CheckSyncReport(0,0,0, 0,0,1));
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// sync the same change to second client
// => one item left (the one inserted locally)
accessClientB->sync(SYNC_ONE_WAY_FROM_SERVER, ".delete", CheckSyncReport(0,0,1, 0,0,0));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
}
// tests one-way sync from client:
// - 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-client
// - two-way sync with first client
// => two items on first client, one on second
// - delete on second client, sync that to first client
// via one-way-from-client, two-way
// => one item left on first client (the one inserted locally)
void SyncTests::testOneWayFromClient() {
// no items anywhere
deleteAll();
accessClientB->deleteAll();
// check that everything is empty, also resets change tracking
// in second sources of each client
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
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());
}
}
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
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());
}
}
// add one item on first client, copy to server, and check change tracking via second source
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->insertManyItems(it->second->createSourceA, 1, 1);
}
sync(SYNC_TWO_WAY, ".send", CheckSyncReport(0,0,0, 1,0,0));
for (it = sources.begin(); it != sources.end(); ++it) {
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
// add a different item on second client, one-way-from-client
// => no item added locally, one sent to server
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
it->second->insertManyItems(it->second->createSourceA, 2, 1);
if (it->second->config.createSourceB) {
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(it->second->createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -