WebDAV: improved --configure

Added INFO output about checking sources. This helps with WebDAV when
the server cannot be contacted (dead, misconfigured) because otherwise
there would be no indication at all why the --configure operation
seems to hang.

Here is some example output, including aborting:
$ syncevolution --configure --template webdav \
                syncURL=http://192.168.1.100:9000/ \
                username=foo password=bar retryDuration=2s \
                target-config@webdav-temp
[INFO] creating configuration target-config@webdav-temp
[INFO] addressbook: looking for databases...
[INFO] addressbook: no database to synchronize
[INFO] calendar: looking for databases...
[INFO] calendar: no database to synchronize
[INFO] memo: looking for databases...
[INFO] memo: no database to synchronize
[INFO] todo: looking for databases...
[INFO] todo: no database to synchronize

It timed out fairly quickly here because of the retryDuration=2s. That
also gets placed in the resulting config, which is probably not desired.

$ syncevolution --configure \
                --template webdav \
                syncURL=http://192.168.1.100:9000/ \
                username=foo password=bar \
                target-config@webdav-temp
[INFO] creating configuration target-config@webdav-temp
[INFO] addressbook: looking for databases...
^C[INFO] Asking to suspend...
[INFO] Press CTRL-C again quickly (within 2s) to stop immediately (can cause problems in the future!)
^C[INFO] Aborting immediately ...
[ERROR] error code from SyncEvolution aborted on behalf of user (local, status 20017): aborting as requested by user

It would be good to make the CTRL-C handling code aware that it can
abort immediately instead of doing the intermediate "asking to suspend"
step, which only makes sense for sync sessions.

Also added task and memo sources to the WebDAV template.

Both requires changes to the testing. Instead of updating the C++
CmdlineTest, the affected tests were removed and only the
corresponding Python tests were updated.
This commit is contained in:
Patrick Ohly 2012-06-20 12:34:19 +02:00
parent da9f577950
commit f418481057
3 changed files with 61 additions and 670 deletions

View File

