📄 clienttest.cpp
字号:
accessClientB->sync(SYNC_ONE_WAY_FROM_CLIENT, ".send", CheckSyncReport(0,0,0, 1,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(), 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 client A for verification
// => receive one item
sync(SYNC_TWO_WAY, ".check", CheckSyncReport(1,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(), 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());
}
}
// delete items on client B, sync to server
for (it = accessClientB->sources.begin(); it != accessClientB->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());
}
}
accessClientB->sync(SYNC_ONE_WAY_FROM_CLIENT, ".delete", CheckSyncReport(0,0,0, 0,0,1));
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, 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 client A
// => one item left (the one inserted locally)
sync(SYNC_TWO_WAY, ".delete", CheckSyncReport(0,0,1, 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(), 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());
}
}
}
// creates several items, transmits them back and forth and
// then compares which of them have been preserved
void SyncTests::testItems() {
// clean server and first test database
deleteAll();
// import data
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->testImport();
}
// transfer from client A to server to client B
sync(SYNC_TWO_WAY, ".send");
accessClientB->refreshClient();
compareDatabases();
}
// tests the following sequence of events:
// - both clients in sync with server
// - client 1 adds item
// - client 1 updates the same item
// - client 2 gets item: the client should be asked to add the item
//
// However it has been observed that sometimes the item was sent as "update"
// for a non-existant local item. This is a server bug, the client does not
// have to handle that. See
// http://forge.objectweb.org/tracker/?func=detail&atid=100096&aid=305018&group_id=96
void SyncTests::testAddUpdate() {
// clean server and both test databases
deleteAll();
accessClientB->refreshClient();
// add item
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->insert(it->second->createSourceA, it->second->config.insertItem);
}
sync(SYNC_TWO_WAY, ".add", CheckSyncReport(0,0,0, 1,0,0));
// update it
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->update(it->second->createSourceB, it->second->config.updateItem);
}
sync(SYNC_TWO_WAY, ".update", CheckSyncReport(0,0,0, 0,1,0));
// now download the updated item into the second client
accessClientB->sync(SYNC_TWO_WAY, ".recv", CheckSyncReport(1,0,0, 0,0,0));
// compare the two databases
compareDatabases();
}
//
// stress tests: execute some of the normal operations,
// but with large number of artificially generated items
//
// two-way sync with clean client/server,
// followed by slow sync and comparison
// via second client
void SyncTests::testManyItems() {
// clean server and client A
deleteAll();
// import artificial data
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->insertManyItems(it->second->createSourceA);
}
// send data to server
sync(SYNC_TWO_WAY, ".send", CheckSyncReport(0,0,0, -1,0,0));
// ensure that client has the same data, ignoring data conversion
// issues (those are covered by testItems())
refreshClient();
// also copy to second client
accessClientB->refreshClient();
// slow sync now should not change anything
sync(SYNC_SLOW, ".twinning");
// compare
compareDatabases();
}
/**
* implements testMaxMsg(), testLargeObject(), testLargeObjectEncoded()
* using a sequence of items with varying sizes
*/
void SyncTests::doVarSizes(bool withMaxMsgSize,
bool withLargeObject,
const char *encoding) {
static const int maxMsgSize = 8 * 1024;
// clean server and client A
deleteAll();
// insert items, doubling their size, then restart with small size
source_it it;
for (it = sources.begin(); it != sources.end(); ++it) {
int item = 1;
for (int i = 0; i < 2; i++ ) {
int size = 1;
while (size < 2 * maxMsgSize) {
it->second->insertManyItems(it->second->createSourceA, item, 1, (int)strlen(it->second->config.templateItem) + 10 + size);
size *= 2;
item++;
}
}
}
// transfer to server
sync(SYNC_TWO_WAY, ".send",
CheckSyncReport(0,0,0, -1,0,0), // number of items sent to server depends on source
withMaxMsgSize ? maxMsgSize : 0,
withMaxMsgSize ? maxMsgSize * 100 : 0,
withLargeObject,
encoding);
// copy to second client
accessClientB->sync(SYNC_REFRESH_FROM_SERVER, ".recv",
CheckSyncReport(-1,0,-1, 0,0,0), // number of items received from server depends on source
withLargeObject ? maxMsgSize : withMaxMsgSize ? maxMsgSize * 100 /* large enough so that server can sent the largest item */ : 0,
withMaxMsgSize ? maxMsgSize * 100 : 0,
withLargeObject,
encoding);
// compare
compareDatabases();
}
void SyncTests::sync(SyncMode syncMode,
const std::string &logprefix,
CheckSyncReport checkReport,
long maxMsgSize,
long maxObjSize,
bool loSupport,
const char *encoding) {
int res = 0;
static int syncCounter = 0;
static std::string lastTest;
std::stringstream logstream;
// reset counter when switching tests
if (lastTest != getCurrentTest()) {
syncCounter = 0;
lastTest = getCurrentTest();
}
logstream << std::setw(4) << std::setfill('0') << syncCounter << "_" << getCurrentTest() << logprefix;
std::string logname = logstream.str();
simplifyFilename(logname);
syncCounter++;
std::string logfile = logname + ".client." + (accessClientB ? "A" : "B") + ".log";
remove(logfile.c_str());
LOG.setLogName(logfile.c_str());
LOG.reset();
try {
res = client.sync(sourceArray,
syncMode,
checkReport,
maxMsgSize,
maxObjSize,
loSupport,
encoding);
client.postSync(res, logname);
} catch (...) {
res = 1;
client.postSync(res, logname);
// this logs the original exception using CPPUnit mechanisms
CPPUNIT_ASSERT_NO_THROW( throw );
}
CPPUNIT_ASSERT( !res );
}
/** generates tests on demand based on what the client supports */
class ClientTestFactory : public CppUnit::TestFactory {
public:
ClientTestFactory(ClientTest &c) :
client(c) {}
virtual CppUnit::Test *makeTest() {
int source;
CppUnit::TestSuite *alltests = new CppUnit::TestSuite("Client");
CppUnit::TestSuite *tests;
// create local source tests
tests = new CppUnit::TestSuite(alltests->getName() + "::Source");
for (source=0; source < client.getNumSources(); source++) {
ClientTest::Config config;
client.getSourceConfig(source, config);
if (config.sourceName) {
LocalTests *sourcetests =
client.createLocalTests(tests->getName() + "::" + config.sourceName, source, config);
sourcetests->addTests();
tests->addTest(sourcetests);
}
}
alltests->addTest(tests);
tests = 0;
// create sync tests with just one source
tests = new CppUnit::TestSuite(alltests->getName() + "::Sync");
for (source=0; source < client.getNumSources(); source++) {
ClientTest::Config config;
client.getSourceConfig(source, config);
if (config.sourceName) {
std::vector<int> sources;
sources.push_back(source);
SyncTests *synctests =
client.createSyncTests(tests->getName() + "::" + config.sourceName, sources);
synctests->addTests();
tests->addTest(synctests);
}
}
// create sync tests with all sources enabled, unless we only have one:
// that would be identical to the test above
std::vector<int> sources;
std::string name, name_reversed;
for (source=0; source < client.getNumSources(); source++) {
ClientTest::Config config;
client.getSourceConfig(source, config);
if (config.sourceName) {
sources.push_back(source);
if (name.size() > 0) {
name += "_";
name_reversed = std::string("_") + name_reversed;
}
name += config.sourceName;
name_reversed = config.s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -