testing: added Client::Source::*::testLinkedSources

The WebDAV backend must support different kinds of items in the same
collection. The new testLinkedSources covers this by adding, updating
and deleting an item of one kind and checking that other sources
referencing the same database do not see these changes.

This test must be activated for a specific source by adding links to
other sources using the same database. A separate commit will do that
for WebDAV.
This commit is contained in:
Patrick Ohly 2012-06-12 17:20:40 +02:00
parent 497a9bec74
commit c1a705169d
4 changed files with 163 additions and 0 deletions

View File

@ -296,6 +296,7 @@ public:
config.m_createSourceA = createSource;
config.m_createSourceB = createSource;
config.m_sourceName = test->m_configName.c_str();
config.m_linkedSources = test->m_linkedSources;
test->updateConfig(config);
}

View File

@ -485,6 +485,15 @@ struct ClientTestConfig {
*/
boost::function<void (std::string &)> m_update;
boost::function<void (std::string &)> m_genericUpdate;
/**
* A list of m_sourceName values of other ClientTestConfigs
* which share the same database. Normally, sources are tested in
* isolation, but for such linked sources we also need to test
* interdependencies, in particular regarding change tracking and
* item listing.
*/
std::list<std::string> m_linkedSources;
};
/**
@ -561,6 +570,15 @@ class RegisterSyncSourceTest
const string m_configName;
const string m_testCaseName;
/**
* A list of m_configName values of other RegisterSyncSourceTest
* which share the same database. Normally, sources are tested in
* isolation, but for such linked sources we also need to test
* interdependencies, in particular regarding change tracking and
* item listing.
*/
std::list<std::string> m_linkedSources;
};
class TestRegistry : public vector<const RegisterSyncSourceTest *>

View File

