testing: enhanced DAV source testing + infrastructure
The main goal is to test CalDAV/CardDAV sources as part of a SyncML client and/or server. A test involving syncevo-http-server is now named "<client storage><server storage>": - edsfile = EDS in client, file in server (used to be syncevohttp) - davfile = CalDAV/CardDAV in client, file in server (new) - edsdav = EDS in client, CalDAV/CardDAV in server (new) For this, WebDAVSourceRegister.cpp must be able to create test sources which match the client 1/2 sync configs. The client "1" or "2" strings are passed through the abstract ClientTest into the source A/B create callbacks. WebDAVSourceRegister.cpp cannot get this directly from ClientTest because it lives in a plugin which is not necessarily linked against ClientTest. A conceptual change is that CLIENT_TEST_EVOLUTION_PREFIX/USER/PASSWORD no longer override existing config properties. That is necessary because the shared prefix is too simplistic for WebDAV (needs full URL in "database"); also helps KDE (needs resource URI). The env variables and the default "SyncEvolution_Test_" value for the database prefix are still used if the config does not exist. That is useful to prevent accidentally running client-test against the default databases. The nightly setup script might (should!?) be made public to simplify configuring a server. Another change is the user-configurable part of client-test now lives entirely in the _1/_2 client sync configs and contexts. From there the source properties are copied into the Client::Source context each time client-test runs.
This commit is contained in:
parent
a27f2af580
commit
5eed5ea60b
|
@ -171,9 +171,11 @@ static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::s
|
|||
}
|
||||
|
||||
static TestingSyncSource *createEASSource(const ClientTestConfig::createsource_t &create,
|
||||
ClientTest &client, int source, bool isSourceA)
|
||||
ClientTest &client,
|
||||
const std::string &clientID,
|
||||
int source, bool isSourceA)
|
||||
{
|
||||
TestingSyncSource *res = create(client, source, isSourceA);
|
||||
TestingSyncSource *res = create(client, clientID, source, isSourceA);
|
||||
|
||||
// Mangle username: if the base username in the config is account
|
||||
// "foo", then source B uses "foo_B", because otherwise it'll end
|
||||
|
@ -205,9 +207,9 @@ static void updateConfigEAS(const RegisterSyncSourceTest */* me */,
|
|||
// wrap orginal source creation, set default database for
|
||||
// database #0 and refuse to return a source for database #1
|
||||
config.m_createSourceA = boost::bind(createEASSource, config.m_createSourceA,
|
||||
_1, _2, _3);
|
||||
_1, _2, _3, _4);
|
||||
config.m_createSourceB = boost::bind(createEASSource, config.m_createSourceB,
|
||||
_1, _2, _3);
|
||||
_1, _2, _3, _4);
|
||||
|
||||
config.m_dump = DumpItems;
|
||||
config.m_sourceLUIDsAreVolatile = true;
|
||||
|
|
|
@ -233,8 +233,8 @@ public:
|
|||
if (m_type == "caldav") {
|
||||
config.m_supportsReccurenceEXDates = true;
|
||||
}
|
||||
config.m_createSourceA = boost::bind(&WebDAVTest::createSource, this, _3);
|
||||
config.m_createSourceB = boost::bind(&WebDAVTest::createSource, this, _3);
|
||||
config.m_createSourceA = boost::bind(&WebDAVTest::createSource, this, _2, _4);
|
||||
config.m_createSourceB = boost::bind(&WebDAVTest::createSource, this, _2, _4);
|
||||
ConfigProps::const_iterator it = m_props.find(m_type + "/testcases");
|
||||
if (it != m_props.end() ||
|
||||
(it = m_props.find("testcases")) != m_props.end()) {
|
||||
|
@ -242,19 +242,65 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
TestingSyncSource *createSource(bool isSourceA) const
|
||||
// This is very similar to client-test-app.cpp. TODO: refactor?!
|
||||
TestingSyncSource *createSource(const std::string &clientID, bool isSourceA) const
|
||||
{
|
||||
boost::shared_ptr<SyncConfig> context(new SyncConfig(string("target-config@client-test-") + m_server));
|
||||
SyncSourceNodes nodes = context->getSyncSourceNodes(m_type,
|
||||
/* string("_") m_clientID + */
|
||||
string("_") + (isSourceA ? "A" : "B"));
|
||||
std::string name = m_server + "_" + m_type;
|
||||
const char *server = getenv("CLIENT_TEST_SERVER");
|
||||
std::string config = "target-config@client-test";
|
||||
if (server) {
|
||||
config += "-";
|
||||
config += server;
|
||||
}
|
||||
std::string tracking =
|
||||
string("_") + clientID +
|
||||
string("_") + (isSourceA ? "A" : "B");
|
||||
|
||||
// always set properties taken from the environment;
|
||||
// TODO: "database" property (currently always uses the default)
|
||||
SE_LOG_DEBUG(NULL, NULL, "instantiating testing source %s in config %s, with tracking name %s",
|
||||
name.c_str(),
|
||||
config.c_str(),
|
||||
tracking.c_str());
|
||||
boost::shared_ptr<SyncConfig> context(new SyncConfig(config));
|
||||
SyncSourceNodes nodes = context->getSyncSourceNodes(name, tracking);
|
||||
|
||||
// Copy properties from the Client::Sync
|
||||
// @<CLIENT_TEST_SERVER>_<clientID>/<name> config, to ensure
|
||||
// that a testing source used as part of Client::Sync uses the
|
||||
// same settings.
|
||||
std::string peerName = std::string(server ? server : "no-such-server") + "_" + clientID;
|
||||
boost::shared_ptr<SyncConfig> peer(new SyncConfig(peerName));
|
||||
SyncSourceNodes peerNodes = peer->getSyncSourceNodes(name);
|
||||
SE_LOG_DEBUG(NULL, NULL, "overriding testing source %s properties with the ones from config %s = %s",
|
||||
name.c_str(),
|
||||
peerName.c_str(),
|
||||
peer->getRootPath().c_str());
|
||||
BOOST_FOREACH(const ConfigProperty *prop, SyncSourceConfig::getRegistry()) {
|
||||
if (prop->isHidden()) {
|
||||
continue;
|
||||
}
|
||||
boost::shared_ptr<FilterConfigNode> node = peerNodes.getNode(*prop);
|
||||
InitStateString value = prop->getProperty(*node);
|
||||
SE_LOG_DEBUG(NULL, NULL, " %s = %s (%s)",
|
||||
prop->getMainName().c_str(),
|
||||
value.c_str(),
|
||||
value.wasSet() ? "set" : "default");
|
||||
node = nodes.getNode(*prop);
|
||||
node->setProperty(prop->getMainName(), value);
|
||||
}
|
||||
// Also copy loglevel.
|
||||
context->setLogLevel(peer->getLogLevel());
|
||||
context->flush();
|
||||
|
||||
|
||||
// Always set properties taken from the environment.
|
||||
nodes.getProperties()->setProperty("backend", m_type);
|
||||
SE_LOG_DEBUG(NULL, NULL, " additional property backend = %s (from CLIENT_TEST_WEBDAV)",
|
||||
m_type.c_str());
|
||||
BOOST_FOREACH(const StringPair &propval, m_props) {
|
||||
boost::shared_ptr<FilterConfigNode> node = context->getNode(propval.first);
|
||||
if (node) {
|
||||
SE_LOG_DEBUG(NULL, NULL, " additional property %s = %s (from CLIENT_TEST_WEBDAV)",
|
||||
propval.first.c_str(), propval.second.c_str());
|
||||
node->setProperty(propval.first, propval.second);
|
||||
} else if (!boost::ends_with(propval.first, "testconfig") &&
|
||||
!boost::ends_with(propval.first, "testcases")) {
|
||||
|
|
|
@ -135,6 +135,8 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual std::string getClientID() const { return m_clientID; }
|
||||
|
||||
/**
|
||||
* code depends on other global constructors to run first, execute it after constructor but before
|
||||
* any other methods
|
||||
|
@ -239,11 +241,22 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// always set these properties: they might have changed since the last run
|
||||
string database = getDatabaseName(test->m_configName);
|
||||
sc->setDatabaseID(database);
|
||||
sc->setUser(m_evoUser);
|
||||
sc->setPassword(m_evoPassword);
|
||||
// Set these properties if not set yet: that means the env
|
||||
// variables are used when creating the config initially,
|
||||
// but then no longer can be used to change the config.
|
||||
// This prevents accidentally running a test with default
|
||||
// values, for example for the database.
|
||||
if (sc->getDatabaseID().empty()) {
|
||||
string database = getDatabaseName(test->m_configName);
|
||||
sc->setDatabaseID(database);
|
||||
}
|
||||
if (sc->getUser().empty() && !m_evoUser.empty()) {
|
||||
sc->setUser(m_evoUser);
|
||||
}
|
||||
if (sc->getPassword().empty() && !m_evoPassword.empty()) {
|
||||
sc->setPassword(m_evoPassword);
|
||||
}
|
||||
// Always set this one, to ensure the config matches the test.
|
||||
sc->setBackend(SourceType(testconfig.m_type).m_backend);
|
||||
}
|
||||
config->flush();
|
||||
|
@ -461,7 +474,7 @@ private:
|
|||
}
|
||||
|
||||
/** called by test frame work */
|
||||
static TestingSyncSource *createSource(ClientTest &client, int source, bool isSourceA) {
|
||||
static TestingSyncSource *createSource(ClientTest &client, const std::string &clientID, int source, bool isSourceA) {
|
||||
TestEvolution &evClient((TestEvolution &)client);
|
||||
string name = evClient.m_localSource2Config[source];
|
||||
|
||||
|
@ -480,15 +493,57 @@ private:
|
|||
config += "-";
|
||||
config += server;
|
||||
}
|
||||
std::string tracking =
|
||||
string("_") + m_clientID +
|
||||
"_" + (isSourceA ? "A" : "B");
|
||||
SE_LOG_DEBUG(NULL, NULL, "instantiating testing source %s in config %s, with tracking name %s",
|
||||
name.c_str(),
|
||||
config.c_str(),
|
||||
tracking.c_str());
|
||||
boost::shared_ptr<SyncConfig> context(new SyncConfig(config));
|
||||
SyncSourceNodes nodes = context->getSyncSourceNodes(name,
|
||||
string("_") + m_clientID +
|
||||
"_" + (isSourceA ? "A" : "B"));
|
||||
SyncSourceNodes nodes = context->getSyncSourceNodes(name, tracking);
|
||||
|
||||
// always set this property: the name might have changes since last test run
|
||||
nodes.getProperties()->setProperty("evolutionsource", database.c_str());
|
||||
nodes.getProperties()->setProperty("evolutionuser", m_evoUser.c_str());
|
||||
nodes.getProperties()->setProperty("evolutionpassword", m_evoPassword.c_str());
|
||||
// The user of client-test must have configured the source
|
||||
// @<CLIENT_TEST_SERVER>_<m_clientID>/<name> when doing
|
||||
// Client::Sync testing. Our testing source must use the same
|
||||
// properties, but different change tracking.
|
||||
std::string peerName = server ? (std::string(server) + "_" + m_clientID) : "@default";
|
||||
boost::shared_ptr<SyncConfig> peer(new SyncConfig(peerName));
|
||||
SyncSourceNodes peerNodes = peer->getSyncSourceNodes(name);
|
||||
SE_LOG_DEBUG(NULL, NULL, "overriding testing source %s properties with the ones from config %s = %s",
|
||||
name.c_str(),
|
||||
peerName.c_str(),
|
||||
peer->getRootPath().c_str());
|
||||
BOOST_FOREACH(const ConfigProperty *prop, SyncSourceConfig::getRegistry()) {
|
||||
if (prop->isHidden()) {
|
||||
continue;
|
||||
}
|
||||
boost::shared_ptr<FilterConfigNode> node = peerNodes.getNode(*prop);
|
||||
InitStateString value = prop->getProperty(*node);
|
||||
SE_LOG_DEBUG(NULL, NULL, " %s = %s (%s)",
|
||||
prop->getMainName().c_str(),
|
||||
value.c_str(),
|
||||
value.wasSet() ? "set" : "default");
|
||||
node = nodes.getNode(*prop);
|
||||
node->setProperty(prop->getMainName(), value);
|
||||
}
|
||||
context->flush();
|
||||
|
||||
// Same as in init() above: set values if still empty, but don't
|
||||
// overwrite anything.
|
||||
boost::shared_ptr<FilterConfigNode> props = nodes.getProperties();
|
||||
std::string value;
|
||||
if (!props->getProperty("database", value)) {
|
||||
props->setProperty("database", database);
|
||||
}
|
||||
if (!props->getProperty("databaseUser", value) &&
|
||||
!m_evoUser.empty()) {
|
||||
props->setProperty("databaseUser", m_evoUser);
|
||||
}
|
||||
if (!props->getProperty("databasePassword", value) &&
|
||||
!m_evoPassword.empty()) {
|
||||
props->setProperty("databasePassword", m_evoPassword);
|
||||
}
|
||||
|
||||
SyncSourceParams params(name,
|
||||
nodes,
|
||||
|
|
|
@ -201,11 +201,14 @@ struct ClientTestConfig {
|
|||
* the sync source's desctructor should not thow exceptions.
|
||||
*
|
||||
* @param client the same instance to which this config belongs
|
||||
* @param clientID the unique ID of the client, "1" resp. "2" in practice (can also be obtained as
|
||||
* client->getClientID(), but not all implementers have (or want) access to the
|
||||
* class definition)
|
||||
* @param source index of the data source (from 0 to ClientTest::getNumSources() - 1)
|
||||
* @param isSourceA true if the requested SyncSource is the first one accessing that
|
||||
* data, otherwise the second
|
||||
*/
|
||||
typedef boost::function<TestingSyncSource *(ClientTest &, int, bool)> createsource_t;
|
||||
typedef boost::function<TestingSyncSource *(ClientTest &, const std::string &, int, bool)> createsource_t;
|
||||
|
||||
/**
|
||||
* Creates a sync source which references the primary database;
|
||||
|
|
|
@ -241,6 +241,9 @@ class ClientTest {
|
|||
ClientTest(int serverSleepSec = 0, const std::string &serverLog= "");
|
||||
virtual ~ClientTest();
|
||||
|
||||
/** a unique string - "1" or "2" in practice */
|
||||
virtual std::string getClientID() const = 0;
|
||||
|
||||
/** set up before running a test */
|
||||
virtual void setup() { }
|
||||
|
||||
|
@ -448,7 +451,7 @@ public:
|
|||
|
||||
TestingSyncSource *operator() () {
|
||||
CPPUNIT_ASSERT(createSource);
|
||||
return createSource(client, source, isSourceA);
|
||||
return createSource(client, client.getClientID(), source, isSourceA);
|
||||
}
|
||||
|
||||
const ClientTest::Config::createsource_t createSource;
|
||||
|
|
106
test/runtests.py
106
test/runtests.py
|
@ -1164,7 +1164,29 @@ class ActiveSyncTest(SyncEvolutionTest):
|
|||
test = ActiveSyncTest("exchange")
|
||||
context.add(test)
|
||||
|
||||
test = SyncEvolutionTest("syncevohttp",
|
||||
syncevoPrefix=" ".join([os.path.join(sync.basedir, "test", "wrappercheck.sh")] +
|
||||
# redirect output of command run under valgrind (when
|
||||
# using valgrind) or of the whole command (otherwise)
|
||||
# to syncevohttp.log
|
||||
( 'valgrindcheck' in options.testprefix and \
|
||||
[ "VALGRIND_CMD_LOG=syncevohttp.log" ] or \
|
||||
[ "--daemon-log", "syncevohttp.log" ] ) +
|
||||
[ options.testprefix,
|
||||
os.path.join(compile.installdir, "usr", "libexec", "syncevo-dbus-server"),
|
||||
"--",
|
||||
os.path.join(sync.basedir, "test", "wrappercheck.sh"),
|
||||
# also redirect additional syncevo-http-server
|
||||
# output into the same file
|
||||
"--daemon-log", "syncevohttp.log",
|
||||
os.path.join(compile.installdir, "usr", "bin", "syncevo-http-server"),
|
||||
"--quiet",
|
||||
"http://127.0.0.1:9999/syncevolution",
|
||||
"--",
|
||||
options.testprefix])
|
||||
|
||||
# The test uses EDS on the clients and a server config with file
|
||||
# backends.
|
||||
test = SyncEvolutionTest("edsfile",
|
||||
compile,
|
||||
"", options.shell,
|
||||
"Client::Sync::eds_event Client::Sync::eds_contact Client::Sync::eds_event_eds_contact",
|
||||
|
@ -1172,9 +1194,9 @@ test = SyncEvolutionTest("syncevohttp",
|
|||
"CLIENT_TEST_NUM_ITEMS=10 "
|
||||
"CLIENT_TEST_LOG=syncevohttp.log "
|
||||
# could be enabled, but reporting result is currently missing (BMC #1009)
|
||||
#"CLIENT_TEST_RETRY=t "
|
||||
#"CLIENT_TEST_RESEND=t "
|
||||
#"CLIENT_TEST_SUSPEND=t "
|
||||
"CLIENT_TEST_RETRY=t "
|
||||
"CLIENT_TEST_RESEND=t "
|
||||
"CLIENT_TEST_SUSPEND=t "
|
||||
# server supports refresh-from-client, use it for
|
||||
# more efficient test setup
|
||||
"CLIENT_TEST_DELETE_REFRESH=1 "
|
||||
|
@ -1183,27 +1205,63 @@ test = SyncEvolutionTest("syncevohttp",
|
|||
"CLIENT_TEST_SKIP="
|
||||
# server does not detect duplicates (uses file backend), detecting on the
|
||||
# client breaks syncing (see '[SyncEvolution] 409 "item merged" in client')
|
||||
"Client::Sync::.*::testAddBothSides.*"
|
||||
# "Client::Sync::.*::testAddBothSides.*"
|
||||
,
|
||||
testPrefix=" ".join([os.path.join(sync.basedir, "test", "wrappercheck.sh")] +
|
||||
# redirect output of command run under valgrind (when
|
||||
# using valgrind) or of the whole command (otherwise)
|
||||
# to syncevohttp.log
|
||||
( 'valgrindcheck' in options.testprefix and \
|
||||
[ "VALGRIND_CMD_LOG=syncevohttp.log" ] or \
|
||||
[ "--daemon-log", "syncevohttp.log" ] ) +
|
||||
[ options.testprefix,
|
||||
os.path.join(compile.installdir, "usr", "libexec", "syncevo-dbus-server"),
|
||||
"--",
|
||||
os.path.join(sync.basedir, "test", "wrappercheck.sh"),
|
||||
# also redirect additional syncevo-http-server
|
||||
# output into the same file
|
||||
"--daemon-log", "syncevohttp.log",
|
||||
os.path.join(compile.installdir, "usr", "bin", "syncevo-http-server"),
|
||||
"--quiet",
|
||||
"http://127.0.0.1:9999/syncevolution",
|
||||
"--",
|
||||
options.testprefix]))
|
||||
testPrefix=syncevoPrefix)
|
||||
context.add(test)
|
||||
|
||||
# This one uses CalDAV/CardDAV in DAViCal and the same server config
|
||||
# with file backends as edsfile.
|
||||
test = SyncEvolutionTest("davfile",
|
||||
compile,
|
||||
"", options.shell,
|
||||
"Client::Sync::davical_caldav Client::Sync::davical_carddav Client::Sync::davical_caldav_davical_carddav",
|
||||
[ "davical_caldav", "davical_carddav" ],
|
||||
"CLIENT_TEST_SIMPLE_UID=1 " # DAViCal server gets confused by UID with special characters
|
||||
"CLIENT_TEST_WEBDAV='davical caldav carddav' "
|
||||
"CLIENT_TEST_NUM_ITEMS=10 "
|
||||
"CLIENT_TEST_LOG=syncevohttp.log "
|
||||
# could be enabled, but reporting result is currently missing (BMC #1009)
|
||||
# "CLIENT_TEST_RETRY=t "
|
||||
# "CLIENT_TEST_RESEND=t "
|
||||
# "CLIENT_TEST_SUSPEND=t "
|
||||
# server supports refresh-from-client, use it for
|
||||
# more efficient test setup
|
||||
"CLIENT_TEST_DELETE_REFRESH=1 "
|
||||
# server supports multiple cycles inside the same session
|
||||
"CLIENT_TEST_PEER_CAN_RESTART=1 "
|
||||
"CLIENT_TEST_SKIP="
|
||||
# server does not detect duplicates (uses file backend), detecting on the
|
||||
# client breaks syncing (see '[SyncEvolution] 409 "item merged" in client')
|
||||
# "Client::Sync::.*::testAddBothSides.*"
|
||||
,
|
||||
testPrefix=syncevoPrefix)
|
||||
context.add(test)
|
||||
|
||||
# EDS on client side, DAV on server.
|
||||
test = SyncEvolutionTest("edsdav",
|
||||
compile,
|
||||
"", options.shell,
|
||||
"Client::Sync::eds_event Client::Sync::eds_contact Client::Sync::eds_event_eds_contact",
|
||||
[ "eds_event", "eds_contact" ],
|
||||
"CLIENT_TEST_SIMPLE_UID=1 " # DAViCal server gets confused by UID with special characters
|
||||
"CLIENT_TEST_NUM_ITEMS=10 "
|
||||
"CLIENT_TEST_LOG=syncevohttp.log "
|
||||
# could be enabled, but reporting result is currently missing (BMC #1009)
|
||||
# "CLIENT_TEST_RETRY=t "
|
||||
# "CLIENT_TEST_RESEND=t "
|
||||
# "CLIENT_TEST_SUSPEND=t "
|
||||
# server supports refresh-from-client, use it for
|
||||
# more efficient test setup
|
||||
"CLIENT_TEST_DELETE_REFRESH=1 "
|
||||
# server supports multiple cycles inside the same session
|
||||
"CLIENT_TEST_PEER_CAN_RESTART=1 "
|
||||
"CLIENT_TEST_SKIP="
|
||||
# server does not detect duplicates (uses file backend), detecting on the
|
||||
# client breaks syncing (see '[SyncEvolution] 409 "item merged" in client')
|
||||
# "Client::Sync::.*::testAddBothSides.*"
|
||||
,
|
||||
testPrefix=syncevoPrefix)
|
||||
context.add(test)
|
||||
|
||||
scheduleworldtest = SyncEvolutionTest("scheduleworld", compile,
|
||||
|
|
Loading…
Reference in New Issue