sync modes: added refresh/one-way-from-local/remote (BMC #23537)

The -from-client/server sync modes are confusing because the direction
of the data exchange depends on which side acts as SyncML server or
client.

This patch introduces new modes which use -from-local/remote
instead. The statistics and messages also use these variants now. The
old modes are still understood, but are declared as "not recommended"
in the documentation.
This commit is contained in:
Patrick Ohly 2011-10-24 19:52:01 +02:00
parent 741d55e8bf
commit 8c89db5b0f
11 changed files with 370 additions and 124 deletions

View File

@ -415,9 +415,9 @@ the right database dumps for the selected sources.
A restore tries to minimize the number of item changes (see section
`Item Changes and Data Changes`_). This means that items that are
identical before and after the change will not be transmitted anew to
the server during the next synchronization. If the server somehow
needs to get a clean copy of all items on the client then, use "--sync
refresh-from-client" in the next run. ::
the peer during the next synchronization. If the peer somehow
needs to get a clean copy of all local items, then use ``--sync
refresh-from-local`` in the next run. ::
syncevolution --print-items <config> <source>
syncevolution [--delimiter <string>] --export <dir>|<file>|- <config> <source> [<luid> ...]
@ -451,17 +451,12 @@ a list of valid values.
--sync|-s <mode>|?
Temporarily synchronize the active sources in that mode. Useful
for a `refresh-from-server` or `refresh-from-client` sync which
for a `refresh-from-local` or `refresh-from-remote` sync which
clears all data at one end and copies all items from the other.
**Warning:** in local sync (`CalDAV and CardDAV`_/ActiveSync, ...) and
direct sync with a phone, the sync is started by the side which acts
as server. Therefore the ``from-server`` variants
(``one-way-from-server``, ``refresh-from-server``) transfer data
from the sync config into the target config (see "Synchronization
beyond SyncML" below) resp. to a phone. The ``from-client`` variants
transfer in the other direction, even if the target config happens
to access data on a remote server.
**Warning:** `local` is the data accessed via the sync config
directly and `remote` is the data on the peer, regardless
where the data is actually stored physically.
--print-servers|--print-configs|--print-peers
Prints the names of all configured peers to stdout. There is no

View File

@ -1464,7 +1464,7 @@ bool Cmdline::run() {
context->getSyncSources()) {
boost::shared_ptr<PersistentSyncSourceConfig> source_config =
context->getSyncSourceConfig(source);
if (source_config->getSync() != "disabled") {
if (!source_config->isDisabled()) {
context->setConfigFilter(false, source, m_props.createSourceFilter(m_server, source));
}
}
@ -3159,7 +3159,7 @@ protected:
TestCmdline failure2("--sync", "foo", NULL);
CPPUNIT_ASSERT(!failure2.m_cmdline->parse());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure2.m_out.str());
CPPUNIT_ASSERT_EQUAL(string("ERROR: '--sync foo': not one of the valid values (two-way, slow, refresh-from-client = refresh-client, refresh-from-server = refresh-server = refresh, one-way-from-client = one-way-client, one-way-from-server = one-way-server = one-way, disabled = none)\n"), lastLine(failure2.m_err.str()));
CPPUNIT_ASSERT_EQUAL(string("ERROR: '--sync foo': not one of the valid values (two-way, slow, refresh-from-local, refresh-from-remote = refresh, one-way-from-local, one-way-from-remote = one-way, refresh-from-client = refresh-client, refresh-from-server = refresh-server, one-way-from-client = one-way-client, one-way-from-server = one-way-server, disabled = none)\n"), lastLine(failure2.m_err.str()));
TestCmdline help("--sync", " ?", NULL);
help.doit();
@ -3170,19 +3170,23 @@ protected:
" only send/receive changes since last sync\n"
" slow\n"
" exchange all items\n"
" refresh-from-client\n"
" discard all remote items and replace with the items on the client\n"
" refresh-from-server\n"
" discard all local items and replace with the items on the server\n"
" one-way-from-client\n"
" transmit changes from client\n"
" one-way-from-server\n"
" transmit changes from server\n"
" refresh-from-remote\n"
" discard all local items and replace with\n"
" the items on the peer\n"
" refresh-from-local\n"
" discard all items on the peer and replace\n"
" with the local items\n"
" one-way-from-remote\n"
" transmit changes from peer\n"
" one-way-from-local\n"
" transmit local changes\n"
" disabled (or none)\n"
" synchronization disabled\n"
" \n"
" **WARNING**: which side is `client` and which is `server` depends on\n"
" the value of the ``peerIsClient`` property in the configuration.\n"
" refresh/one-way-from-server/client are also supported. Their use is\n"
" discouraged because the direction of the data transfer depends\n"
" on the role of the local side (can be server or client), which is\n"
" not always obvious.\n"
" \n"
" When accepting a sync session in a SyncML server (HTTP server), only\n"
" sources with sync != disabled are made available to the client,\n"

View File

@ -284,7 +284,7 @@ void LocalTransportAgent::run()
BOOST_FOREACH(const string &sourceName, m_server->getSyncSources()) {
SyncSourceNodes nodes = m_server->getSyncSourceNodesNoTracking(sourceName);
SyncSourceConfig source(sourceName, nodes);
string sync = source.getSync();
std::string sync = source.getSync();
if (sync != "disabled") {
string targetName = source.getURINonEmpty();
SyncSourceNodes targetNodes = m_client->getSyncSourceNodes(targetName);
@ -304,13 +304,23 @@ void LocalTransportAgent::run()
// so none of the regular config nodes have to
// be written. If a sync mode was set, it must have been
// done before in this loop => error in original config.
if (string(targetSource.getSync()) != "disabled") {
if (!targetSource.isDisabled()) {
m_client->throwError(StringPrintf("%s: source targetted twice by %s",
fullTargetName.c_str(),
m_clientContext.c_str()));
}
targetSource.setSync(sync.c_str(), true);
targetSource.setURI(sourceName.c_str(), true);
// invert data direction
if (sync == "refresh-from-local") {
sync = "refresh-from-remote";
} else if (sync == "refresh-from-remote") {
sync = "refresh-from-local";
} else if (sync == "one-way-from-local") {
sync = "one-way-from-remote";
} else if (sync == "one-way-from-remote") {
sync = "one-way-from-local";
}
targetSource.setSync(sync, true);
targetSource.setURI(sourceName, true);
}
}

View File

@ -2153,20 +2153,24 @@ StringConfigProperty SyncSourceConfig::m_sourcePropSync("sync",
" only send/receive changes since last sync\n"
" slow\n"
" exchange all items\n"
" refresh-from-client\n"
" discard all remote items and replace with the items on the client\n"
" refresh-from-server\n"
" discard all local items and replace with the items on the server\n"
" one-way-from-client\n"
" transmit changes from client\n"
" one-way-from-server\n"
" transmit changes from server\n"
" refresh-from-remote\n"
" discard all local items and replace with\n"
" the items on the peer\n"
" refresh-from-local\n"
" discard all items on the peer and replace\n"
" with the local items\n"
" one-way-from-remote\n"
" transmit changes from peer\n"
" one-way-from-local\n"
" transmit local changes\n"
" disabled (or none)\n"
" synchronization disabled\n\n"
"**WARNING**: which side is `client` and which is `server` depends on\n"
"the value of the ``peerIsClient`` property in the configuration.\n\n"
" synchronization disabled\n"
"\n"
"refresh/one-way-from-server/client are also supported. Their use is\n"
"discouraged because the direction of the data transfer depends\n"
"on the role of the local side (can be server or client), which is\n"
"not always obvious.\n"
"\n"
"When accepting a sync session in a SyncML server (HTTP server), only\n"
"sources with sync != disabled are made available to the client,\n"
"which chooses the final sync mode based on its own configuration.\n"
@ -2178,10 +2182,16 @@ StringConfigProperty SyncSourceConfig::m_sourcePropSync("sync",
Values() +
(Aliases("two-way")) +
(Aliases("slow")) +
(Aliases("refresh-from-local")) +
(Aliases("refresh-from-remote") + "refresh") +
(Aliases("one-way-from-local")) +
(Aliases("one-way-from-remote") + "one-way") +
(Aliases("refresh-from-client") + "refresh-client") +
(Aliases("refresh-from-server") + "refresh-server" + "refresh") +
(Aliases("refresh-from-server") + "refresh-server") +
(Aliases("one-way-from-client") + "one-way-client") +
(Aliases("one-way-from-server") + "one-way-server" + "one-way") +
(Aliases("one-way-from-server") + "one-way-server") +
(Aliases("disabled") + "none"));
static class SourceBackendConfigProperty : public StringConfigProperty {

View File

@ -1985,6 +1985,9 @@ class SyncSourceConfig {
virtual std::string getSync() const;
virtual void setSync(const std::string &value, bool temporarily = false);
/** shortcut for checking sync mode against "disabled" */
bool isDisabled() { return getSync() == "disabled"; }
private:
std::string m_name;
SyncSourceNodes m_nodes;

View File

@ -1577,8 +1577,9 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
extra2=1 for resumed session,
extra3 0=twoway, 1=fromserver, 2=fromclient */
// -1 is used for alerting a restore from backup. Synthesis won't use this
bool peerIsClient = getPeerIsClient();
if (extra1 != -1) {
SE_LOG_INFO(NULL, NULL, "%s: %s %s sync%s",
SE_LOG_INFO(NULL, NULL, "%s: %s %s sync%s (%s)",
source.getDisplayName().c_str(),
extra2 ? "resuming" : "starting",
extra1 == 0 ? "normal" :
@ -1588,31 +1589,34 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
extra3 == 0 ? ", two-way" :
extra3 == 1 ? " from server" :
extra3 == 2 ? " from client" :
", unknown direction");
", unknown direction",
peerIsClient ? "peer is client" : "peer is server");
SyncMode mode = SYNC_NONE;
SimpleSyncMode mode = SIMPLE_SYNC_NONE;
std::string sync = source.getSync();
switch (extra1) {
case 0:
switch (extra3) {
case 0:
mode = SYNC_TWO_WAY;
mode = SIMPLE_SYNC_TWO_WAY;
if (m_serverMode &&
m_serverAlerted &&
source.getSync() == "one-way-from-server") {
(sync == "one-way-from-server" ||
sync == "one-way-from-local")) {
// As in the slow/refresh-from-server case below,
// pretending to do a two-way incremental sync
// is a correct way of executing the requested
// one-way sync, as long as the client doesn't
// send any of its own changes. The Synthesis
// engine does that.
mode = SYNC_ONE_WAY_FROM_SERVER;
mode = SIMPLE_SYNC_ONE_WAY_FROM_LOCAL;
}
break;
case 1:
mode = SYNC_ONE_WAY_FROM_SERVER;
mode = peerIsClient ? SIMPLE_SYNC_ONE_WAY_FROM_LOCAL : SIMPLE_SYNC_ONE_WAY_FROM_REMOTE;
break;
case 2:
mode = SYNC_ONE_WAY_FROM_CLIENT;
mode = peerIsClient ? SIMPLE_SYNC_ONE_WAY_FROM_REMOTE : SIMPLE_SYNC_ONE_WAY_FROM_LOCAL;
break;
}
break;
@ -1620,28 +1624,29 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
case 2:
switch (extra3) {
case 0:
mode = SYNC_SLOW;
mode = SIMPLE_SYNC_SLOW;
if (m_serverMode &&
m_serverAlerted &&
source.getSync() == "refresh-from-server") {
(sync == "refresh-from-server" ||
sync == "refresh-from-local")) {
// We run as server and told the client to refresh
// its data. A slow sync is how some clients (the
// Synthesis engine included) execute that sync mode;
// let's be optimistic and assume that the client
// did as it was told and deleted its data.
mode = SYNC_REFRESH_FROM_SERVER;
mode = SIMPLE_SYNC_REFRESH_FROM_LOCAL;
}
break;
case 1:
mode = SYNC_REFRESH_FROM_SERVER;
mode = peerIsClient ? SIMPLE_SYNC_REFRESH_FROM_LOCAL : SIMPLE_SYNC_REFRESH_FROM_REMOTE;
break;
case 2:
mode = SYNC_REFRESH_FROM_CLIENT;
mode = peerIsClient ? SIMPLE_SYNC_REFRESH_FROM_REMOTE : SIMPLE_SYNC_REFRESH_FROM_LOCAL;
break;
}
break;
}
source.recordFinalSyncMode(mode);
source.recordFinalSyncMode(SyncMode(mode));
source.recordFirstSync(extra1 == 2);
source.recordResumeSync(extra2 == 1);
} else {
@ -1759,7 +1764,8 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
// refresh-from-server/client. That's a matter of
// taste. In SyncEvolution we'd like these
// items to show up, so add it here.
source.getFinalSyncMode() == (m_serverMode ? SYNC_REFRESH_FROM_CLIENT : SYNC_REFRESH_FROM_SERVER) ?
(source.getFinalSyncMode() == (m_serverMode ? SYNC_REFRESH_FROM_CLIENT : SYNC_REFRESH_FROM_SERVER) ||
source.getFinalSyncMode() == SYNC_REFRESH_FROM_REMOTE) ?
source.getNumDeleted() :
extra3);
break;
@ -1950,10 +1956,8 @@ void SyncContext::initSources(SourceList &sourceList)
BOOST_FOREACH(const string &name, configuredSources) {
boost::shared_ptr<PersistentSyncSourceConfig> sc(getSyncSourceConfig(name));
SyncSourceNodes source = getSyncSourceNodes (name);
// is the source enabled?
string sync = sc->getSync();
bool enabled = sync != "disabled";
if (enabled) {
std::string sync = sc->getSync();
if (sync != "disabled") {
SourceType sourceType = SyncSource::getSourceType(source);
if (sourceType.m_backend == "virtual") {
//This is a virtual sync source, check and enable the referenced
@ -1995,11 +1999,7 @@ void SyncContext::initSources(SourceList &sourceList)
boost::shared_ptr<PersistentSyncSourceConfig> sc(getSyncSourceConfig(name));
SyncSourceNodes source = getSyncSourceNodes (name);
// is the source enabled?
string sync = sc->getSync();
bool enabled = sync != "disabled";
if (enabled) {
if (!sc->isDisabled()) {
SourceType sourceType = SyncSource::getSourceType(source);
if (sourceType.m_backend != "virtual") {
SyncSourceParams params(name,
@ -2430,9 +2430,13 @@ void SyncContext::getConfigXML(string &xml, string &configname)
// we *want* a slow sync, but couldn't tell the client -> force it server-side
datastores << " <alertscript> FORCESLOWSYNC(); </alertscript>\n";
} else if (mode != "slow" &&
mode != "refresh-from-server" && // is implemented as "delete local data" + "slow sync",
// so a slow sync is acceptable in this case
// slow-sync detection not implemented when running as server,
// not even when initiating the sync (direct sync with phone)
!m_serverMode &&
// is implemented as "delete local data" + "slow sync",
// so a slow sync is acceptable in this case
mode != "refresh-from-server" &&
mode != "refresh-from-remote" &&
// The forceSlow should be disabled if the sync session is
// initiated by a remote peer (eg. Server Alerted Sync)
!m_remoteInitiated &&
@ -3012,11 +3016,11 @@ bool SyncContext::sendSAN(uint16_t version)
BOOST_FOREACH (boost::shared_ptr<VirtualSyncSource> vSource, m_sourceListPtr->getVirtualSources()) {
std::string evoSyncSource = vSource->getDatabaseID();
std::string sync = vSource->getSync();
int mode = StringToSyncMode (sync, true);
SANSyncMode mode = AlertSyncMode(StringToSyncMode(sync, true), getPeerIsClient());
std::vector<std::string> mappedSources = unescapeJoinedString (evoSyncSource, ',');
BOOST_FOREACH (std::string source, mappedSources) {
dataSources.erase (source);
if (mode == SYNC_SLOW) {
if (mode == SA_SLOW) {
// We force a source which the client is not expected to use into slow mode.
// Shouldn't we rather reject attempts to synchronize it?
(*m_sourceListPtr)[source]->setForceSlowSync(true);
@ -3025,19 +3029,19 @@ bool SyncContext::sendSAN(uint16_t version)
dataSources.insert (vSource->getName());
}
int syncMode = 0;
SANSyncMode syncMode = SA_INVALID;
vector<pair <string, string> > alertedSources;
/* For each source to be notified do the following: */
BOOST_FOREACH (string name, dataSources) {
boost::shared_ptr<PersistentSyncSourceConfig> sc(getSyncSourceConfig(name));
string sync = sc->getSync();
int mode = StringToSyncMode (sync, true);
if (mode == SYNC_SLOW) {
SANSyncMode mode = AlertSyncMode(StringToSyncMode(sync, true), getPeerIsClient());
if (mode == SA_SLOW) {
(*m_sourceListPtr)[name]->setForceSlowSync(true);
mode = SA_SYNC_TWO_WAY;
mode = SA_TWO_WAY;
}
if (mode <SYNC_FIRST || mode >SYNC_LAST) {
if (mode < SA_FIRST || mode > SA_LAST) {
SE_LOG_DEV (NULL, NULL, "Ignoring data source %s with an invalid sync mode", name.c_str());
continue;
}
@ -3274,27 +3278,30 @@ SyncMLStatus SyncContext::doSync()
m_engine.SetInt32Value(target, "enabled", 1);
int slow = 0;
int direction = 0;
string mode = source->getSync();
if (!strcasecmp(mode.c_str(), "slow")) {
string sync = source->getSync();
// this code only runs when we are the client,
// take that into account for the "from-local/remote" modes
SimpleSyncMode mode = SimplifySyncMode(StringToSyncMode(sync), false);
if (mode == SIMPLE_SYNC_SLOW) {
slow = 1;
direction = 0;
} else if (!strcasecmp(mode.c_str(), "two-way")) {
} else if (mode == SIMPLE_SYNC_TWO_WAY) {
slow = 0;
direction = 0;
} else if (!strcasecmp(mode.c_str(), "refresh-from-server")) {
} else if (mode == SIMPLE_SYNC_REFRESH_FROM_REMOTE) {
slow = 1;
direction = 1;
} else if (!strcasecmp(mode.c_str(), "refresh-from-client")) {
} else if (mode == SIMPLE_SYNC_REFRESH_FROM_LOCAL) {
slow = 1;
direction = 2;
} else if (!strcasecmp(mode.c_str(), "one-way-from-server")) {
} else if (mode == SIMPLE_SYNC_ONE_WAY_FROM_REMOTE) {
slow = 0;
direction = 1;
} else if (!strcasecmp(mode.c_str(), "one-way-from-client")) {
} else if (mode == SIMPLE_SYNC_ONE_WAY_FROM_LOCAL) {
slow = 0;
direction = 2;
} else {
source->throwError(string("invalid sync mode: ") + mode);
source->throwError(string("invalid sync mode: ") + sync);
}
m_engine.SetInt32Value(target, "forceslow", slow);
m_engine.SetInt32Value(target, "syncmode", direction);

View File

@ -38,6 +38,95 @@
using namespace std;
SE_BEGIN_CXX
SimpleSyncMode SimplifySyncMode(SyncMode mode, bool peerIsClient)
{
switch (mode) {
case SYNC_NONE:
case SYNC_TWO_WAY:
case SYNC_SLOW:
case SYNC_RESTORE_FROM_BACKUP:
case SYNC_ONE_WAY_FROM_LOCAL:
case SYNC_REFRESH_FROM_LOCAL:
case SYNC_ONE_WAY_FROM_REMOTE:
case SYNC_REFRESH_FROM_REMOTE:
return static_cast<SimpleSyncMode>(mode);
case SA_SYNC_ONE_WAY_FROM_CLIENT:
case SYNC_ONE_WAY_FROM_CLIENT:
return peerIsClient ? SIMPLE_SYNC_ONE_WAY_FROM_REMOTE : SIMPLE_SYNC_ONE_WAY_FROM_LOCAL;
case SA_SYNC_REFRESH_FROM_CLIENT:
case SYNC_REFRESH_FROM_CLIENT:
return peerIsClient ? SIMPLE_SYNC_REFRESH_FROM_REMOTE : SIMPLE_SYNC_REFRESH_FROM_LOCAL;
case SA_SYNC_ONE_WAY_FROM_SERVER:
case SYNC_ONE_WAY_FROM_SERVER:
return peerIsClient ? SIMPLE_SYNC_ONE_WAY_FROM_LOCAL : SIMPLE_SYNC_ONE_WAY_FROM_REMOTE;
case SA_SYNC_REFRESH_FROM_SERVER:
case SYNC_REFRESH_FROM_SERVER:
return peerIsClient ? SIMPLE_SYNC_REFRESH_FROM_LOCAL : SIMPLE_SYNC_REFRESH_FROM_REMOTE;
case SA_SYNC_TWO_WAY:
return SIMPLE_SYNC_TWO_WAY;
case SYNC_LAST:
case SYNC_INVALID:
return SIMPLE_SYNC_INVALID;
}
return SIMPLE_SYNC_INVALID;
}
SANSyncMode AlertSyncMode(SyncMode mode, bool peerIsClient)
{
switch(mode) {
case SYNC_RESTORE_FROM_BACKUP:
case SYNC_NONE:
case SYNC_LAST:
case SYNC_INVALID:
return SA_INVALID;
case SYNC_SLOW:
return SA_SLOW;
case SYNC_TWO_WAY:
case SA_SYNC_TWO_WAY:
return SA_TWO_WAY;
case SYNC_ONE_WAY_FROM_CLIENT:
case SA_SYNC_ONE_WAY_FROM_CLIENT:
return SA_ONE_WAY_FROM_CLIENT;
case SYNC_REFRESH_FROM_CLIENT:
case SA_SYNC_REFRESH_FROM_CLIENT:
return SA_REFRESH_FROM_CLIENT;
case SYNC_ONE_WAY_FROM_SERVER:
case SA_SYNC_ONE_WAY_FROM_SERVER:
return SA_ONE_WAY_FROM_SERVER;
case SYNC_REFRESH_FROM_SERVER:
case SA_SYNC_REFRESH_FROM_SERVER:
return SA_REFRESH_FROM_SERVER;
case SYNC_ONE_WAY_FROM_LOCAL:
return peerIsClient ? SA_ONE_WAY_FROM_SERVER : SA_ONE_WAY_FROM_CLIENT;
case SYNC_REFRESH_FROM_LOCAL:
return peerIsClient ? SA_REFRESH_FROM_SERVER : SA_REFRESH_FROM_CLIENT;
case SYNC_ONE_WAY_FROM_REMOTE:
return peerIsClient ? SA_ONE_WAY_FROM_CLIENT : SA_ONE_WAY_FROM_SERVER;
case SYNC_REFRESH_FROM_REMOTE:
return peerIsClient ? SA_REFRESH_FROM_CLIENT : SA_REFRESH_FROM_SERVER;
}
return SA_INVALID;
}
std::string PrettyPrintSyncMode(SyncMode mode, bool userVisible)
{
switch (mode) {
@ -62,6 +151,14 @@ std::string PrettyPrintSyncMode(SyncMode mode, bool userVisible)
return userVisible ? "refresh-from-server" : "SYNC_REFRESH_FROM_SERVER";
case SYNC_RESTORE_FROM_BACKUP:
return userVisible ? "restore-from-backup" : "SYNC_RESTORE_FROM_BACKUP";
case SYNC_ONE_WAY_FROM_LOCAL:
return userVisible ? "one-way-from-local" : "SYNC_REFRESH_FROM_LOCAL";
case SYNC_REFRESH_FROM_LOCAL:
return userVisible ? "refresh-from-local" : "SYNC_REFRESH_FROM_LOCAL";
case SYNC_ONE_WAY_FROM_REMOTE:
return userVisible ? "one-way-from-remote" : "SYNC_ONE_WAY_FROM_REMOTE";
case SYNC_REFRESH_FROM_REMOTE:
return userVisible ? "refresh-from-remote" : "SYNC_REFRESH_FROM_REMOTE";
default:
std::stringstream res;
@ -84,6 +181,14 @@ SyncMode StringToSyncMode(const std::string &mode, bool serverAlerted)
return serverAlerted? SA_SYNC_ONE_WAY_FROM_SERVER: SYNC_ONE_WAY_FROM_SERVER;
} else if (boost::iequals(mode, "one-way-from-client") || boost::iequals(mode, "SYNC_ONE_WAY_FROM_CLIENT")) {
return serverAlerted? SA_SYNC_ONE_WAY_FROM_CLIENT: SYNC_ONE_WAY_FROM_CLIENT;
} else if (boost::iequals(mode, "refresh-from-remote") || boost::iequals(mode, "SYNC_REFRESH_FROM_REMOTE")) {
return SYNC_REFRESH_FROM_REMOTE;
} else if (boost::iequals(mode, "refresh-from-local") || boost::iequals(mode, "SYNC_REFRESH_FROM_LOCAL")) {
return SYNC_REFRESH_FROM_LOCAL;
} else if (boost::iequals(mode, "one-way-from-remote") || boost::iequals(mode, "SYNC_ONE_WAY_FROM_REMOTE")) {
return SYNC_ONE_WAY_FROM_REMOTE;
} else if (boost::iequals(mode, "one-way-from-local") || boost::iequals(mode, "SYNC_ONE_WAY_FROM_LOCAL")) {
return SYNC_ONE_WAY_FROM_LOCAL;
} else if (boost::iequals(mode, "disabled") || boost::iequals(mode, "SYNC_NONE")) {
return SYNC_NONE;
} else {

View File

@ -31,7 +31,43 @@
#include <syncevo/declarations.h>
SE_BEGIN_CXX
/** alert Codes used at the synchronization initialization */
/**
* only the codes which are valid for a server alerted sync (SAN) message
*/
enum SANSyncMode {
SA_SLOW = 201,
SA_FIRST = SA_SLOW,
SA_TWO_WAY = 206,
SA_ONE_WAY_FROM_CLIENT = 207,
SA_REFRESH_FROM_CLIENT = 208,
SA_ONE_WAY_FROM_SERVER = 209,
SA_REFRESH_FROM_SERVER = 210,
SA_LAST = SA_REFRESH_FROM_SERVER,
SA_INVALID = 255
};
/**
* unambiguous sync modes:
* - data direction is independent of client/server role
* - no server alerted variants
*/
enum SimpleSyncMode {
SIMPLE_SYNC_NONE,
SIMPLE_SYNC_TWO_WAY = 200,
SIMPLE_SYNC_SLOW = 201,
SIMPLE_SYNC_RESTORE_FROM_BACKUP = 211,
SIMPLE_SYNC_ONE_WAY_FROM_LOCAL = 212,
SIMPLE_SYNC_REFRESH_FROM_LOCAL = 213,
SIMPLE_SYNC_ONE_WAY_FROM_REMOTE = 214,
SIMPLE_SYNC_REFRESH_FROM_REMOTE = 215,
SIMPLE_SYNC_INVALID = 255
};
/** all kinds of sync modes */
enum SyncMode {
/** unset or disabled */
SYNC_NONE,
@ -44,7 +80,7 @@ enum SyncMode {
SYNC_ONE_WAY_FROM_SERVER = 204,
SYNC_REFRESH_FROM_SERVER = 205,
/** used by Server Alerted Sync **/
// used by Server Alerted Sync, same as SA_ in SANSyncMode
SA_SYNC_TWO_WAY = 206,
SA_SYNC_ONE_WAY_FROM_CLIENT = 207,
SA_SYNC_REFRESH_FROM_CLIENT = 208,
@ -54,11 +90,29 @@ enum SyncMode {
// used by restore backend with backup data, a pseudo mode
SYNC_RESTORE_FROM_BACKUP = 211,
// modes which always transfer in the same direction,
// regardless which side acts as client or server
SYNC_ONE_WAY_FROM_LOCAL = 212,
SYNC_REFRESH_FROM_LOCAL = 213,
SYNC_ONE_WAY_FROM_REMOTE = 214,
SYNC_REFRESH_FROM_REMOTE = 215,
SYNC_LAST = 220,
/** error situation (in contrast to SYNC_NONE) */
SYNC_INVALID = 255
};
/**
* maps to normal SYNC_ variants (no SA_*) and unambiguous direction
* (LOCAL/REMOTE instead of CLIENT/SERVER)
*/
SimpleSyncMode SimplifySyncMode(SyncMode mode, bool peerIsClient);
/**
* maps to the server alerted variants
*/
SANSyncMode AlertSyncMode(SyncMode mode, bool peerIsClient);
/* According to OMNA WSP Content Type Numbers*/
enum ContentType {
WSPCTC_TEXT_PLAIN = 0x03,

View File

@ -1939,6 +1939,8 @@ void SyncTests::addTests(bool isFirstSource) {
ADD_TEST(SyncTests, testSlowSync);
ADD_TEST(SyncTests, testRefreshFromServerSync);
ADD_TEST(SyncTests, testRefreshFromClientSync);
ADD_TEST(SyncTests, testRefreshFromRemoteSync);
ADD_TEST(SyncTests, testRefreshFromLocalSync);
// testTimeout is independent of the actual peer; all it needs
// is a SyncML client config. Can't test for that explicitly
// here, so only rule out the test if we run in server mode.
@ -2013,6 +2015,8 @@ void SyncTests::addTests(bool isFirstSource) {
ADD_TEST(SyncTests, testLargeObject);
ADD_TEST(SyncTests, testOneWayFromServer);
ADD_TEST(SyncTests, testOneWayFromClient);
ADD_TEST(SyncTests, testOneWayFromRemote);
ADD_TEST(SyncTests, testOneWayFromLocal);
}
}
}
@ -2161,7 +2165,7 @@ void SyncTests::deleteAll(DeleteAllMode mode) {
}
doSync("refreshserver",
SyncOptions(RefreshFromLocalMode(),
CheckSyncReport(0,0,0, 0,0,-1, true, RefreshFromLocalMode())));
CheckSyncReport(0,0,0, 0,0,-1, true, SYNC_REFRESH_FROM_LOCAL)));
break;
}
}
@ -2250,6 +2254,37 @@ void SyncTests::testDeleteAllRefresh() {
}
}
// refresh-from-server sync, regardless of peer's role
void SyncTests::testRefreshFromServerSync()
{
doSync(SyncOptions(SYNC_REFRESH_FROM_SERVER,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true,
isServerMode() ? SYNC_REFRESH_FROM_LOCAL : SYNC_REFRESH_FROM_REMOTE)));
}
// do a refresh-from-client sync, regardless of peer's role
void SyncTests::testRefreshFromClientSync()
{
doSync(SyncOptions(SYNC_REFRESH_FROM_CLIENT,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true,
isServerMode() ? SYNC_REFRESH_FROM_REMOTE : SYNC_REFRESH_FROM_LOCAL)));
}
// do a refresh-from-remote sync, regardless of peer's role
void SyncTests::testRefreshFromRemoteSync()
{
doSync(SyncOptions(SYNC_REFRESH_FROM_REMOTE,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_REMOTE)));
}
// do a refresh-from-local sync, regardless of peer's role
void SyncTests::testRefreshFromLocalSync()
{
doSync(SyncOptions(SYNC_REFRESH_FROM_LOCAL,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_LOCAL)));
}
// test that a refresh sync from an empty server leads to an empty datatbase
// and no changes are sent to server during next two-way sync
void SyncTests::testRefreshFromServerSemantic() {
@ -2264,7 +2299,7 @@ void SyncTests::testRefreshFromServerSemantic() {
}
doSync("refresh",
SyncOptions(RefreshFromPeerMode(),
CheckSyncReport(0,0,-1, 0,0,0, true, RefreshFromPeerMode())));
CheckSyncReport(0,0,-1, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE)));
// check
for (it = sources.begin(); it != sources.end(); ++it) {
@ -2302,12 +2337,12 @@ void SyncTests::testRefreshFromClientSemantic() {
// refresh from client
doSync("refresh",
SyncOptions(RefreshFromLocalMode(),
CheckSyncReport(0,0,0, 0,0,0, true, RefreshFromLocalMode())));
CheckSyncReport(0,0,0, 0,0,0, true, SYNC_REFRESH_FROM_LOCAL)));
// check
doSync("check",
SyncOptions(RefreshFromPeerMode(),
CheckSyncReport(0,0,0, 0,0,0, true, RefreshFromPeerMode())));
CheckSyncReport(0,0,0, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE)));
}
// tests the following sequence of events:
@ -2331,7 +2366,7 @@ void SyncTests::testRefreshStatus() {
doSync("refresh-from-client",
SyncOptions(RefreshFromLocalMode(),
CheckSyncReport(0,0,0, -1,-1,-1, /* strictly speaking 1,0,0, but not sure exactly what the server will be told */
true, RefreshFromLocalMode())));
true, SYNC_REFRESH_FROM_LOCAL)));
doSync("two-way",
SyncOptions(SYNC_TWO_WAY,
CheckSyncReport(0,0,0, 0,0,0, true, SYNC_TWO_WAY)));
@ -2474,7 +2509,7 @@ void SyncTests::testMerge() {
// Be extra careful and pull that data anew and compare once more.
doSync("check",
SyncOptions(RefreshFromPeerMode(),
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, RefreshFromPeerMode())));
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_REMOTE)));
CPPUNIT_ASSERT_NO_THROW(compareDatabases());
}
@ -2508,7 +2543,7 @@ void SyncTests::testTwinning() {
CPPUNIT_ASSERT_NO_THROW(compareDatabases());
}
// tests one-way sync from server:
// tests one-way sync from peer:
// - 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
@ -2517,7 +2552,7 @@ void SyncTests::testTwinning() {
// - 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() {
void SyncTests::doOneWayFromRemote(SyncMode oneWayFromRemote) {
// no items anywhere
deleteAll();
accessClientB->refreshClient();
@ -2577,8 +2612,8 @@ void SyncTests::testOneWayFromServer() {
}
}
accessClientB->doSync("recv",
SyncOptions(OneWayFromPeerMode(),
CheckSyncReport(1,0,0, 0,0,0, true, OneWayFromPeerMode())));
SyncOptions(oneWayFromRemote,
CheckSyncReport(1,0,0, 0,0,0, true, SYNC_ONE_WAY_FROM_REMOTE)));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.m_createSourceB) {
TestingSyncSourcePtr source;
@ -2640,8 +2675,8 @@ void SyncTests::testOneWayFromServer() {
// sync the same change to second client
// => one item left (the one inserted locally)
accessClientB->doSync("delete",
SyncOptions(OneWayFromPeerMode(),
CheckSyncReport(0,0,1, 0,0,0, true, OneWayFromPeerMode())));
SyncOptions(oneWayFromRemote,
CheckSyncReport(0,0,1, 0,0,0, true, SYNC_ONE_WAY_FROM_REMOTE)));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.m_createSourceB) {
TestingSyncSourcePtr source;
@ -2655,7 +2690,19 @@ void SyncTests::testOneWayFromServer() {
}
}
// tests one-way sync from client:
// one-way-from-remote test with one-way-from-client/server, depending
// on role of remote side
void SyncTests::testOneWayFromServer()
{
doOneWayFromRemote(OneWayFromPeerMode());
}
void SyncTests::testOneWayFromRemote()
{
doOneWayFromRemote(SYNC_ONE_WAY_FROM_REMOTE);
}
// tests one-way sync from local side:
// - 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
@ -2664,7 +2711,7 @@ void SyncTests::testOneWayFromServer() {
// - 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() {
void SyncTests::doOneWayFromLocal(SyncMode oneWayFromLocal) {
// no items anywhere
deleteAll();
accessClientB->deleteAll();
@ -2724,8 +2771,8 @@ void SyncTests::testOneWayFromClient() {
}
}
accessClientB->doSync("send",
SyncOptions(OneWayFromLocalMode(),
CheckSyncReport(0,0,0, 1,0,0, true, OneWayFromLocalMode())));
SyncOptions(oneWayFromLocal,
CheckSyncReport(0,0,0, 1,0,0, true, SYNC_ONE_WAY_FROM_LOCAL)));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.m_createSourceB) {
TestingSyncSourcePtr source;
@ -2770,8 +2817,8 @@ void SyncTests::testOneWayFromClient() {
}
}
accessClientB->doSync("delete",
SyncOptions(OneWayFromLocalMode(),
CheckSyncReport(0,0,0, 0,0,1, true, OneWayFromLocalMode())));
SyncOptions(oneWayFromLocal,
CheckSyncReport(0,0,0, 0,0,1, true, SYNC_ONE_WAY_FROM_LOCAL)));
for (it = accessClientB->sources.begin(); it != accessClientB->sources.end(); ++it) {
if (it->second->config.m_createSourceB) {
TestingSyncSourcePtr source;
@ -2802,6 +2849,18 @@ void SyncTests::testOneWayFromClient() {
}
}
// one-way-from-local test with one-way-from-client/server, depending
// on role of local side
void SyncTests::testOneWayFromClient()
{
doOneWayFromLocal(OneWayFromLocalMode());
}
void SyncTests::testOneWayFromLocal()
{
doOneWayFromLocal(SYNC_ONE_WAY_FROM_LOCAL);
}
// get engine ready, then use it to convert our test items
// to and from the internal field list
void SyncTests::testConversion() {
@ -3102,7 +3161,7 @@ void SyncTests::testManyDeletes() {
accessClientB->doSync("delete-client",
SyncOptions(RefreshFromPeerMode(),
checkSyncModeStr ? CheckSyncReport() :
CheckSyncReport(0,0,num_items, 0,0,0, true, RefreshFromPeerMode()),
CheckSyncReport(0,0,num_items, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE),
10 * 1024));
}
@ -3136,7 +3195,7 @@ void SyncTests::testSlowSyncSemantic()
CheckSyncReport(0,0,0, 0,0,1, true, SYNC_TWO_WAY)));
accessClientB->doSync("check",
SyncOptions(RefreshFromPeerMode(),
CheckSyncReport(0,0,0, 0,0,0, true, RefreshFromPeerMode())));
CheckSyncReport(0,0,0, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE)));
// now the item should also be deleted on A
doSync("delete",
@ -3169,7 +3228,7 @@ void SyncTests::testComplexRefreshFromServerSemantic()
accessClientB->doSync("refresh-one",
SyncOptions(RefreshFromPeerMode(),
checkSyncModeStr ? CheckSyncReport() :
CheckSyncReport(1,0,1, 0,0,0, true, RefreshFromPeerMode())));
CheckSyncReport(1,0,1, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE)));
}
// delete that item via A, check again
@ -3185,7 +3244,7 @@ void SyncTests::testComplexRefreshFromServerSemantic()
accessClientB->doSync("refresh-none",
SyncOptions(RefreshFromPeerMode(),
checkSyncModeStr ? CheckSyncReport() :
CheckSyncReport(0,0,1, 0,0,0, true, RefreshFromPeerMode())));
CheckSyncReport(0,0,1, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE)));
}
}
@ -3641,7 +3700,7 @@ void SyncTests::doVarSizes(bool withMaxMsgSize,
} else {
accessClientB->doSync("recv",
SyncOptions(RefreshFromPeerMode(),
CheckSyncReport(-1,0,-1, 0,0,0, true, RefreshFromPeerMode()), // number of items received from server depends on source
CheckSyncReport(-1,0,-1, 0,0,0, true, SYNC_REFRESH_FROM_REMOTE), // 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));

View File

@ -697,17 +697,11 @@ protected:
doSync(SyncOptions(SYNC_SLOW,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_SLOW)));
}
// do a refresh from server sync without additional checks
virtual void testRefreshFromServerSync() {
doSync(SyncOptions(SYNC_REFRESH_FROM_SERVER,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_SERVER)));
}
// do a refresh from client sync without additional checks
virtual void testRefreshFromClientSync() {
doSync(SyncOptions(SYNC_REFRESH_FROM_CLIENT,
CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_CLIENT)));
}
virtual void testRefreshFromServerSync();
virtual void testRefreshFromClientSync();
virtual void testRefreshFromRemoteSync();
virtual void testRefreshFromLocalSync();
// delete all items, locally and on server using two-way sync
virtual void testDeleteAllSync() {
@ -730,8 +724,12 @@ protected:
virtual void testDelete();
virtual void testMerge();
virtual void testTwinning();
virtual void testOneWayFromServer();
virtual void testOneWayFromClient();
void doOneWayFromRemote(SyncMode oneWayFromRemote);
void testOneWayFromServer();
void testOneWayFromRemote();
void doOneWayFromLocal(SyncMode oneWayFromLocal);
void testOneWayFromClient();
void testOneWayFromLocal();
bool doConversionCallback(bool *success,
SyncContext &client,
SyncOptions &options);

View File

@ -1545,9 +1545,10 @@ class TestSessionAPIsDummy(unittest.TestCase, DBusUtil):
self.assertEqual(str(ex),
"org.syncevolution.InvalidCall: invalid value 'invalid-value' for "
"property 'sync': 'not one of the valid values (two-way, slow, "
"refresh-from-client = refresh-client, refresh-from-server = "
"refresh-server = refresh, one-way-from-client = one-way-client, "
"one-way-from-server = one-way-server = one-way, disabled = none)'")
"refresh-from-local, refresh-from-remote = refresh, one-way-from-local, "
"one-way-from-remote = one-way, refresh-from-client = refresh-client, "
"refresh-from-server = refresh-server, one-way-from-client = one-way-client, "
"one-way-from-server = one-way-server, disabled = none)'")
else:
self.fail("no exception thrown")