@ -1102,6 +1102,12 @@ bool Cmdline::run() {
}
}
// TODO: update complete --configure output to be more informative.
// This is a first step, but shouldn't be done in isolation.
// SE_LOG_INFO(NULL, NULL, "%s configuration %s",
// fromScratch ? "creating" : "updating",
// to->getConfigName().c_str());
// copy and filter into the target config: createSyncClient()
// creates a SyncContext for m_server, with propert
// implementation of the password handling methods in derived
@ -1132,7 +1138,10 @@ bool Cmdline::run() {
sources.erase(entry);
}
// check whether the sync source works
// check whether the sync source works; this can
// take some time, so allow the user to abort
SE_LOG_INFO(NULL, NULL, "%s: looking for databases...",
source.c_str());
SyncSourceParams params(source, to->getSyncSourceNodes(source), to);
auto_ptr<SyncSource> syncSource(SyncSource::createSource(params, false, to.get()));
if (syncSource.get() == NULL) {
@ -1148,6 +1157,9 @@ bool Cmdline::run() {
}
}
s.checkForNormal();
SE_LOG_INFO(NULL, NULL, "%s: %s\n",
source.c_str(),
disable.empty() ? "okay" : disable.c_str());
}
// Do sanity checking of source (can it be enabled?),
@ -2248,30 +2260,6 @@ static string removeComments(const string &buffer)
return res.str();
}
// remove comment lines from scanFiles() output
static string filterFiles(const string &buffer)
{
ostringstream res;
typedef boost::split_iterator<string::const_iterator> string_split_iterator;
for (string_split_iterator it =
boost::make_split_iterator(buffer, boost::first_finder("\n", boost::is_iequal()));
it != string_split_iterator();
++it) {
string line = boost::copy_range<string>(*it);
if (line.find(":#") == line.npos) {
res << line;
// do not add extra newline after last newline
if (!line.empty() || it->end() < buffer.end()) {
res << endl;
}
}
}
return res.str();
}
static string injectValues(const string &buffer)
{
string res = buffer;
@ -2458,7 +2446,6 @@ class CmdlineTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testSetupFunambol);
CPPUNIT_TEST(testSetupSynthesis);
CPPUNIT_TEST(testPrintServers);
CPPUNIT_TEST(testPrintConfig);
CPPUNIT_TEST(testPrintFileTemplates);
CPPUNIT_TEST(testPrintFileTemplatesConfig);
CPPUNIT_TEST(testTemplate);
@ -2468,13 +2455,11 @@ class CmdlineTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testKeyring);
CPPUNIT_TEST(testWebDAV);
CPPUNIT_TEST(testConfigure);
CPPUNIT_TEST(testConfigureTemplates);
CPPUNIT_TEST(testConfigureSources);
CPPUNIT_TEST(testOldConfigure);
CPPUNIT_TEST(testMigrate);
CPPUNIT_TEST(testMigrateContext);
CPPUNIT_TEST(testMigrateAutoSync);
CPPUNIT_TEST(testItemOperations);
CPPUNIT_TEST_SUITE_END();
public:
@ -2983,203 +2968,6 @@ protected:
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
}
void testPrintConfig() {
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "templates");
ScopedEnvChange xdg("XDG_CONFIG_HOME", m_testDir);
ScopedEnvChange home("HOME", m_testDir);
testSetupFunambol();
{
TestCmdline failure("--print-config", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(!failure.m_cmdline->run());
CPPUNIT_ASSERT_NO_THROW(failure.expectUsageError("[ERROR] --print-config requires either a --template or a server name.\n"));
}
{
TestCmdline failure("--print-config", "foo", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(!failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL(string("[ERROR] Server 'foo' has not been configured yet.\n"),
failure.m_err.str());
}
{
TestCmdline failure("--print-config", "--template", "foo", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(!failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL(string("[ERROR] No configuration template for 'foo' available.\n"),
failure.m_err.str());
}
{
TestCmdline cmdline("--print-config", "--template", "scheduleworld", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string actual = cmdline.m_out.str();
// deviceId must be the one from Funambol
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
string filtered = injectValues(filterConfig(actual));
CPPUNIT_ASSERT_EQUAL_DIFF(filterConfig(internalToIni(ScheduleWorldConfig())),
filtered);
// there should have been comments
CPPUNIT_ASSERT(actual.size() > filtered.size());
}
{
TestCmdline cmdline("--print-config", "--template", "scheduleworld@nosuchcontext", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string actual = cmdline.m_out.str();
// deviceId must *not* be the one from Funambol because of the new context
CPPUNIT_ASSERT(!boost::contains(actual, "deviceId = fixed-devid"));
}
{
TestCmdline cmdline("--print-config", "--template", "Default", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
CPPUNIT_ASSERT_EQUAL_DIFF(filterConfig(internalToIni(DefaultConfig())),
actual);
}
{
TestCmdline cmdline("--print-config", "funambol", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF(filterConfig(internalToIni(FunambolConfig())),
injectValues(filterConfig(cmdline.m_out.str())));
}
{
// override context and template properties
TestCmdline cmdline("--print-config", "--template", "scheduleworld",
"syncURL=foo",
"database=Personal",
"--source-property", "sync=disabled",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string expected = filterConfig(internalToIni(ScheduleWorldConfig()));
boost::replace_first(expected,
"syncURL = http://sync.scheduleworld.com/funambol/ds",
"syncURL = foo");
boost::replace_all(expected,
"# database = ",
"database = Personal");
boost::replace_all(expected,
"sync = two-way",
"sync = disabled");
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
CPPUNIT_ASSERT_EQUAL_DIFF(expected,
actual);
}
{
// override context and template properties, using legacy property name
TestCmdline cmdline("--print-config", "--template", "scheduleworld",
"--sync-property", "syncURL=foo",
"--source-property", "evolutionsource=Personal",
"--source-property", "sync=disabled",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string expected = filterConfig(internalToIni(ScheduleWorldConfig()));
boost::replace_first(expected,
"syncURL = http://sync.scheduleworld.com/funambol/ds",
"syncURL = foo");
boost::replace_all(expected,
"# database = ",
"database = Personal");
boost::replace_all(expected,
"sync = two-way",
"sync = disabled");
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
CPPUNIT_ASSERT_EQUAL_DIFF(expected,
actual);
}
{
TestCmdline cmdline("--print-config", "--quiet",
"--template", "scheduleworld",
"funambol",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string actual = cmdline.m_out.str();
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
CPPUNIT_ASSERT_EQUAL_DIFF(internalToIni(ScheduleWorldConfig()),
injectValues(filterConfig(actual)));
}
{
// change shared source properties, then check template again
TestCmdline cmdline("--configure",
"--source-property", "database=Personal",
"funambol",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
}
{
TestCmdline cmdline("--print-config", "--quiet",
"--template", "scheduleworld",
"funambol",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
string expected = filterConfig(internalToIni(ScheduleWorldConfig()));
// from modified Funambol config
boost::replace_all(expected,
"# database = ",
"database = Personal");
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(boost::contains(actual, "deviceId = fixed-devid"));
CPPUNIT_ASSERT_EQUAL_DIFF(expected,
actual);
}
{
// print config => must not use settings from default context
TestCmdline cmdline("--print-config", "--template", "scheduleworld@nosuchcontext", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
// source settings *not* from modified Funambol config
string expected = filterConfig(internalToIni(ScheduleWorldConfig()));
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(!boost::contains(actual, "deviceId = fixed-devid"));
removeRandomUUID(actual);
CPPUNIT_ASSERT_EQUAL_DIFF(expected,
actual);
}
{
// create config => again, must not use settings from default context
TestCmdline cmdline("--configure", "--template", "scheduleworld", "other@other", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
}
{
TestCmdline cmdline("--print-config", "other@other", NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
// source settings *not* from modified Funambol config
string expected = filterConfig(internalToIni(ScheduleWorldConfig()));
string actual = injectValues(filterConfig(cmdline.m_out.str()));
CPPUNIT_ASSERT(!boost::contains(actual, "deviceId = fixed-devid"));
removeRandomUUID(actual);
CPPUNIT_ASSERT_EQUAL_DIFF(expected,
actual);
}
}
void testPrintFileTemplates() {
// use local copy of templates in build dir (no need to install)
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "./templates");
@ -3561,7 +3349,15 @@ protected:
"foobar@default", NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str());
CPPUNIT_ASSERT_EQUAL(std::string("[ERROR] Unsupported value for the \"keyring\" property, no such keyring found: no-such-keyring"),
CPPUNIT_ASSERT_EQUAL(std::string("[INFO] addressbook: looking for databases...\n"
"[INFO] addressbook: okay\n"
"[INFO] calendar: looking for databases...\n"
"[INFO] calendar: okay\n"
"[INFO] memo: looking for databases...\n"
"[INFO] memo: okay\n"
"[INFO] todo: looking for databases...\n"
"[INFO] todo: okay\n"
"[ERROR] Unsupported value for the \"keyring\" property, no such keyring found: no-such-keyring"),
cmdline.m_err.str());
}
}
@ -3851,230 +3647,6 @@ protected:
}
}
/**
* Test semantic of config creation (instead of updating) with and without
* templates. See BMC #14805.
*/
void testConfigureTemplates() {
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "templates");
ScopedEnvChange xdg("XDG_CONFIG_HOME", m_testDir);
ScopedEnvChange home("HOME", m_testDir);
rm_r(m_testDir);
{
// catch possible typos like "sheduleworld"
TestCmdline failure("--configure", "foo", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(!failure.m_cmdline->run());
static const char error[] = "[ERROR] No configuration template for 'foo@default' available.\n"
"[INFO] Use '--template none' and/or specify relevant properties on the command line to create a configuration without a template. Need values for: syncURL\n"
"[INFO] \n"
"[INFO] Available configuration templates (clients and servers):\n";
std::string out = failure.m_out.str();
std::string err = failure.m_err.str();
std::string all = failure.m_all.str();
CPPUNIT_ASSERT(boost::starts_with(err, error));
CPPUNIT_ASSERT(boost::ends_with(err, "\n"));
CPPUNIT_ASSERT(!boost::ends_with(err, "\n\n"));
CPPUNIT_ASSERT_EQUAL(string(""), out);
CPPUNIT_ASSERT_EQUAL(all, err);
}
rm_r(m_testDir);
{
// catch possible typos like "sheduleworld" when
// enough properties are specified to continue without
// a template
TestCmdline failure("--configure", "syncURL=http://foo.com", "--template", "foo", "bar", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(!failure.m_cmdline->run());
static const char error[] = "[ERROR] No configuration template for 'foo' available.\n"
"[INFO] All relevant properties seem to be set, omit the --template parameter to proceed.\n"
"[INFO] \n"
"[INFO] Available configuration templates (clients and servers):\n";
std::string out = failure.m_out.str();
std::string err = failure.m_err.str();
std::string all = failure.m_all.str();
CPPUNIT_ASSERT(boost::starts_with(err, error));
CPPUNIT_ASSERT(boost::ends_with(err, "\n"));
CPPUNIT_ASSERT(!boost::ends_with(err, "\n\n"));
CPPUNIT_ASSERT_EQUAL(string(""), out);
CPPUNIT_ASSERT_EQUAL(all, err);
}
string fooconfig =
StringPrintf("syncevolution/.internal.ini:rootMinVersion = %d\n"
"syncevolution/.internal.ini:rootCurVersion = %d\n"
"syncevolution/default/.internal.ini:contextMinVersion = %d\n"
"syncevolution/default/.internal.ini:contextCurVersion = %d\n"
"syncevolution/default/config.ini:deviceId = fixed-devid\n"
"syncevolution/default/peers/foo/.internal.ini:peerMinVersion = %d\n"
"syncevolution/default/peers/foo/.internal.ini:peerCurVersion = %d\n",
CONFIG_ROOT_MIN_VERSION, CONFIG_ROOT_CUR_VERSION,
CONFIG_CONTEXT_MIN_VERSION, CONFIG_CONTEXT_CUR_VERSION,
CONFIG_PEER_MIN_VERSION, CONFIG_PEER_CUR_VERSION);
string syncurl =
"syncevolution/default/peers/foo/config.ini:syncURL = local://@bar\n";
string configsource =
"syncevolution/default/peers/foo/sources/eds_event/config.ini:sync = two-way\n"
"syncevolution/default/sources/eds_event/config.ini:backend = calendar\n";
rm_r(m_testDir);
{
// allow user to proceed if they wish: should result in no sources configured
TestCmdline failure("--configure", "--template", "none", "foo", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
bool success = failure.m_cmdline->run();
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
CPPUNIT_ASSERT(success);
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they wish: should result in no sources configured,
// even if general source properties are specified
TestCmdline failure("--configure", "--template", "none", "backend=calendar", "foo", NULL);
bool success = failure.m_cmdline->parse() && failure.m_cmdline->run();
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
CPPUNIT_ASSERT(success);
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they wish: should result in no sources configured,
// even if specific source properties are specified
TestCmdline failure("--configure", "--template", "none", "eds_event/backend=calendar", "foo", NULL);
bool success = failure.m_cmdline->parse() && failure.m_cmdline->run();
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
CPPUNIT_ASSERT(success);
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they wish and possible: here eds_event is not usable
TestCmdline failure("--configure", "--template", "none", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
bool caught = false;
try {
CPPUNIT_ASSERT(failure.m_cmdline->run());
} catch (const StatusException &ex) {
if (!strcmp(ex.what(), "eds_event: no backend available")) {
caught = true;
} else {
throw;
}
}
CPPUNIT_ASSERT(caught);
}
rm_r(m_testDir);
{
// allow user to proceed if they wish and possible: here eds_event is not configurable
TestCmdline failure("--configure", "syncURL=local://@bar", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
bool caught = false;
try {
CPPUNIT_ASSERT(failure.m_cmdline->run());
} catch (const StatusException &ex) {
if (!strcmp(ex.what(), "no such source(s): eds_event")) {
caught = true;
} else {
throw;
}
}
CPPUNIT_ASSERT(caught);
}
rm_r(m_testDir);
{
// allow user to proceed if they wish and possible: here eds_event is not configurable (wrong context)
TestCmdline failure("--configure", "syncURL=local://@bar", "eds_event/backend@xyz=calendar", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
bool caught = false;
try {
CPPUNIT_ASSERT(failure.m_cmdline->run());
} catch (const StatusException &ex) {
if (!strcmp(ex.what(), "no such source(s): eds_event")) {
caught = true;
} else {
throw;
}
}
CPPUNIT_ASSERT(caught);
}
rm_r(m_testDir);
{
// allow user to proceed if they wish: configure exactly the specified sources
TestCmdline failure("--configure", "--template", "none", "backend=calendar", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig + configsource, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they provide enough information: should result in no sources configured
TestCmdline failure("--configure", "syncURL=local://@bar", "foo", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig + syncurl, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they provide enough information;
// source created because listed and usable
TestCmdline failure("--configure", "syncURL=local://@bar", "backend=calendar", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig + syncurl + configsource, filterFiles(res));
}
rm_r(m_testDir);
{
// allow user to proceed if they provide enough information;
// source created because listed and usable
TestCmdline failure("--configure", "syncURL=local://@bar", "eds_event/backend@default=calendar", "foo", "eds_event", NULL);
CPPUNIT_ASSERT(failure.m_cmdline->parse());
CPPUNIT_ASSERT(failure.m_cmdline->run());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure.m_err.str());
string res = scanFiles(m_testDir);
removeRandomUUID(res);
CPPUNIT_ASSERT_EQUAL_DIFF(fooconfig + syncurl + configsource, filterFiles(res));
}
}
void testConfigureSources() {
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "templates");
ScopedEnvChange xdg("XDG_CONFIG_HOME", m_testDir);
@ -4689,206 +4261,6 @@ protected:
}
}
void testItemOperations() {
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "templates");
ScopedEnvChange xdg("XDG_CONFIG_HOME", m_testDir);
ScopedEnvChange home("HOME", m_testDir);
{
// "foo" not configured
TestCmdline cmdline("--print-items",
"foo",
"bar",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] bar: backend not supported or not correctly configured (backend=select backend databaseFormat= syncFormat=)\nconfiguration 'foo' does not exist\nsource 'bar' does not exist\nbackend property not set", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// "foo" not configured, no source named
TestCmdline cmdline("--print-items",
"foo",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] backend not supported or not correctly configured (backend=select backend databaseFormat= syncFormat=)\nconfiguration 'foo' does not exist\nno source selected\nbackend property not set", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// nothing known about source
TestCmdline cmdline("--print-items",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] backend not supported or not correctly configured (backend=select backend databaseFormat= syncFormat=)\nno source selected\nbackend property not set", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// now create foo
TestCmdline cmdline("--configure",
"--template",
"default",
"foo",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// "foo" now configured, still no source
TestCmdline cmdline("--print-items",
"foo",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] backend not supported or not correctly configured (backend=select backend databaseFormat= syncFormat=)\nno source selected\nbackend property not set", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// foo configured, but "bar" is not
TestCmdline cmdline("--print-items",
"foo",
"bar",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] bar: backend not supported or not correctly configured (backend=select backend databaseFormat= syncFormat=)\nsource 'bar' does not exist\nbackend property not set", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// add "bar" source, using file backend
TestCmdline cmdline("--configure",
"backend=file",
("database=file://" + m_testDir + "/addressbook").c_str(),
"databaseFormat=text/vcard",
"foo",
"bar",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
{
// no items yet
TestCmdline cmdline("--print-items",
"foo",
"bar",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_out.str());
}
static const std::string john =
"BEGIN:VCARD\n"
"VERSION:3.0\n"
"FN:John Doe\n"
"N:Doe;John;;;\n"
"END:VCARD\n",
joan =
"BEGIN:VCARD\n"
"VERSION:3.0\n"
"FN:Joan Doe\n"
"N:Doe;Joan;;;\n"
"END:VCARD\n";
{
// create one file
std::string file1 = "1:" + john, file2 = "2:" + joan;
boost::replace_all(file1, "\n", "\n1:");
file1.resize(file1.size() - 2);
boost::replace_all(file2, "\n", "\n2:");
file2.resize(file2.size() - 2);
createFiles(m_testDir + "/addressbook", file1 + file2);
TestCmdline cmdline("--print-items",
"foo",
"bar",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("1\n2\n", cmdline.m_out.str());
}
{
// alternatively just specify enough parameters,
// without the foo bar config part
TestCmdline cmdline("--print-items",
"backend=file",
("database=file://" + m_testDir + "/addressbook").c_str(),
"databaseFormat=text/vcard",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF("1\n2\n", cmdline.m_out.str());
}
{
// export all
TestCmdline cmdline("--export", "-",
"backend=file",
("database=file://" + m_testDir + "/addressbook").c_str(),
"databaseFormat=text/vcard",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF(john + "\n" + joan, cmdline.m_out.str());
}
{
// export all via config
TestCmdline cmdline("--export", "-",
"foo", "bar",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF(john + "\n" + joan, cmdline.m_out.str());
}
{
// export one
TestCmdline cmdline("--export", "-",
"backend=file",
("database=file://" + m_testDir + "/addressbook").c_str(),
"databaseFormat=text/vcard",
"--luids", "1",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF(john, cmdline.m_out.str());
}
{
// export one via config
TestCmdline cmdline("--export", "-",
"foo", "bar", "1",
NULL);
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("", cmdline.m_err.str());
CPPUNIT_ASSERT_EQUAL_DIFF(john, cmdline.m_out.str());
}
// TODO: check configuration of just the source as @foo bar without peer
{
// check error message for missing config name
TestCmdline cmdline((const char *)NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_NO_THROW(cmdline.expectUsageError("[ERROR] No configuration name specified.\n"));
}
{
// check error message for missing config name, version II
TestCmdline cmdline("--run",
NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_NO_THROW(cmdline.expectUsageError("[ERROR] No configuration name specified.\n"));
}
}
const string m_testDir;
private:

View File

@ -16,3 +16,12 @@ backend = CardDAV
=== sources/calendar/config.ini ===
sync = two-way
backend = CalDAV
=== sources/memo/config.ini ===
sync = two-way
backend = CalDAVJournal
=== sources/todo/config.ini ===
sync = two-way
backend = CalDAVTodo

View File

@ -4335,6 +4335,12 @@ class TestCmdline(DBusUtil, unittest.TestCase):
return (out, err, s.returncode)
def sourceCheckOutput(self, sources=['addressbook', 'calendar', 'memo', 'todo']):
'''returns the output produced by --configure when checking sources'''
if not (isinstance(sources, type([])) or isinstance(sources, type(()))):
sources = (sources,)
return ''.join(['[INFO] %s: looking for databases...\n[INFO] %s: okay\n' % (i, i) for i in sources])
def assertNoErrors(self, err):
'''check that error output is empty'''
self.assertEqualDiff('', err)
@ -4864,9 +4870,11 @@ spds/sources/todo/config.txt:# evolutionpassword =
self.assertRegexpMatches(rootMin, r'^\d+$', 'Peer min version is not a number.')
self.assertRegexpMatches(rootCur, r'^\d+$', 'Root cur version is not a number.')
def assertSilent(self, out, err):
def assertSilent(self, out, err, ignore=None):
if err != None and \
os.environ.get('SYNCEVOLUTION_DEBUG', None) == None:
if ignore:
err = err.replace(ignore, "", 1)
self.assertNoErrors(err)
self.assertEqualDiff('', out)
@ -4883,7 +4891,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
out, err, code = self.runCmdline(['--configure',
'--sync-property', 'proxyHost = proxy',
'scheduleworld', 'addressbook'])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('addressbook'))
res = sortConfig(scanFiles(root))
res = self.removeRandomUUID(res)
expected = self.ScheduleWorldConfig()
@ -4902,7 +4910,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
out, err, code = self.runCmdline(['--configure',
'--sync-property', 'deviceId = fixed-devid',
'scheduleworld'])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = sortConfig(scanFiles(root))
expected = self.ScheduleWorldConfig()
expected = sortConfig(expected)
@ -4921,7 +4929,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
'--template', 'default',
'--sync-property', 'deviceId = fixed-devid',
'some-other-server'])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = scanFiles(root, 'some-other-server')
expected = sortConfig(self.DefaultConfig()).replace('/syncevolution/', '/some-other-server/')
self.assertEqualDiff(expected, res)
@ -4940,7 +4948,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
"--template", "scheduleworld",
"--sync-property", "deviceId = fixed-devid",
"scheduleworld2"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = scanFiles(root, "scheduleworld2")
expected = sortConfig(self.ScheduleWorldConfig()).replace("/scheduleworld/", "/scheduleworld2/")
self.assertEqualDiff(expected, res)
@ -4959,7 +4967,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
args.append("FunamBOL")
out, err, code = self.runCmdline(args)
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = scanFiles(root, "funambol")
expected = sortConfig(self.FunambolConfig())
self.assertEqualDiff(expected, res)
@ -4983,7 +4991,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
args.append("synthesis")
out, err, code = self.runCmdline(args)
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = scanFiles(root, "synthesis")
expected = sortConfig(self.SynthesisConfig())
self.assertEqualDiff(expected, res)
@ -5197,7 +5205,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
# create config => again, must not use settings from default context
out, err, code = self.runCmdline(["--configure", "--template", "scheduleworld", "other@other"])
self.assertEqualDiff("", err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
out, err, code = self.runCmdline(["--print-config", "other@other"])
self.assertEqualDiff("", err)
@ -5420,7 +5428,8 @@ sources/xyz/config.ini:# databasePassword = """)
out, err, code = self.runCmdline(["--configure",
"--template", "yahoo",
"target-config@my-yahoo"])
self.assertSilent(out, err)
# TODO: why does it check 'addressbook'? It's disabled in the template.
self.assertSilent(out, err, ignore=self.sourceCheckOutput(['addressbook', 'calendar']))
out, err, code = self.runCmdline(["--print-config", "target-config@my-yahoo"])
self.assertNoErrors(err)
@ -5435,7 +5444,7 @@ sources/xyz/config.ini:# databasePassword = """)
# configure Google Calendar with template derived from config name
out, err, code = self.runCmdline(["--configure",
"target-config@google-calendar"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('calendar'))
out, err, code = self.runCmdline(["--print-config", "target-config@google-calendar"])
self.assertNoErrors(err)
@ -5483,7 +5492,7 @@ sources/xyz/config.ini:# databasePassword = """)
out, err, code = self.runCmdline(["--configure",
"--source-property", "sync = disabled",
"scheduleworld"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
expected = filterConfig(internalToIni(config)).replace("sync = two-way",
"sync = disabled")
self.assertEqualDiff(expected,
@ -5834,7 +5843,8 @@ syncevolution/default/sources/eds_event/config.ini:backend = calendar
expectSuccess = False)
self.assertEqualDiff('', out)
err = stripOutput(err)
self.assertEqualDiff('[ERROR] error code from SyncEvolution fatal error (local, status 10500): eds_event: no backend available\n', err)
self.assertEqualDiff(self.sourceCheckOutput('eds_event').replace('okay', 'no backend available') +
'[ERROR] error code from SyncEvolution fatal error (local, status 10500): eds_event: no backend available\n', err)
shutil.rmtree(self.configdir, True)
# allow user to proceed if they wish and possible: here
@ -5858,7 +5868,7 @@ syncevolution/default/sources/eds_event/config.ini:backend = calendar
# allow user to proceed if they wish: configure exactly the
# specified sources
out, err, code = self.runCmdline(["--configure", "--template", "none", "backend=calendar", "foo", "eds_event"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('eds_event'))
res = filterFiles(self.removeRandomUUID(scanFiles(xdg_config)))
self.assertEqualDiff(fooconfig + configsource, res)
@ -5874,7 +5884,7 @@ syncevolution/default/sources/eds_event/config.ini:backend = calendar
# allow user to proceed if they provide enough information:
# source created because listed and usable
out, err, code = self.runCmdline(["--configure", "syncURL=local://@bar", "backend=calendar", "foo", "eds_event"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('eds_event'))
res = filterFiles(self.removeRandomUUID(scanFiles(xdg_config)))
self.assertEqualDiff(fooconfig + syncurl + configsource, res)
@ -5882,7 +5892,7 @@ syncevolution/default/sources/eds_event/config.ini:backend = calendar
# allow user to proceed if they provide enough information:
# source created because listed and usable
out, err, code = self.runCmdline(["--configure", "syncURL=local://@bar", "eds_event/backend@default=calendar", "foo", "eds_event"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('eds_event'))
res = filterFiles(self.removeRandomUUID(scanFiles(xdg_config)))
self.assertEqualDiff(fooconfig + syncurl + configsource, res)
@ -5895,7 +5905,7 @@ syncevolution/default/sources/eds_event/config.ini:backend = calendar
"--source-property", "type = file:text/x-vcard",
"@foobar",
"addressbook"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('addressbook'))
root = self.configdir + "/foobar"
res = self.removeRandomUUID(scanFiles(root))
@ -5933,7 +5943,7 @@ sources/calendar/config.ini:# databasePassword =
# add ScheduleWorld peer: must reuse existing backend settings
out, err, code = self.runCmdline(["--configure",
"scheduleworld@foobar"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
res = self.removeRandomUUID(scanFiles(root))
expected = self.ScheduleWorldConfig()
@ -5969,7 +5979,7 @@ sources/calendar/config.ini:# databasePassword =
"--source-property", "addressbook/type=file:text/vcard:3.0",
"--source-property", "calendar/type=file:text/calendar:2.0",
"syncevo@syncevo"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
syncevoroot = self.configdir + "/syncevo"
res = scanFiles(syncevoroot + "/sources/addressbook")
@ -6009,7 +6019,7 @@ sources/calendar/config.ini:# databasePassword =
if haveEDS:
# limit output to one specific backend, chosen via config
out, err, code = self.runCmdline(["--configure", "backend=evolution-contacts", "@foo-config", "bar-source"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput('bar-source'))
out, err, code = self.runCmdline(["--print-databases", "@foo-config", "bar-source"])
self.assertNoErrors(err)
self.assertTrue(out.startswith("@foo-config/bar-source:\n"))
@ -6483,7 +6493,7 @@ sources/memo/config.ini:type = todo
out, err, code = self.runCmdline(["--configure",
"--template", "default",
"foo"])
self.assertSilent(out, err)
self.assertSilent(out, err, ignore=self.sourceCheckOutput())
# "foo" now configured, still no source
out, err, code = self.runCmdline(["--print-items",