@ -266,6 +266,9 @@ class TestingSyncSourcePtr : public std::auto_ptr<TestingSyncSource>
public:
TestingSyncSourcePtr() : m_active(false) {}
TestingSyncSourcePtr(const TestingSyncSourcePtr &other) : m_active(false) {
CPPUNIT_ASSERT(!other.get());
}
~TestingSyncSourcePtr()
{
// We can skip the full cleanup if the test has already failed.
@ -444,6 +447,10 @@ void LocalTests::addTests() {
if (config.m_createSourceB) {
ADD_TEST(LocalTests, testChanges);
ADD_TEST(LocalTests, testChangesMultiCycles);
if (!config.m_linkedSources.empty()) {
ADD_TEST(LocalTests, testLinkedSources);
}
}
}
@ -1270,6 +1277,115 @@ void LocalTests::testChangesMultiCycles()
doChanges(true);
}
// Make changes in one source and verify that other linked
// sources do not see and report any changes in their view
// of the shared database. Source A of the other sources
// is created once and is restarted, source B is created
// from scratch after each change.
void LocalTests::testLinkedSources()
{
// make changes in each of the sources (doesn't have t be
// the current one)
BOOST_FOREACH (LocalTests *main, m_linkedSources) {
CLIENT_TEST_LOG("making changes in %s", main->getSourceName().c_str());
// first delete via *all* sources
BOOST_FOREACH (LocalTests *test, m_linkedSources) {
CLIENT_TEST_LOG("clean via source A of %s", test->getSourceName().c_str());
CT_ASSERT_NO_THROW(test->deleteAll(test->createSourceA));
}
std::map<std::string, TestingSyncSourcePtr> sourcesA;
BOOST_FOREACH (LocalTests *test, m_linkedSources) {
if (test == main) {
continue;
}
TestingSyncSourcePtr &source = sourcesA[test->getSourceName()];
CLIENT_TEST_LOG("creating source A of %s", test->getSourceName().c_str());
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(test->createSourceA()));
CT_ASSERT_NO_THROW(source.stopAccess());
}
// insert one item
CLIENT_TEST_LOG("inserting into %s", main->getSourceName().c_str());
CT_ASSERT_NO_THROW(main->testSimpleInsert());
BOOST_FOREACH (LocalTests *test, m_linkedSources) {
if (test == main) {
continue;
}
TestingSyncSourcePtr &source = sourcesA[test->getSourceName()];
CLIENT_TEST_LOG("checking %s after insertion into %s",
test->getSourceName().c_str(),
main->getSourceName().c_str());
SOURCE_ASSERT_NO_FAILURE(source.get(), source.startAccess());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_NO_FAILURE(source.get(), source.stopAccess());
TestingSyncSourcePtr sourceB;
SOURCE_ASSERT_NO_FAILURE(sourceB.get(), sourceB.reset(test->createSourceB()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countNewItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countUpdatedItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countDeletedItems(sourceB.get()));
}
// update one item
CLIENT_TEST_LOG("updating in %s", main->getSourceName().c_str());
CT_ASSERT_NO_THROW(main->update(main->createSourceA, main->config.m_updateItem));
BOOST_FOREACH (LocalTests *test, m_linkedSources) {
if (test == main) {
continue;
}
TestingSyncSourcePtr &source = sourcesA[test->getSourceName()];
CLIENT_TEST_LOG("checking %s after update into %s",
test->getSourceName().c_str(),
main->getSourceName().c_str());
SOURCE_ASSERT_NO_FAILURE(source.get(), source.startAccess());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_NO_FAILURE(source.get(), source.stopAccess());
TestingSyncSourcePtr sourceB;
SOURCE_ASSERT_NO_FAILURE(sourceB.get(), sourceB.reset(test->createSourceB()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countNewItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countUpdatedItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countDeletedItems(sourceB.get()));
}
// delete one item
CLIENT_TEST_LOG("deleting in %s", main->getSourceName().c_str());
CT_ASSERT_NO_THROW(main->deleteAll(main->createSourceA));
BOOST_FOREACH (LocalTests *test, m_linkedSources) {
if (test == main) {
continue;
}
TestingSyncSourcePtr &source = sourcesA[test->getSourceName()];
CLIENT_TEST_LOG("checking %s after delete in %s",
test->getSourceName().c_str(),
main->getSourceName().c_str());
SOURCE_ASSERT_NO_FAILURE(source.get(), source.startAccess());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_NO_FAILURE(source.get(), source.stopAccess());
TestingSyncSourcePtr sourceB;
SOURCE_ASSERT_NO_FAILURE(sourceB.get(), sourceB.reset(test->createSourceB()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countNewItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countUpdatedItems(sourceB.get()));
SOURCE_ASSERT_EQUAL(sourceB.get(), 0, countDeletedItems(sourceB.get()));
}
}
}
// clean database, import file, then export again and compare
void LocalTests::testImport() {
// check additional requirements
@ -5790,6 +5906,8 @@ public:
CppUnit::TestSuite *tests;
// create local source tests
typedef std::map<std::string, LocalTests *> ConfigMap;
ConfigMap configs;
tests = new CppUnit::TestSuite(alltests->getName() + "::Source");
for (source=0; source < client.getNumLocalSources(); source++) {
ClientTest::Config config;
@ -5799,6 +5917,18 @@ public:
client.createLocalTests(tests->getName() + "::" + config.m_sourceName, source, config);
sourcetests->addTests();
tests->addTest(FilterTest(sourcetests));
configs[config.m_sourceName] = sourcetests;
}
}
// link configs of sources which share the same database
BOOST_FOREACH (const ConfigMap::value_type &entry, configs) {
LocalTests *sourcetests = entry.second;
const ClientTest::Config &config = sourcetests->config;
if (!config.m_linkedSources.empty()) {
sourcetests->m_linkedSources.push_back(sourcetests);
BOOST_FOREACH (const std::string &source, config.m_linkedSources) {
sourcetests->m_linkedSources.push_back(configs[source]);
}
}
}
alltests->addTest(FilterTest(tests));

View File

@ -476,6 +476,19 @@ public:
/** configuration that corresponds to source */
const ClientTest::Config config;
/** shortcut for config.m_sourceName */
const std::string &getSourceName() const { return config.m_sourceName; }
/**
* A list of config pointers which share the same
* database. Normally, sources are tested in isolation, but for
* such linked sources we also need to test interdependencies, in
* particular regarding change tracking and item listing.
*
* This includes *all* configs, not just the other ones.
*/
std::list<LocalTests *> m_linkedSources;
/** helper funclets to create sources */
CreateSource createSourceA, createSourceB;
@ -617,6 +630,7 @@ public:
void doChanges(bool restart);
virtual void testChanges();
virtual void testChangesMultiCycles();
virtual void testLinkedSources();
virtual void testImport();
virtual void testImportDelete();
virtual void testRemoveProperties();