2006-12-01 23:49:15 +01:00
/*
2009-03-25 12:25:08 +01:00
* Copyright ( C ) 2008 Funambol , Inc .
2009-03-25 15:21:04 +01:00
* Copyright ( C ) 2008 - 2009 Patrick Ohly < patrick . ohly @ gmx . de >
* Copyright ( C ) 2009 Intel Corporation
2006-12-01 23:49:15 +01:00
*
2009-04-30 18:26:27 +02:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) version 3.
2006-12-01 23:49:15 +01:00
*
2009-04-30 18:26:27 +02:00
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2006-12-01 23:49:15 +01:00
*
2009-04-30 18:26:27 +02:00
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 USA
2006-12-01 23:49:15 +01:00
*/
2007-03-19 20:41:01 +01:00
/** @cond API */
/** @addtogroup ClientTest */
/** @{ */
2006-12-01 23:49:15 +01:00
# ifdef HAVE_CONFIG_H
2009-10-05 14:49:32 +02:00
# include "config.h"
2006-12-01 23:49:15 +01:00
# endif
2007-03-04 12:21:15 +01:00
# ifdef ENABLE_INTEGRATION_TESTS
2006-12-01 23:49:15 +01:00
# include "ClientTest.h"
2009-02-18 12:39:51 +01:00
# include "test.h"
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
# include <SyncSource.h>
2009-02-18 12:39:51 +01:00
# include <TransportAgent.h>
# include <Logging.h>
2009-10-05 14:49:32 +02:00
# include <syncevo/util.h>
# include <syncevo/SyncContext.h>
2009-07-01 14:10:59 +02:00
# include <VolatileConfigNode.h>
2009-03-11 15:01:07 +01:00
# include <synthesis/dataconversion.h>
2006-12-01 23:49:15 +01:00
# include <memory>
# include <vector>
2010-09-01 18:01:19 +02:00
# include <set>
2006-12-01 23:49:15 +01:00
# include <utility>
2006-12-05 23:23:27 +01:00
# include <sstream>
# include <iomanip>
# include <fstream>
2006-12-09 18:50:06 +01:00
# include <iostream>
2007-02-08 22:58:13 +01:00
# include <algorithm>
2006-12-01 23:49:15 +01:00
2009-10-02 17:23:53 +02:00
# include <fcntl.h>
2009-03-11 15:01:07 +01:00
# include <boost/bind.hpp>
2009-10-05 14:49:32 +02:00
# include <syncevo/declarations.h>
2009-10-02 17:23:53 +02:00
SE_BEGIN_CXX
2010-09-01 18:01:19 +02:00
static set < ClientTest : : Cleanup_t > cleanupSet ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
/**
* Using this pointer automates the open ( ) / beginSync ( ) / endSync ( ) / close ( )
* life cycle : it automatically calls these functions when a new
* pointer is assigned or deleted .
2010-06-21 17:10:22 +02:00
*
* Anchors are stored globally in a hash which uses the tracking node
* name as key . This name happens to be the unique file path that
* is created for each source ( see TestEvolution : : createSource ( ) and
* SyncConfig : : getSyncSourceNodes ( ) ) .
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
*/
class TestingSyncSourcePtr : public std : : auto_ptr < TestingSyncSource >
{
typedef std : : auto_ptr < TestingSyncSource > base_t ;
2010-06-21 17:10:22 +02:00
static StringMap m_anchors ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
public :
TestingSyncSourcePtr ( ) { }
TestingSyncSourcePtr ( TestingSyncSource * source ) :
base_t ( source )
{
CPPUNIT_ASSERT ( source ) ;
SOURCE_ASSERT_NO_FAILURE ( source , source - > open ( ) ) ;
2010-06-21 17:10:22 +02:00
string node = source - > getTrackingNode ( ) - > getName ( ) ;
SOURCE_ASSERT_NO_FAILURE ( source , source - > beginSync ( m_anchors [ node ] , " " ) ) ;
2009-12-11 05:39:20 +01:00
const char * serverMode = getenv ( " CLIENT_TEST_MODE " ) ;
if ( serverMode & & ! strcmp ( serverMode , " server " ) ) {
SOURCE_ASSERT_NO_FAILURE ( source , source - > enableServerMode ( ) ) ;
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
}
~ TestingSyncSourcePtr ( )
{
reset ( NULL ) ;
}
void reset ( TestingSyncSource * source = NULL )
{
if ( this - > get ( ) ) {
BOOST_FOREACH ( const SyncSource : : Operations : : CallbackFunctor_t & callback ,
get ( ) - > getOperations ( ) . m_endSession ) {
callback ( ) ;
}
2010-06-21 17:10:22 +02:00
string node = get ( ) - > getTrackingNode ( ) - > getName ( ) ;
SOURCE_ASSERT_NO_FAILURE ( get ( ) , ( m_anchors [ node ] = get ( ) - > endSync ( true ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( get ( ) , get ( ) - > close ( ) ) ;
}
CPPUNIT_ASSERT_NO_THROW ( base_t : : reset ( source ) ) ;
if ( source ) {
SOURCE_ASSERT_NO_FAILURE ( source , source - > open ( ) ) ;
2010-06-21 17:10:22 +02:00
string node = source - > getTrackingNode ( ) - > getName ( ) ;
SOURCE_ASSERT_NO_FAILURE ( source , source - > beginSync ( m_anchors [ node ] , " " ) ) ;
2009-12-11 05:39:20 +01:00
const char * serverMode = getenv ( " CLIENT_TEST_MODE " ) ;
if ( serverMode & & ! strcmp ( serverMode , " server " ) ) {
SOURCE_ASSERT_NO_FAILURE ( source , source - > enableServerMode ( ) ) ;
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
BOOST_FOREACH ( const SyncSource : : Operations : : CallbackFunctor_t & callback ,
source - > getOperations ( ) . m_endSession ) {
callback ( ) ;
}
}
}
} ;
2010-06-21 17:10:22 +02:00
StringMap TestingSyncSourcePtr : : m_anchors ;
2009-03-17 14:16:49 +01:00
bool SyncOptions : : defaultWBXML ( )
{
const char * t = getenv ( " CLIENT_TEST_XML " ) ;
if ( t & & ( ! strcmp ( t , " 1 " ) | | ! strcasecmp ( t , " t " ) ) ) {
// use XML
return false ;
} else {
return true ;
}
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
std : : list < std : : string > listItemsOfType ( TestingSyncSource * source , int state )
2007-06-27 22:08:46 +02:00
{
2008-04-16 19:23:06 +02:00
std : : list < std : : string > res ;
2007-11-28 15:28:46 +01:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
BOOST_FOREACH ( const string & luid , source - > getItems ( SyncSourceChanges : : State ( state ) ) ) {
res . push_back ( luid ) ;
2007-06-27 22:08:46 +02:00
}
return res ;
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
static std : : list < std : : string > listNewItems ( TestingSyncSource * source ) { return listItemsOfType ( source , SyncSourceChanges : : NEW ) ; }
static std : : list < std : : string > listUpdatedItems ( TestingSyncSource * source ) { return listItemsOfType ( source , SyncSourceChanges : : UPDATED ) ; }
static std : : list < std : : string > listDeletedItems ( TestingSyncSource * source ) { return listItemsOfType ( source , SyncSourceChanges : : DELETED ) ; }
static std : : list < std : : string > listItems ( TestingSyncSource * source ) { return listItemsOfType ( source , SyncSourceChanges : : ANY ) ; }
2007-06-27 22:08:46 +02:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
int countItemsOfType ( TestingSyncSource * source , int type ) { return source - > getItems ( SyncSourceChanges : : State ( type ) ) . size ( ) ; }
static int countNewItems ( TestingSyncSource * source ) { return countItemsOfType ( source , SyncSourceChanges : : NEW ) ; }
static int countUpdatedItems ( TestingSyncSource * source ) { return countItemsOfType ( source , SyncSourceChanges : : UPDATED ) ; }
static int countDeletedItems ( TestingSyncSource * source ) { return countItemsOfType ( source , SyncSourceChanges : : DELETED ) ; }
static int countItems ( TestingSyncSource * source ) { return countItemsOfType ( source , SyncSourceChanges : : ANY ) ; }
2008-04-16 19:23:06 +02:00
2008-12-21 21:53:18 +01:00
/** insert new item, return LUID */
2010-10-14 11:40:45 +02:00
static std : : string importItem ( TestingSyncSource * source , const ClientTestConfig & config , std : : string & data )
2006-12-05 23:23:27 +01:00
{
CPPUNIT_ASSERT ( source ) ;
if ( data . size ( ) ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceRaw : : InsertItemResult res ;
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_NO_FAILURE ( source , res = source - > insertItemRaw ( " " , config . mangleItem ( data . c_str ( ) ) . c_str ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
CPPUNIT_ASSERT ( ! res . m_luid . empty ( ) ) ;
return res . m_luid ;
2008-12-21 21:53:18 +01:00
} else {
return " " ;
2006-12-05 23:23:27 +01:00
}
}
2007-06-27 22:16:17 +02:00
/** adds the supported tests to the instance itself */
void LocalTests : : addTests ( ) {
if ( config . createSourceA ) {
ADD_TEST ( LocalTests , testOpen ) ;
ADD_TEST ( LocalTests , testIterateTwice ) ;
if ( config . insertItem ) {
ADD_TEST ( LocalTests , testSimpleInsert ) ;
ADD_TEST ( LocalTests , testLocalDeleteAll ) ;
ADD_TEST ( LocalTests , testComplexInsert ) ;
if ( config . updateItem ) {
ADD_TEST ( LocalTests , testLocalUpdate ) ;
if ( config . createSourceB ) {
ADD_TEST ( LocalTests , testChanges ) ;
2006-12-05 23:23:27 +01:00
}
2007-06-27 22:16:17 +02:00
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
if ( config . import & &
config . dump & &
config . compare & &
config . testcases ) {
ADD_TEST ( LocalTests , testImport ) ;
ADD_TEST ( LocalTests , testImportDelete ) ;
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
if ( config . templateItem & &
config . uniqueProperties ) {
ADD_TEST ( LocalTests , testManyChanges ) ;
2006-12-01 23:49:15 +01:00
}
2008-04-16 19:23:06 +02:00
if ( config . parentItem & &
config . childItem ) {
2008-07-22 10:07:43 +02:00
ADD_TEST ( LocalTests , testLinkedItemsParent ) ;
2010-10-26 11:09:17 +02:00
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsChild ) ;
}
2008-07-22 10:07:43 +02:00
ADD_TEST ( LocalTests , testLinkedItemsParentChild ) ;
2010-10-26 11:09:17 +02:00
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsChildParent ) ;
}
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsChildChangesParent ) ;
}
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsRemoveParentFirst ) ;
}
2008-07-22 10:07:43 +02:00
ADD_TEST ( LocalTests , testLinkedItemsRemoveNormal ) ;
2009-02-18 12:39:51 +01:00
if ( config . sourceKnowsItemSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsInsertParentTwice ) ;
2010-10-26 11:09:17 +02:00
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsInsertChildTwice ) ;
}
2009-02-18 12:39:51 +01:00
}
2008-07-22 10:07:43 +02:00
ADD_TEST ( LocalTests , testLinkedItemsParentUpdate ) ;
2010-10-26 11:09:17 +02:00
if ( config . linkedItemsRelaxedSemantic ) {
ADD_TEST ( LocalTests , testLinkedItemsUpdateChild ) ;
}
2008-07-22 10:07:43 +02:00
ADD_TEST ( LocalTests , testLinkedItemsInsertBothUpdateChild ) ;
ADD_TEST ( LocalTests , testLinkedItemsInsertBothUpdateParent ) ;
2008-04-16 19:23:06 +02:00
}
2006-12-01 23:49:15 +01:00
}
}
2007-06-27 22:16:17 +02:00
}
2007-06-06 10:37:35 +02:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
std : : string LocalTests : : insert ( CreateSource createSource , const char * data , bool relaxed ) {
2007-06-27 22:16:17 +02:00
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2007-06-27 22:16:17 +02:00
// count number of already existing items
2008-06-25 19:15:47 +02:00
int numItems = 0 ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( numItems = countItems ( source . get ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceRaw : : InsertItemResult res ;
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , res = source - > insertItemRaw ( " " , config . mangleItem ( data ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
CPPUNIT_ASSERT ( ! res . m_luid . empty ( ) ) ;
2007-06-27 22:16:17 +02:00
// delete source again
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
source . reset ( ) ;
2007-06-27 22:16:17 +02:00
2008-06-25 19:15:47 +02:00
if ( ! relaxed ) {
// two possible results:
// - a new item was added
// - the item was matched against an existing one
CPPUNIT_ASSERT_NO_THROW ( source . reset ( createSource ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
CPPUNIT_ASSERT_EQUAL ( numItems + ( res . m_merged ? 0 : 1 ) ,
2008-06-25 19:15:47 +02:00
countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT ( countNewItems ( source . get ( ) ) = = 0 ) ;
CPPUNIT_ASSERT ( countUpdatedItems ( source . get ( ) ) = = 0 ) ;
CPPUNIT_ASSERT ( countDeletedItems ( source . get ( ) ) = = 0 ) ;
}
2006-12-05 23:23:27 +01:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
return res . m_luid ;
2008-04-16 19:23:06 +02:00
}
/** deletes specific item locally via sync source */
2010-10-14 11:40:45 +02:00
static std : : string updateItem ( CreateSource createSource , const ClientTestConfig & config , const std : : string & uid , const char * data ) {
2008-04-16 19:23:06 +02:00
std : : string newuid ;
CPPUNIT_ASSERT ( createSource . createSource ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2008-04-16 19:23:06 +02:00
// insert item
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceRaw : : InsertItemResult res ;
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , res = source - > insertItemRaw ( uid , config . mangleItem ( data ) . c_str ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT ( source . get ( ) , ! res . m_luid . empty ( ) ) ;
2008-04-16 19:23:06 +02:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
return res . m_luid ;
2007-06-27 22:16:17 +02:00
}
2008-12-28 19:11:38 +01:00
/** updates specific item locally via sync source */
static void removeItem ( CreateSource createSource , const std : : string & luid )
{
CPPUNIT_ASSERT ( createSource . createSource ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2008-12-28 19:11:38 +01:00
// remove item
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > deleteItem ( luid ) ) ;
2008-12-28 19:11:38 +01:00
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
void LocalTests : : update ( CreateSource createSource , const char * data , bool check ) {
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( createSource . createSource ) ;
CPPUNIT_ASSERT ( data ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2007-06-27 22:16:17 +02:00
// get existing item, then update it
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceChanges : : Items_t : : const_iterator it ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getAllItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getAllItems ( ) . end ( ) ) ;
string luid = * it ;
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > insertItemRaw ( luid , config . mangleItem ( data ) ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2007-06-28 22:09:02 +02:00
if ( ! check ) {
return ;
}
2007-06-27 22:16:17 +02:00
// check that the right changes are reported when reopening the source
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSource ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 1 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countNewItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countDeletedItems ( source . get ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getAllItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getAllItems ( ) . end ( ) ) ;
CPPUNIT_ASSERT_EQUAL ( luid , * it ) ;
2007-06-27 22:16:17 +02:00
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
void LocalTests : : update ( CreateSource createSource , const char * data , const std : : string & luid ) {
2008-12-21 21:53:18 +01:00
CPPUNIT_ASSERT ( createSource . createSource ) ;
CPPUNIT_ASSERT ( data ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2008-12-21 21:53:18 +01:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
// update it
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > insertItemRaw ( luid , config . mangleItem ( data ) . c_str ( ) ) ) ;
2008-12-21 21:53:18 +01:00
}
2007-06-27 22:16:17 +02:00
/** deletes all items locally via sync source */
void LocalTests : : deleteAll ( CreateSource createSource ) {
CPPUNIT_ASSERT ( createSource . createSource ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2007-06-27 22:16:17 +02:00
// delete all items
2008-06-07 20:45:07 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > removeAllItems ( ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// check that all items are gone
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSource ( ) ) ) ;
SOURCE_ASSERT_MESSAGE (
" should be empty now " ,
source . get ( ) ,
countItems ( source . get ( ) ) = = 0 ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countNewItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , countDeletedItems ( source . get ( ) ) ) ;
}
2006-12-01 23:49:15 +01:00
2008-04-16 19:23:06 +02:00
/** deletes specific item locally via sync source */
static void deleteItem ( CreateSource createSource , const std : : string & uid ) {
CPPUNIT_ASSERT ( createSource . createSource ) ;
// create source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSource ( ) ) ;
2008-04-16 19:23:06 +02:00
// delete item
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > deleteItem ( uid ) ) ;
2008-04-16 19:23:06 +02:00
}
2007-06-27 22:16:17 +02:00
/**
* takes two databases , exports them ,
* then compares them using synccompare
*
* @ param refFile existing file with source reference items , NULL uses a dump of sync source A instead
* @ param copy a sync source which contains the copied items , begin / endSync will be called
* @ param raiseAssert raise assertion if comparison yields differences ( defaults to true )
*/
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
bool LocalTests : : compareDatabases ( const char * refFile , TestingSyncSource & copy , bool raiseAssert ) {
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( config . dump ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
std : : string sourceFile , copyFile ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
if ( refFile ) {
sourceFile = refFile ;
} else {
2008-12-28 21:26:58 +01:00
sourceFile = getCurrentTest ( ) + " .A.test.dat " ;
2007-06-27 22:16:17 +02:00
simplifyFilename ( sourceFile ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceA ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , config . dump ( client , * source . get ( ) , sourceFile . c_str ( ) ) ) ;
2006-12-05 23:23:27 +01:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
2008-12-28 21:26:58 +01:00
copyFile = getCurrentTest ( ) + " .B.test.dat " ;
2007-06-27 22:16:17 +02:00
simplifyFilename ( copyFile ) ;
SOURCE_ASSERT_EQUAL ( & copy , 0 , config . dump ( client , copy , copyFile . c_str ( ) ) ) ;
2006-12-05 23:23:27 +01:00
2008-12-28 21:26:58 +01:00
bool equal = config . compare ( client , sourceFile . c_str ( ) , copyFile . c_str ( ) ) ;
CPPUNIT_ASSERT ( ! raiseAssert | | equal ) ;
return equal ;
2007-06-27 22:16:17 +02:00
}
2006-12-05 23:23:27 +01:00
2008-12-28 19:11:38 +01:00
std : : string LocalTests : : createItem ( int item , const std : : string & revision , int size )
{
2010-10-14 11:40:45 +02:00
std : : string data = config . mangleItem ( config . templateItem ) ;
2008-12-28 19:11:38 +01:00
std : : stringstream prefix ;
prefix < < std : : setfill ( ' 0 ' ) < < std : : setw ( 3 ) < < item < < " " ;
const char * prop = config . uniqueProperties ;
const char * nextProp ;
while ( * prop ) {
std : : string curProp ;
nextProp = strchr ( prop , ' : ' ) ;
if ( ! nextProp ) {
curProp = prop ;
} else {
curProp = std : : string ( prop , 0 , nextProp - prop ) ;
}
std : : string property ;
// property is expected to not start directly at the
// beginning
property = " \n " ;
property + = curProp ;
property + = " : " ;
size_t off = data . find ( property ) ;
if ( off ! = data . npos ) {
data . insert ( off + property . size ( ) , prefix . str ( ) ) ;
}
if ( ! nextProp ) {
break ;
}
prop = nextProp + 1 ;
}
2009-09-10 07:11:12 +02:00
/** add check for if not found, STL will crash */
if ( data . find ( " <<REVISION>> " ) ! = std : : string : : npos ) {
data . replace ( data . find ( " <<REVISION>> " ) , strlen ( " <<REVISION>> " ) , revision ) ;
} else if ( data . find ( " REVISION " ) ! = std : : string : : npos ) {
/* change "<<REVISION>>" to "REVISION" for memo */
data . replace ( data . find ( " REVISION " ) , strlen ( " REVISION " ) , revision ) ;
}
2008-12-28 19:11:38 +01:00
if ( size > 0 & & ( int ) data . size ( ) < size ) {
int additionalBytes = size - ( int ) data . size ( ) ;
int added = 0 ;
/* vCard 2.1 and vCal 1.0 need quoted-printable line breaks */
bool quoted = data . find ( " VERSION:1.0 " ) ! = data . npos | |
data . find ( " VERSION:2.1 " ) ! = data . npos ;
size_t toreplace = 1 ;
CPPUNIT_ASSERT ( config . sizeProperty ) ;
/* stuff the item so that it reaches at least that size */
size_t off = data . find ( config . sizeProperty ) ;
CPPUNIT_ASSERT ( off ! = data . npos ) ;
std : : stringstream stuffing ;
if ( quoted ) {
stuffing < < " ;ENCODING=QUOTED-PRINTABLE: " ;
} else {
stuffing < < " : " ;
}
// insert after the first line, it often acts as the summary
if ( data . find ( " BEGIN:VJOURNAL " ) ! = data . npos ) {
size_t start = data . find ( " : " , off ) ;
CPPUNIT_ASSERT ( start ! = data . npos ) ;
size_t eol = data . find ( " \\ n " , off ) ;
CPPUNIT_ASSERT ( eol ! = data . npos ) ;
stuffing < < data . substr ( start + 1 , eol - start + 1 ) ;
toreplace + = eol - start + 1 ;
}
while ( added < additionalBytes ) {
int linelen = 0 ;
while ( added + 4 < additionalBytes & &
linelen < 60 ) {
stuffing < < ' x ' ;
added + + ;
linelen + + ;
}
// insert line breaks to allow folding
if ( quoted ) {
stuffing < < " x=0D=0Ax " ;
added + = 8 ;
} else {
stuffing < < " x \\ nx " ;
added + = 4 ;
}
}
off = data . find ( " : " , off ) ;
data . replace ( off , toreplace , stuffing . str ( ) ) ;
}
return data ;
}
2007-06-27 22:16:17 +02:00
/**
2007-11-05 20:14:09 +01:00
* insert artificial items , number of them determined by config . numItems
2007-06-27 22:16:17 +02:00
* unless passed explicitly
*
* @ param createSource a factory for the sync source that is to be used
* @ param startIndex IDs are generated starting with this value
2007-11-05 20:14:09 +01:00
* @ param numItems number of items to be inserted if non - null , otherwise config . numItems is used
2007-06-27 22:16:17 +02:00
* @ param size minimum size for new items
2008-12-21 21:53:18 +01:00
* @ return LUIDs of all inserted items
2007-06-27 22:16:17 +02:00
*/
2008-12-21 21:53:18 +01:00
std : : list < std : : string > LocalTests : : insertManyItems ( CreateSource createSource , int startIndex , int numItems , int size ) {
std : : list < std : : string > luids ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( config . templateItem ) ;
CPPUNIT_ASSERT ( config . uniqueProperties ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceA ( ) ) ) ;
CPPUNIT_ASSERT ( startIndex > 1 | | ! countItems ( source . get ( ) ) ) ;
int firstIndex = startIndex ;
if ( firstIndex < 0 ) {
firstIndex = 1 ;
}
int lastIndex = firstIndex + ( numItems > = 1 ? numItems : config . numItems ) - 1 ;
for ( int item = firstIndex ; item < = lastIndex ; item + + ) {
2008-12-28 19:11:38 +01:00
std : : string data = createItem ( item , " " , size ) ;
2010-10-14 11:40:45 +02:00
luids . push_back ( importItem ( source . get ( ) , config , data ) ) ;
2007-06-27 22:16:17 +02:00
}
2008-12-21 21:53:18 +01:00
return luids ;
2007-06-27 22:16:17 +02:00
}
// creating sync source
void LocalTests : : testOpen ( ) {
// check requirements
CPPUNIT_ASSERT ( config . createSourceA ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
// Intentionally use the plain auto_ptr here and
// call open directly. That way it is a bit more clear
// what happens and where it fails, if it fails.
std : : auto_ptr < TestingSyncSource > source ( createSourceA ( ) ) ;
// got a sync source?
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( source . get ( ) ! = 0 ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
// can it be opened?
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > open ( ) ) ;
// delete it
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
// restart scanning of items
void LocalTests : : testIterateTwice ( ) {
// check requirements
CPPUNIT_ASSERT ( config . createSourceA ) ;
// open source
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSourceA ( ) ) ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_MESSAGE (
" iterating twice should produce identical results " ,
source . get ( ) ,
countItems ( source . get ( ) ) = = countItems ( source . get ( ) ) ) ;
}
// insert one contact without clearing the source first
void LocalTests : : testSimpleInsert ( ) {
// check requirements
CPPUNIT_ASSERT ( config . insertItem ) ;
CPPUNIT_ASSERT ( config . createSourceA ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
insert ( createSourceA , config . insertItem ) ;
2007-06-27 22:16:17 +02:00
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// delete all items
void LocalTests : : testLocalDeleteAll ( ) {
// check requirements
CPPUNIT_ASSERT ( config . insertItem ) ;
CPPUNIT_ASSERT ( config . createSourceA ) ;
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// make sure there is something to delete, then delete again
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
insert ( createSourceA , config . insertItem ) ;
2007-06-27 22:16:17 +02:00
deleteAll ( createSourceA ) ;
}
// clean database, then insert
void LocalTests : : testComplexInsert ( ) {
testLocalDeleteAll ( ) ;
testSimpleInsert ( ) ;
testIterateTwice ( ) ;
}
// clean database, insert item, update it
void LocalTests : : testLocalUpdate ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . updateItem ) ;
testLocalDeleteAll ( ) ;
testSimpleInsert ( ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
update ( createSourceA , config . updateItem ) ;
2007-06-27 22:16:17 +02:00
}
// complex sequence of changes
void LocalTests : : testChanges ( ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceChanges : : Items_t : : const_iterator it , it2 ;
2007-06-27 22:16:17 +02:00
// check additional requirements
CPPUNIT_ASSERT ( config . createSourceB ) ;
testLocalDeleteAll ( ) ;
testSimpleInsert ( ) ;
// clean changes in sync source B by creating and closing it
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ( createSourceB ( ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// no new changes now
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , 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 ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
string item ;
string luid ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getAllItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getAllItems ( ) . end ( ) ) ;
luid = * it ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > readItem ( * it , item ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// delete item again via sync source A
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
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 ( ) , 1 , countDeletedItems ( source . get ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getDeletedItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getDeletedItems ( ) . end ( ) ) ;
CPPUNIT_ASSERT ( ! it - > empty ( ) ) ;
CPPUNIT_ASSERT_EQUAL ( luid , * it ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// insert another item via sync source A
testSimpleInsert ( ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getAllItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getAllItems ( ) . end ( ) ) ;
luid = * it ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > readItem ( * it , item ) ) ;
string newItem ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getNewItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getNewItems ( ) . end ( ) ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > readItem ( * it , item ) ) ;
CPPUNIT_ASSERT_EQUAL ( luid , * it ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// update item via sync source A
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
update ( createSourceA , config . updateItem ) ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countUpdatedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
string updatedItem ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getUpdatedItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getUpdatedItems ( ) . end ( ) ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source - > readItem ( * it , updatedItem ) ) ;
CPPUNIT_ASSERT_EQUAL ( luid , * it ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2007-12-15 18:24:45 +01:00
// start anew, then create and update an item -> should only be listed as new
// or updated, but not both
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
source . reset ( ) ;
2007-12-15 18:24:45 +01:00
testSimpleInsert ( ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
update ( createSourceA , config . updateItem ) ;
2007-12-15 18:24:45 +01:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) + countUpdatedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
// start anew, then create, delete and recreate an item -> should only be listed as new or updated,
// even if (as for calendar with UID) the same LUID gets reused
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
source . reset ( ) ;
2007-12-15 18:24:45 +01:00
testSimpleInsert ( ) ;
deleteAll ( createSourceA ) ;
testSimpleInsert ( ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) + countUpdatedItems ( source . get ( ) ) ) ;
if ( countDeletedItems ( source . get ( ) ) = = 1 ) {
// It's not nice, but acceptable to send the LUID of a deleted item to a
// server which has never seen that LUID. The LUID must not be the same as
// the one we list as new or updated, though.
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it = source - > getDeletedItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it ! = source - > getDeletedItems ( ) . end ( ) ) ;
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it2 = source - > getNewItems ( ) . begin ( ) ) ;
if ( it2 = = source - > getNewItems ( ) . end ( ) ) {
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , it2 = source - > getUpdatedItems ( ) . begin ( ) ) ;
CPPUNIT_ASSERT ( it2 ! = source - > getUpdatedItems ( ) . end ( ) ) ;
}
CPPUNIT_ASSERT ( * it ! = * it2 ) ;
2007-12-15 18:24:45 +01:00
} else {
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
}
2007-06-27 22:16:17 +02:00
}
// clean database, import file, then export again and compare
void LocalTests : : testImport ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . import ) ;
CPPUNIT_ASSERT ( config . dump ) ;
CPPUNIT_ASSERT ( config . compare ) ;
CPPUNIT_ASSERT ( config . testcases ) ;
testLocalDeleteAll ( ) ;
// import via sync source A
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceA ( ) ) ) ;
2009-07-08 18:38:58 +02:00
std : : string testcases ;
2010-10-14 11:40:45 +02:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , config . import ( client , * source . get ( ) , config , config . testcases , testcases ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
// export again and compare against original file
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceA ( ) ) ) ;
2009-07-08 18:38:58 +02:00
compareDatabases ( testcases . c_str ( ) , * copy . get ( ) ) ;
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
// same as testImport() with immediate delete
void LocalTests : : testImportDelete ( ) {
testImport ( ) ;
// delete again, because it was observed that this did not
// work right with calendars in SyncEvolution
testLocalDeleteAll ( ) ;
}
// test change tracking with large number of items
void LocalTests : : testManyChanges ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . templateItem ) ;
CPPUNIT_ASSERT ( config . uniqueProperties ) ;
deleteAll ( createSourceA ) ;
// check that everything is empty, also resets change counter of sync source B
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
// now insert plenty of items
2008-12-21 21:53:18 +01:00
int numItems = insertManyItems ( createSourceA ) . size ( ) ;
2007-06-27 22:16:17 +02:00
// check that exactly this number of items is listed as new
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , numItems , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , numItems , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
// delete all items
deleteAll ( createSourceA ) ;
// verify again
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , numItems , countDeletedItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
}
2008-04-16 19:23:06 +02:00
template < class T , class V > int countEqual ( const T & container ,
const V & value ) {
return count ( container . begin ( ) ,
container . end ( ) ,
value ) ;
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
2008-07-22 10:07:43 +02:00
void LocalTests : : testLinkedItemsParent ( ) {
2008-04-16 19:23:06 +02:00
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-04-16 19:23:06 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
// now insert main item
2009-04-01 16:46:55 +02:00
parent = insert ( createSourceA , config . parentItem , config . itemType ) ;
2008-04-16 19:23:06 +02:00
// check that exactly the parent is listed as new
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
// delete all items
deleteAll ( createSourceA ) ;
// verify again
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
2008-07-22 10:07:43 +02:00
}
2008-04-16 19:23:06 +02:00
2008-07-22 10:07:43 +02:00
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsChild ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// same as above for child item
2009-04-01 16:46:55 +02:00
child = insert ( createSourceA , config . childItem , config . itemType ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsParentChild ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// insert parent first, then child
2009-04-01 16:46:55 +02:00
parent = insert ( createSourceA , config . parentItem , config . itemType ) ;
child = insert ( createSourceA , config . childItem , config . itemType ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
2008-07-22 10:07:43 +02:00
}
2008-04-16 19:23:06 +02:00
2008-07-22 10:07:43 +02:00
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsChildParent ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// insert child first, then parent
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
child = insert ( createSourceA , config . childItem ) ;
parent = insert ( createSourceA , config . parentItem , true ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
2008-07-22 10:07:43 +02:00
}
2008-04-16 19:23:06 +02:00
2008-07-22 10:07:43 +02:00
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsChildChangesParent ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-06-25 19:15:47 +02:00
// insert child first, check changes, then insert the parent
2009-04-01 16:46:55 +02:00
child = insert ( createSourceA , config . childItem , config . itemType ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem , true ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listNewItems ( copy . get ( ) ) , parent ) ) ;
2008-06-25 19:15:47 +02:00
// relaxed semantic: the child item might be considered updated now if
// it had to be modified when inserting the parent
SOURCE_ASSERT ( copy . get ( ) , 1 > = countUpdatedItems ( copy . get ( ) ) ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteAll ( createSourceA ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
2008-07-22 10:07:43 +02:00
}
2008-04-16 19:23:06 +02:00
2008-07-22 10:07:43 +02:00
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsRemoveParentFirst ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// insert both items, remove parent, then child
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
2008-06-25 19:15:47 +02:00
// deleting the parent may or may not modify the child
SOURCE_ASSERT ( copy . get ( ) , 1 > = countUpdatedItems ( copy . get ( ) ) ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , child ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsRemoveNormal ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
2010-02-23 17:17:46 +01:00
TestingSyncSourcePtr source , copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// insert both items, remove child, then parent
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , child ) ;
2010-02-23 17:17:46 +01:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( createSourceA ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , 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 ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
2010-02-23 17:17:46 +01:00
// parent might have been updated
int updated = countUpdatedItems ( copy . get ( ) ) ;
SOURCE_ASSERT ( copy . get ( ) , 0 < = updated & & updated < = 1 ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsInsertParentTwice ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add parent twice (should be turned into update)
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsInsertChildTwice ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add child twice (should be turned into update)
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , child ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsParentUpdate ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add parent, then update it
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2010-10-14 11:40:45 +02:00
parent = updateItem ( createSourceA , config , parent , config . parentItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-07-22 10:07:43 +02:00
}
2008-04-16 19:23:06 +02:00
2008-07-22 10:07:43 +02:00
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsUpdateChild ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add child, then update it
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2010-10-14 11:40:45 +02:00
child = updateItem ( createSourceA , config , child , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , child ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsInsertBothUpdateChild ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add parent and child, then update child
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2010-10-14 11:40:45 +02:00
child = updateItem ( createSourceA , config , child , config . childItem ) ;
2008-04-16 19:23:06 +02:00
2009-02-23 17:57:31 +01:00
// child has to be listed as modified, parent may be
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
2009-02-23 17:57:31 +01:00
SOURCE_ASSERT ( copy . get ( ) , 1 < = countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT ( copy . get ( ) , 2 > = countUpdatedItems ( copy . get ( ) ) ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
deleteItem ( createSourceA , child ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-07-22 10:07:43 +02:00
}
// test inserting, removing and updating of parent + child item in
// various order plus change tracking
void LocalTests : : testLinkedItemsInsertBothUpdateParent ( ) {
// check additional requirements
CPPUNIT_ASSERT ( config . parentItem ) ;
CPPUNIT_ASSERT ( config . childItem ) ;
deleteAll ( createSourceA ) ;
std : : string parent , child ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2008-07-22 10:07:43 +02:00
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2008-04-16 19:23:06 +02:00
// add parent and child, then update parent
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
parent = insert ( createSourceA , config . parentItem ) ;
child = insert ( createSourceA , config . childItem ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , child ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2010-10-14 11:40:45 +02:00
parent = updateItem ( createSourceA , config , parent , config . parentItem ) ;
2008-04-16 19:23:06 +02:00
2009-02-23 17:57:31 +01:00
// parent has to be listed as modified, child may be
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
2009-02-23 17:57:31 +01:00
SOURCE_ASSERT ( copy . get ( ) , 1 < = countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT ( copy . get ( ) , 2 > = countUpdatedItems ( copy . get ( ) ) ) ;
2008-04-16 19:23:06 +02:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listUpdatedItems ( copy . get ( ) ) , parent ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
deleteItem ( createSourceA , parent ) ;
deleteItem ( createSourceA , child ) ;
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countNewItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countUpdatedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 2 , countDeletedItems ( copy . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , parent ) ) ;
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 1 , countEqual ( listDeletedItems ( copy . get ( ) ) , child ) ) ;
}
2007-06-27 22:16:17 +02:00
SyncTests : : SyncTests ( const std : : string & name , ClientTest & cl , std : : vector < int > sourceIndices , bool isClientA ) :
CppUnit : : TestSuite ( name ) ,
client ( cl ) {
sourceArray = new int [ sourceIndices . size ( ) + 1 ] ;
2009-12-11 05:54:28 +01:00
int offset = 0 ;
2007-06-27 22:16:17 +02:00
for ( std : : vector < int > : : iterator it = sourceIndices . begin ( ) ;
it ! = sourceIndices . end ( ) ;
+ + it ) {
ClientTest : : Config config ;
2009-12-16 07:43:08 +01:00
client . getSyncSourceConfig ( * it , config ) ;
2007-06-27 22:16:17 +02:00
if ( config . sourceName ) {
2009-12-11 05:54:28 +01:00
sourceArray [ sources . size ( ) + offset ] = * it ;
2009-12-16 07:43:08 +01:00
if ( config . subConfigs ) {
vector < string > subs ;
boost : : split ( subs , config . subConfigs , boost : : is_any_of ( " , " ) ) ;
2009-12-11 05:54:28 +01:00
offset + + ;
2009-12-16 07:43:08 +01:00
ClientTest : : Config subConfig ;
BOOST_FOREACH ( string sub , subs ) {
client . getSourceConfig ( sub , subConfig ) ;
sources . push_back ( std : : pair < int , LocalTests * > ( * it , cl . createLocalTests ( sub , client . getLocalSourcePosition ( sub ) , subConfig ) ) ) ;
offset - - ;
}
} else {
sources . push_back ( std : : pair < int , LocalTests * > ( * it , cl . createLocalTests ( config . sourceName , client . getLocalSourcePosition ( config . sourceName ) , config ) ) ) ;
2009-12-11 05:54:28 +01:00
}
2007-06-27 22:16:17 +02:00
}
}
2009-12-16 07:43:08 +01:00
sourceArray [ sources . size ( ) + offset ] = - 1 ;
2007-06-27 22:16:17 +02:00
// check whether we have a second client
ClientTest * clientB = cl . getClientB ( ) ;
if ( clientB ) {
accessClientB = clientB - > createSyncTests ( name , sourceIndices , false ) ;
} else {
accessClientB = 0 ;
}
}
SyncTests : : ~ SyncTests ( ) {
for ( source_it it = sources . begin ( ) ;
it ! = sources . end ( ) ;
+ + it ) {
delete it - > second ;
}
delete [ ] sourceArray ;
if ( accessClientB ) {
delete accessClientB ;
}
}
/** adds the supported tests to the instance itself */
void SyncTests : : addTests ( ) {
if ( sources . size ( ) ) {
const ClientTest : : Config & config ( sources [ 0 ] . second - > config ) ;
// run this test first, even if it is more complex:
// if it works, all the following tests will run with
// the server in a deterministic state
if ( config . createSourceA ) {
if ( config . insertItem ) {
ADD_TEST ( SyncTests , testDeleteAllRefresh ) ;
}
}
ADD_TEST ( SyncTests , testTwoWaySync ) ;
ADD_TEST ( SyncTests , testSlowSync ) ;
ADD_TEST ( SyncTests , testRefreshFromServerSync ) ;
ADD_TEST ( SyncTests , testRefreshFromClientSync ) ;
2009-03-11 15:01:07 +01:00
if ( config . compare & &
2009-05-14 19:51:58 +02:00
config . testcases ) {
2009-03-11 15:01:07 +01:00
ADD_TEST ( SyncTests , testConversion ) ;
}
2007-06-27 22:16:17 +02:00
if ( config . createSourceA ) {
if ( config . insertItem ) {
2009-05-02 11:32:18 +02:00
ADD_TEST ( SyncTests , testRefreshFromServerSemantic ) ;
ADD_TEST ( SyncTests , testRefreshFromClientSemantic ) ;
2007-06-27 22:16:17 +02:00
ADD_TEST ( SyncTests , testRefreshStatus ) ;
if ( accessClientB & &
config . dump & &
config . compare ) {
ADD_TEST ( SyncTests , testCopy ) ;
ADD_TEST ( SyncTests , testDelete ) ;
ADD_TEST ( SyncTests , testAddUpdate ) ;
ADD_TEST ( SyncTests , testManyItems ) ;
2009-10-16 18:16:46 +02:00
ADD_TEST ( SyncTests , testManyDeletes ) ;
2009-07-25 23:00:21 +02:00
ADD_TEST ( SyncTests , testSlowSyncSemantic ) ;
2009-07-30 16:31:19 +02:00
ADD_TEST ( SyncTests , testComplexRefreshFromServerSemantic ) ;
2007-06-27 22:16:17 +02:00
if ( config . updateItem ) {
ADD_TEST ( SyncTests , testUpdate ) ;
}
if ( config . complexUpdateItem ) {
ADD_TEST ( SyncTests , testComplexUpdate ) ;
}
if ( config . mergeItem1 & & config . mergeItem2 ) {
ADD_TEST ( SyncTests , testMerge ) ;
2006-12-05 23:23:27 +01:00
}
2007-06-27 22:16:17 +02:00
if ( config . import ) {
ADD_TEST ( SyncTests , testTwinning ) ;
ADD_TEST ( SyncTests , testItems ) ;
2009-03-17 14:16:49 +01:00
ADD_TEST ( SyncTests , testItemsXML ) ;
2007-06-27 22:16:17 +02:00
}
if ( config . templateItem ) {
ADD_TEST ( SyncTests , testMaxMsg ) ;
ADD_TEST ( SyncTests , testLargeObject ) ;
ADD_TEST ( SyncTests , testOneWayFromServer ) ;
ADD_TEST ( SyncTests , testOneWayFromClient ) ;
2007-02-11 12:14:26 +01:00
}
2006-12-05 23:23:27 +01:00
}
}
}
2009-02-18 12:39:51 +01:00
2009-06-26 08:01:02 +02:00
if ( config . retrySync & &
2009-02-18 12:39:51 +01:00
config . insertItem & &
config . updateItem & &
accessClientB & &
config . dump & &
config . compare ) {
CppUnit : : TestSuite * retryTests = new CppUnit : : TestSuite ( getName ( ) + " ::Retry " ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeClientAdd ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeClientRemove ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeClientUpdate ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeServerAdd ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeServerRemove ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeServerUpdate ) ;
2010-02-26 17:19:12 +01:00
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeClientAddBig ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeClientUpdateBig ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeServerAddBig ) ;
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeServerUpdateBig ) ;
2009-02-18 12:39:51 +01:00
ADD_TEST_TO_SUITE ( retryTests , SyncTests , testInterruptResumeFull ) ;
2009-07-13 18:24:55 +02:00
addTest ( FilterTest ( retryTests ) ) ;
2009-02-18 12:39:51 +01:00
}
2009-06-26 08:01:02 +02:00
2009-08-31 03:54:36 +02:00
if ( config . suspendSync & &
2009-06-26 08:01:02 +02:00
config . insertItem & &
config . updateItem & &
accessClientB & &
config . dump & &
config . compare ) {
CppUnit : : TestSuite * suspendTests = new CppUnit : : TestSuite ( getName ( ) + " ::Suspend " ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendClientAdd ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendClientRemove ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendClientUpdate ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendServerAdd ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendServerRemove ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendServerUpdate ) ;
2010-03-18 18:28:23 +01:00
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendClientAddBig ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendClientUpdateBig ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendServerAddBig ) ;
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendServerUpdateBig ) ;
2009-06-26 08:01:02 +02:00
ADD_TEST_TO_SUITE ( suspendTests , SyncTests , testUserSuspendFull ) ;
2009-07-13 18:24:55 +02:00
addTest ( FilterTest ( suspendTests ) ) ;
2009-06-26 08:01:02 +02:00
}
2009-08-31 03:54:36 +02:00
if ( config . resendSync & &
2009-07-22 10:44:06 +02:00
config . insertItem & &
config . updateItem & &
accessClientB & &
config . dump & &
config . compare ) {
CppUnit : : TestSuite * resendTests = new CppUnit : : TestSuite ( getName ( ) + " ::Resend " ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendClientAdd ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendClientRemove ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendClientUpdate ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendServerAdd ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendServerRemove ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendServerUpdate ) ;
ADD_TEST_TO_SUITE ( resendTests , SyncTests , testResendFull ) ;
addTest ( FilterTest ( resendTests ) ) ;
}
2006-12-05 23:23:27 +01:00
}
2007-06-27 22:16:17 +02:00
}
2007-06-06 10:37:35 +02:00
2008-12-28 21:26:58 +01:00
bool SyncTests : : compareDatabases ( const char * refFileBase , bool raiseAssert ) {
2007-06-27 22:16:17 +02:00
source_it it1 ;
source_it it2 ;
2008-12-28 21:26:58 +01:00
bool equal = true ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( accessClientB ) ;
for ( it1 = sources . begin ( ) , it2 = accessClientB - > sources . begin ( ) ;
it1 ! = sources . end ( ) & & it2 ! = accessClientB - > sources . end ( ) ;
+ + it1 , + + it2 ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( it2 - > second - > createSourceB ( ) ) ) ;
2008-12-28 21:26:58 +01:00
if ( refFileBase ) {
std : : string refFile = refFileBase ;
refFile + = it1 - > second - > config . sourceName ;
refFile + = " .dat " ;
simplifyFilename ( refFile ) ;
if ( ! it1 - > second - > compareDatabases ( refFile . c_str ( ) , * copy . get ( ) , raiseAssert ) ) {
equal = false ;
}
} else {
if ( ! it1 - > second - > compareDatabases ( NULL , * copy . get ( ) , raiseAssert ) ) {
equal = false ;
}
}
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2006-12-01 23:49:15 +01:00
}
2007-06-27 22:16:17 +02:00
CPPUNIT_ASSERT ( it1 = = sources . end ( ) ) ;
CPPUNIT_ASSERT ( it2 = = accessClientB - > sources . end ( ) ) ;
2008-12-28 21:26:58 +01:00
CPPUNIT_ASSERT ( ! raiseAssert | | equal ) ;
return equal ;
2007-06-27 22:16:17 +02:00
}
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
/** deletes all items locally and on server */
void SyncTests : : deleteAll ( DeleteAllMode mode ) {
source_it it ;
2008-12-21 22:37:53 +01:00
SyncPrefix prefix ( " deleteall " , * this ) ;
2006-12-05 23:23:27 +01:00
2010-03-08 07:43:16 +01:00
const char * value = getenv ( " CLIENT_TEST_DELETE_REFRESH " ) ;
if ( value ) {
mode = DELETE_ALL_REFRESH ;
}
2007-06-27 22:16:17 +02:00
switch ( mode ) {
case DELETE_ALL_SYNC :
// a refresh from server would slightly reduce the amount of data exchanged, but not all servers support it
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " init " , SyncOptions ( SYNC_SLOW ) ) ;
2007-06-27 22:16:17 +02:00
// now that client and server are in sync, delete locally and sync again
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " twoway " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , - 1 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
break ;
case DELETE_ALL_REFRESH :
// delete locally and then tell the server to "copy" the empty databases
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " refreshserver " ,
SyncOptions ( SYNC_REFRESH_FROM_CLIENT ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , - 1 , true , SYNC_REFRESH_FROM_CLIENT ) ) ) ;
2007-06-27 22:16:17 +02:00
break ;
2006-12-05 23:23:27 +01:00
}
2007-06-27 22:16:17 +02:00
}
/** get both clients in sync with empty server, then copy one item from client A to B */
void SyncTests : : doCopy ( ) {
2008-12-21 22:37:53 +01:00
SyncPrefix ( " copy " , * this ) ;
2007-06-27 22:16:17 +02:00
// check requirements
CPPUNIT_ASSERT ( accessClientB ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
deleteAll ( ) ;
accessClientB - > deleteAll ( ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// insert into first database, copy to server
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
2006-12-01 23:49:15 +01:00
}
2009-03-11 11:22:23 +01:00
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// copy into second database
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " recv " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 1 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
compareDatabases ( ) ;
}
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
/**
* replicate server database locally : same as SYNC_REFRESH_FROM_SERVER ,
* but done with explicit local delete and then a SYNC_SLOW because some
* servers do no support SYNC_REFRESH_FROM_SERVER
*/
2009-03-17 14:16:49 +01:00
void SyncTests : : refreshClient ( SyncOptions options ) {
2007-06-27 22:16:17 +02:00
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
2006-12-05 23:23:27 +01:00
}
2009-03-17 14:16:49 +01:00
2009-03-11 11:22:23 +01:00
doSync ( " refresh " ,
2009-03-17 14:16:49 +01:00
options
. setSyncMode ( SYNC_SLOW )
. setCheckReport ( CheckSyncReport ( - 1 , 0 , 0 , 0 , 0 , 0 , true , SYNC_SLOW ) ) ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-05 23:23:27 +01:00
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// delete all items, locally and on server using refresh-from-client sync
void SyncTests : : testDeleteAllRefresh ( ) {
source_it it ;
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// copy something to server first; doesn't matter whether it has the
// item already or not, as long as it exists there afterwards
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " insert " , SyncOptions ( SYNC_SLOW ) ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// now ensure we can delete it
2010-02-12 07:09:34 +01:00
deleteAll ( DELETE_ALL_REFRESH ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// nothing stored locally?
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceA ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
2006-12-05 23:23:27 +01:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// make sure server really deleted everything
2009-03-11 11:22:23 +01:00
doSync ( " check " ,
SyncOptions ( SYNC_SLOW ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_SLOW ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceA ( ) ) ) ;
2006-12-05 23:23:27 +01:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2007-06-27 22:16:17 +02:00
}
}
2006-12-05 23:23:27 +01:00
2009-05-02 11:32:18 +02:00
// test that a refresh sync from an empty server leads to an empty datatbase
2008-02-03 11:18:45 +01:00
// and no changes are sent to server during next two-way sync
2009-05-02 11:32:18 +02:00
void SyncTests : : testRefreshFromServerSemantic ( ) {
2007-06-27 22:16:17 +02:00
source_it it ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// clean client and server
deleteAll ( ) ;
// insert item, then refresh from empty server
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
}
2009-05-02 11:32:18 +02:00
doSync ( " refresh " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
2009-03-11 11:22:23 +01:00
CheckSyncReport ( 0 , 0 , - 1 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
2007-06-27 22:16:17 +02:00
// check
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceA ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
2006-12-05 23:23:27 +01:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " two-way " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-05 23:23:27 +01:00
2009-05-02 11:32:18 +02:00
// test that a refresh sync from an empty client leads to an empty datatbase
// and no changes are sent to server during next two-way sync
void SyncTests : : testRefreshFromClientSemantic ( ) {
source_it it ;
// clean client and server
deleteAll ( ) ;
// insert item, send to server
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
}
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
// delete locally
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
// refresh from client
doSync ( " refresh " ,
SyncOptions ( SYNC_REFRESH_FROM_CLIENT ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_CLIENT ) ) ) ;
// check
doSync ( " check " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
}
2007-06-27 22:16:17 +02:00
// tests the following sequence of events:
// - insert item
// - delete all items
// - insert one other item
// - refresh from client
// => no items should now be listed as new, updated or deleted for this client during another sync
void SyncTests : : testRefreshStatus ( ) {
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
}
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testSimpleInsert ( ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " refresh-from-client " ,
SyncOptions ( SYNC_REFRESH_FROM_CLIENT ,
CheckSyncReport ( 0 , 0 , 0 , - 1 , - 1 , - 1 , /* strictly speaking 1,0,0, but not sure exactly what the server will be told */
true , SYNC_REFRESH_FROM_CLIENT ) ) ) ;
doSync ( " two-way " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// test that a two-way sync copies updates from database to the other client,
// using simple data commonly supported by servers
void SyncTests : : testUpdate ( ) {
CPPUNIT_ASSERT ( sources . begin ( ) ! = sources . end ( ) ) ;
CPPUNIT_ASSERT ( sources . begin ( ) - > second - > config . updateItem ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// setup client A, B and server so that they all contain the same item
doCopy ( ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
it - > second - > update ( it - > second - > createSourceA , it - > second - > config . updateItem ) ;
2006-12-05 23:23:27 +01:00
}
2009-03-11 11:22:23 +01:00
doSync ( " update " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 1 , 0 , true , SYNC_TWO_WAY ) ) ) ;
accessClientB - > doSync ( " update " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 1 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
compareDatabases ( ) ;
}
// test that a two-way sync copies updates from database to the other client,
// using data that some, but not all servers support, like adding a second
// phone number to a contact
void SyncTests : : testComplexUpdate ( ) {
// setup client A, B and server so that they all contain the same item
doCopy ( ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
2007-10-23 23:11:38 +02:00
it - > second - > update ( it - > second - > createSourceA ,
/* this test might get executed with some sources which have
a complex update item while others don ' t : use the normal update item
for them or even just the same item */
it - > second - > config . complexUpdateItem ? it - > second - > config . complexUpdateItem :
it - > second - > config . updateItem ? it - > second - > config . updateItem :
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
it - > second - > config . insertItem
2007-10-23 23:11:38 +02:00
) ;
2006-12-05 23:23:27 +01:00
}
2009-03-11 11:22:23 +01:00
doSync ( " update " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 1 , 0 , true , SYNC_TWO_WAY ) ) ) ;
accessClientB - > doSync ( " update " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 1 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
compareDatabases ( ) ;
}
// test that a two-way sync deletes the copy of an item in the other database
void SyncTests : : testDelete ( ) {
// setup client A, B and server so that they all contain the same item
doCopy ( ) ;
// delete it on A
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// transfer change from A to server to B
2009-03-11 11:22:23 +01:00
doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 1 , true , SYNC_TWO_WAY ) ) ) ;
accessClientB - > doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 1 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// check client B: shouldn't have any items now
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( it - > second - > createSourceA ( ) ) ) ;
2006-12-05 23:23:27 +01:00
SOURCE_ASSERT_EQUAL ( copy . get ( ) , 0 , countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2007-06-27 22:16:17 +02:00
}
}
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// test what the server does when it finds that different
// fields of the same item have been modified
void SyncTests : : testMerge ( ) {
// setup client A, B and server so that they all contain the same item
doCopy ( ) ;
2006-12-05 23:23:27 +01:00
2007-06-27 22:16:17 +02:00
// update in client A
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
it - > second - > update ( it - > second - > createSourceA , it - > second - > config . mergeItem1 ) ;
2007-06-27 22:16:17 +02:00
}
// update in client B
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
it - > second - > update ( it - > second - > createSourceA , it - > second - > config . mergeItem2 ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-05 23:23:27 +01:00
2009-06-12 12:22:21 +02:00
// send change to server from client A (no conflict)
doSync ( " update " ,
2009-03-11 11:22:23 +01:00
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 1 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2009-06-12 12:22:21 +02:00
// Now the changes from client B (conflict!).
// There are several possible outcomes:
// - client item completely replaces server item
// - server item completely replaces client item (update on client)
// - server merges and updates client
accessClientB - > doSync ( " conflict " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-05 23:23:27 +01:00
2009-06-12 12:22:21 +02:00
// figure out how the conflict during ".conflict" was handled
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr copy ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , copy . reset ( it - > second - > createSourceA ( ) ) ) ;
2008-06-25 19:15:47 +02:00
int numItems = 0 ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( copy . get ( ) , numItems = countItems ( copy . get ( ) ) ) ;
CPPUNIT_ASSERT ( numItems > = 1 ) ;
CPPUNIT_ASSERT ( numItems < = 2 ) ;
2009-06-12 12:22:21 +02:00
std : : cout < < " \" " < < it - > second - > config . sourceName < < " : " < < ( numItems = = 1 ? " conflicting items were merged " : " both of the conflicting items were preserved " ) < < " \" " ;
2007-06-27 22:16:17 +02:00
std : : cout . flush ( ) ;
2009-06-12 12:22:21 +02:00
CPPUNIT_ASSERT_NO_THROW ( copy . reset ( ) ) ;
2006-12-05 23:23:27 +01:00
}
2009-06-12 12:22:21 +02:00
// now pull the same changes into client A
doSync ( " refresh " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( - 1 , - 1 , - 1 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
// client A and B should have identical data now
compareDatabases ( ) ;
// Furthermore, it should be identical with the server.
// Be extra careful and pull that data anew and compare once more.
doSync ( " check " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
compareDatabases ( ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// test what the server does when it has to execute a slow sync
// with identical data on client and server:
// expected behaviour is that nothing changes
void SyncTests : : testTwinning ( ) {
// clean server and client A
deleteAll ( ) ;
// import test data
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testImport ( ) ;
}
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// send to server
2009-03-11 11:22:23 +01:00
doSync ( " send " , SyncOptions ( SYNC_TWO_WAY ) ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// ensure that client has the same data, thus ignoring data conversion
// issues (those are covered by testItems())
refreshClient ( ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// copy to client B to have another copy
accessClientB - > refreshClient ( ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// slow sync should not change anything
2009-12-11 06:50:26 +01:00
doSync ( " twinning " , SyncOptions ( SYNC_SLOW ) ) ;
2006-12-01 23:49:15 +01:00
2007-06-27 22:16:17 +02:00
// check
compareDatabases ( ) ;
}
2007-02-08 22:58:13 +01:00
2007-06-27 22:16:17 +02:00
// tests one-way sync from server:
// - 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
// - two-way sync with first client
// => one item on first client, two on second
// - 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 ( ) {
// no items anywhere
deleteAll ( ) ;
accessClientB - > refreshClient ( ) ;
// check that everything is empty, also resets change tracking
// in second sources of each client
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-01 23:49:15 +01:00
}
}
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// add one item on first client, copy to server, and check change tracking via second source
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
2009-07-17 11:04:24 +02:00
it - > second - > insertManyItems ( it - > second - > createSourceA , 200 , 1 ) ;
2007-06-27 22:16:17 +02:00
}
2009-03-11 11:22:23 +01:00
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
}
2007-06-27 22:16:17 +02:00
// add a different item on second client, one-way-from-server
// => one item added locally, none sent to server
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
it - > second - > insertManyItems ( it - > second - > createSourceA , 2 , 1 ) ;
2006-12-07 23:25:22 +01:00
2007-06-27 22:16:17 +02:00
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
}
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " recv " ,
SyncOptions ( SYNC_ONE_WAY_FROM_SERVER ,
CheckSyncReport ( 1 , 0 , 0 , 0 , 0 , 0 , true , SYNC_ONE_WAY_FROM_SERVER ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 2 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
}
2007-06-27 22:16:17 +02:00
// two-way sync with first client for verification
// => no changes
2009-03-11 11:22:23 +01:00
doSync ( " check " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
2007-06-27 22:16:17 +02:00
}
2006-12-07 23:25:22 +01:00
2007-06-27 22:16:17 +02:00
// delete items on clientA, sync to server
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
2006-12-07 23:25:22 +01:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
2006-12-07 23:25:22 +01:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
2007-06-27 22:16:17 +02:00
}
2009-03-11 11:22:23 +01:00
doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 1 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
2006-12-07 23:25:22 +01:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
2006-12-07 23:25:22 +01:00
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
}
2007-06-27 22:16:17 +02:00
// sync the same change to second client
// => one item left (the one inserted locally)
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " delete " ,
SyncOptions ( SYNC_ONE_WAY_FROM_SERVER ,
CheckSyncReport ( 0 , 0 , 1 , 0 , 0 , 0 , true , SYNC_ONE_WAY_FROM_SERVER ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
2007-06-27 22:16:17 +02:00
}
}
2006-12-07 23:25:22 +01:00
2007-06-27 22:16:17 +02:00
// tests one-way sync from client:
// - 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
// - two-way sync with first client
// => two items on first client, one on second
// - 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 ( ) {
// no items anywhere
deleteAll ( ) ;
accessClientB - > deleteAll ( ) ;
// check that everything is empty, also resets change tracking
// in second sources of each client
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
2006-12-07 23:25:22 +01:00
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
}
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
}
2007-06-27 22:16:17 +02:00
// add one item on first client, copy to server, and check change tracking via second source
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > insertManyItems ( it - > second - > createSourceA , 1 , 1 ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-07 23:25:22 +01:00
}
}
2007-06-27 22:16:17 +02:00
// add a different item on second client, one-way-from-client
// => no item added locally, one sent to server
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
it - > second - > insertManyItems ( it - > second - > createSourceA , 2 , 1 ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
}
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " send " ,
SyncOptions ( SYNC_ONE_WAY_FROM_CLIENT ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_ONE_WAY_FROM_CLIENT ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
2007-06-27 22:16:17 +02:00
}
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// two-way sync with client A for verification
// => receive one item
2009-03-11 11:22:23 +01:00
doSync ( " check " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 1 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 2 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// delete items on client B, sync to server
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
it - > second - > deleteAll ( it - > second - > createSourceA ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
2007-06-27 22:16:17 +02:00
}
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " delete " ,
SyncOptions ( SYNC_ONE_WAY_FROM_CLIENT ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 1 , true , SYNC_ONE_WAY_FROM_CLIENT ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = accessClientB - > sources . begin ( ) ; it ! = accessClientB - > sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
}
2007-06-27 22:16:17 +02:00
// sync the same change to client A
// => one item left (the one inserted locally)
2009-03-11 11:22:23 +01:00
doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 1 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( it - > second - > config . createSourceB ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2007-06-27 22:16:17 +02:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceB ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countNewItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 1 , countDeletedItems ( source . get ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , countUpdatedItems ( source . get ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
2006-12-09 18:50:06 +01:00
}
2007-06-27 22:16:17 +02:00
}
}
2006-12-09 18:50:06 +01:00
2009-03-11 15:01:07 +01:00
// get engine ready, then use it to convert our test items
// to and from the internal field list
void SyncTests : : testConversion ( ) {
bool success = false ;
SyncOptions : : Callback_t callback = boost : : bind ( & SyncTests : : doConversionCallback , this , & success , _1 , _2 ) ;
doSync ( SyncOptions ( SYNC_TWO_WAY , CheckSyncReport ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , false ) )
. setStartCallback ( callback ) ) ;
CPPUNIT_ASSERT ( success ) ;
}
bool SyncTests : : doConversionCallback ( bool * success ,
2009-10-05 14:49:32 +02:00
SyncContext & syncClient ,
2009-03-11 15:01:07 +01:00
SyncOptions & options ) {
* success = false ;
for ( source_it it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
const ClientTest : : Config * config = & it - > second - > config ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSource * source = static_cast < TestingSyncSource * > ( syncClient . findSource ( config - > sourceName ) ) ;
2009-03-11 15:01:07 +01:00
CPPUNIT_ASSERT ( source ) ;
std : : string type = source - > getNativeDatatypeName ( ) ;
if ( type . empty ( ) ) {
continue ;
}
std : : list < std : : string > items ;
2009-07-08 18:38:58 +02:00
std : : string testcases ;
ClientTest : : getItems ( config - > testcases , items , testcases ) ;
2009-03-11 15:01:07 +01:00
std : : string converted = getCurrentTest ( ) ;
2009-05-14 19:51:58 +02:00
converted + = " .converted. " ;
2009-03-11 15:01:07 +01:00
converted + = config - > sourceName ;
converted + = " .dat " ;
simplifyFilename ( converted ) ;
std : : ofstream out ( converted . c_str ( ) ) ;
BOOST_FOREACH ( const string & item , items ) {
string convertedItem = item ;
if ( ! sysync : : DataConversion ( syncClient . getSession ( ) . get ( ) ,
type . c_str ( ) ,
type . c_str ( ) ,
convertedItem ) ) {
SE_LOG_ERROR ( NULL , NULL , " failed parsing as %s: \n %s " ,
type . c_str ( ) ,
item . c_str ( ) ) ;
} else {
out < < convertedItem < < " \n " ;
}
}
out . close ( ) ;
2009-07-08 18:38:58 +02:00
CPPUNIT_ASSERT ( config - > compare ( client , testcases . c_str ( ) , converted . c_str ( ) ) ) ;
2009-03-11 15:01:07 +01:00
}
// abort sync after completing the test successfully (no exception so far!)
* success = true ;
return true ;
}
2007-06-27 22:16:17 +02:00
// creates several items, transmits them back and forth and
// then compares which of them have been preserved
void SyncTests : : testItems ( ) {
// clean server and first test database
deleteAll ( ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// import data
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testImport ( ) ;
2006-12-09 18:50:06 +01:00
}
2007-06-27 22:16:17 +02:00
// transfer from client A to server to client B
2009-03-17 14:16:49 +01:00
doSync ( " send " , SyncOptions ( SYNC_TWO_WAY ) . setWBXML ( true ) ) ;
accessClientB - > refreshClient ( SyncOptions ( ) . setWBXML ( true ) ) ;
compareDatabases ( ) ;
}
// creates several items, transmits them back and forth and
// then compares which of them have been preserved
void SyncTests : : testItemsXML ( ) {
// clean server and first test database
deleteAll ( ) ;
// import data
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
it - > second - > testImport ( ) ;
}
// transfer from client A to server to client B using the non-default XML format
doSync ( " send " , SyncOptions ( SYNC_TWO_WAY ) . setWBXML ( false ) ) ;
accessClientB - > refreshClient ( SyncOptions ( ) . setWBXML ( false ) ) ;
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
compareDatabases ( ) ;
}
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// tests the following sequence of events:
// - both clients in sync with server
// - client 1 adds item
// - client 1 updates the same item
// - client 2 gets item: the client should be asked to add the item
//
// However it has been observed that sometimes the item was sent as "update"
// for a non-existant local item. This is a server bug, the client does not
// have to handle that. See
// http://forge.objectweb.org/tracker/?func=detail&atid=100096&aid=305018&group_id=96
void SyncTests : : testAddUpdate ( ) {
// clean server and both test databases
deleteAll ( ) ;
accessClientB - > refreshClient ( ) ;
// add item
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
2009-04-01 16:46:55 +02:00
it - > second - > insert ( it - > second - > createSourceA , it - > second - > config . insertItem , it - > second - > config . itemType ) ;
2007-06-27 22:16:17 +02:00
}
2009-03-11 11:22:23 +01:00
doSync ( " add " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 1 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// update it
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
it - > second - > update ( it - > second - > createSourceB , it - > second - > config . updateItem ) ;
2007-06-27 22:16:17 +02:00
}
2009-03-11 11:22:23 +01:00
doSync ( " update " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 1 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// now download the updated item into the second client
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " recv " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 1 , 0 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// compare the two databases
compareDatabases ( ) ;
}
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
//
// stress tests: execute some of the normal operations,
// but with large number of artificially generated items
//
// two-way sync with clean client/server,
// followed by slow sync and comparison
// via second client
void SyncTests : : testManyItems ( ) {
// clean server and client A
deleteAll ( ) ;
2007-11-05 20:14:09 +01:00
// import artificial data: make them large to generate some
// real traffic and test buffer handling
2007-06-27 22:16:17 +02:00
source_it it ;
2009-10-16 18:16:46 +02:00
int num_items = - 1 ;
2007-06-27 22:16:17 +02:00
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
2009-10-16 18:16:46 +02:00
if ( num_items = = - 1 ) {
num_items = it - > second - > config . numItems ;
} else {
CPPUNIT_ASSERT_EQUAL ( num_items , it - > second - > config . numItems ) ;
}
it - > second - > insertManyItems ( it - > second - > createSourceA , 0 , num_items , 2000 ) ;
}
// send data to server
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , num_items , 0 , 0 , true , SYNC_TWO_WAY ) ,
2009-07-13 09:34:59 +02:00
SyncOptions : : DEFAULT_MAX_MSG_SIZE ,
SyncOptions : : DEFAULT_MAX_OBJ_SIZE ,
true ) ) ;
2009-10-16 18:16:46 +02:00
// ensure that client has the same data, ignoring data conversion
// issues (those are covered by testItems())
refreshClient ( ) ;
// also copy to second client
accessClientB - > refreshClient ( ) ;
// slow sync now should not change anything
doSync ( " twinning " ,
SyncOptions ( SYNC_SLOW ,
CheckSyncReport ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , true , SYNC_SLOW ) ,
2009-07-13 09:34:59 +02:00
SyncOptions : : DEFAULT_MAX_MSG_SIZE ,
SyncOptions : : DEFAULT_MAX_OBJ_SIZE ,
true ) ) ;
2009-10-16 18:16:46 +02:00
// compare
compareDatabases ( ) ;
}
/**
* Tell server to delete plenty of items .
*/
void SyncTests : : testManyDeletes ( ) {
// clean server and client A
deleteAll ( ) ;
// import artificial data: make them small, we just want
// many of them
source_it it ;
int num_items = - 1 ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
if ( num_items = = - 1 ) {
num_items = it - > second - > config . numItems ;
} else {
CPPUNIT_ASSERT_EQUAL ( num_items , it - > second - > config . numItems ) ;
}
it - > second - > insertManyItems ( it - > second - > createSourceA , 0 , num_items , 100 ) ;
2006-12-09 18:50:06 +01:00
}
2007-06-06 10:37:35 +02:00
2007-06-27 22:16:17 +02:00
// send data to server
2009-03-11 11:22:23 +01:00
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
2009-10-16 18:16:46 +02:00
CheckSyncReport ( 0 , 0 , 0 , num_items , 0 , 0 , true , SYNC_TWO_WAY ) ,
2009-03-11 11:22:23 +01:00
64 * 1024 , 64 * 1024 , true ) ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// ensure that client has the same data, ignoring data conversion
// issues (those are covered by testItems())
refreshClient ( ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// also copy to second client
accessClientB - > refreshClient ( ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// slow sync now should not change anything
2009-03-11 11:22:23 +01:00
doSync ( " twinning " ,
SyncOptions ( SYNC_SLOW ,
CheckSyncReport ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , true , SYNC_SLOW ) ,
64 * 1024 , 64 * 1024 , true ) ) ;
2006-12-09 18:50:06 +01:00
2007-06-27 22:16:17 +02:00
// compare
compareDatabases ( ) ;
2009-10-16 18:16:46 +02:00
// delete everything locally
BOOST_FOREACH ( source_array_t : : value_type & source_pair , sources ) {
source_pair . second - > deleteAll ( source_pair . second - > createSourceA ) ;
}
doSync ( " delete-server " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , num_items , true , SYNC_TWO_WAY ) ,
10 * 1024 ) ) ;
// update second client
accessClientB - > doSync ( " delete-client " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( 0 , 0 , num_items , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ,
10 & 1024 ) ) ;
2007-06-27 22:16:17 +02:00
}
2006-12-09 18:50:06 +01:00
2009-07-25 23:00:21 +02:00
/**
* - get client A , server , client B in sync with one item
* - force slow sync in A : must not duplicate items , but may update it locally
* - refresh client B ( in case that the item was updated )
* - delete item in B and server via two - way sync
* - refresh - from - server in B to check that item is gone
* - two - way in A : must delete the item
*/
void SyncTests : : testSlowSyncSemantic ( )
{
// set up one item everywhere
doCopy ( ) ;
// slow in A
doSync ( " slow " ,
SyncOptions ( SYNC_SLOW ,
CheckSyncReport ( 0 , - 1 , 0 , - 1 , - 1 , 0 , true , SYNC_SLOW ) ) ) ;
// refresh B, delete item
accessClientB - > doSync ( " refresh " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , - 1 , 0 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
BOOST_FOREACH ( source_array_t : : value_type & source_pair , accessClientB - > sources ) {
source_pair . second - > deleteAll ( source_pair . second - > createSourceA ) ;
}
accessClientB - > doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 1 , true , SYNC_TWO_WAY ) ) ) ;
accessClientB - > doSync ( " check " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
// now the item should also be deleted on A
doSync ( " delete " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 1 , 0 , 0 , 0 , true , SYNC_TWO_WAY ) ) ) ;
}
2006-12-09 18:50:06 +01:00
2009-07-30 16:31:19 +02:00
/**
* check that refresh - from - server works correctly :
* - create the same item on A , server , B via testCopy ( )
* - refresh B ( one item deleted , one created )
* - delete item on A and server
* - refresh B ( one item deleted )
*/
void SyncTests : : testComplexRefreshFromServerSemantic ( )
{
testCopy ( ) ;
// check refresh with one item on server
accessClientB - > doSync ( " refresh-one " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( 1 , 0 , 1 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
// delete that item via A, check again
BOOST_FOREACH ( source_array_t : : value_type & source_pair , sources ) {
source_pair . second - > deleteAll ( source_pair . second - > createSourceA ) ;
}
doSync ( " delete-item " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , 0 , 0 , 1 , true , SYNC_TWO_WAY ) ) ) ;
accessClientB - > doSync ( " refresh-none " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( 0 , 0 , 1 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) ) ) ;
}
2007-06-27 22:16:17 +02:00
/**
* implements testMaxMsg ( ) , testLargeObject ( ) , testLargeObjectEncoded ( )
* using a sequence of items with varying sizes
*/
void SyncTests : : doVarSizes ( bool withMaxMsgSize ,
2009-03-17 14:16:49 +01:00
bool withLargeObject ) {
2009-06-29 09:59:57 +02:00
int maxMsgSize = 8 * 1024 ;
const char * maxItemSize = getenv ( " CLIENT_TEST_MAX_ITEMSIZE " ) ;
int tmpSize = maxItemSize ? atoi ( maxItemSize ) : 0 ;
2009-07-08 05:01:18 +02:00
if ( tmpSize > 0 )
2009-06-29 09:59:57 +02:00
maxMsgSize = tmpSize ;
2007-06-27 22:16:17 +02:00
// clean server and client A
deleteAll ( ) ;
// insert items, doubling their size, then restart with small size
source_it it ;
for ( it = sources . begin ( ) ; it ! = sources . end ( ) ; + + it ) {
int item = 1 ;
for ( int i = 0 ; i < 2 ; i + + ) {
int size = 1 ;
while ( size < 2 * maxMsgSize ) {
it - > second - > insertManyItems ( it - > second - > createSourceA , item , 1 , ( int ) strlen ( it - > second - > config . templateItem ) + 10 + size ) ;
size * = 2 ;
item + + ;
2006-12-09 18:50:06 +01:00
}
}
}
2007-06-27 22:16:17 +02:00
// transfer to server
2009-03-11 11:22:23 +01:00
doSync ( " send " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( 0 , 0 , 0 , - 1 , 0 , 0 , true , SYNC_TWO_WAY ) , // number of items sent to server depends on source
2009-07-13 09:34:59 +02:00
withMaxMsgSize ? SyncOptions : : DEFAULT_MAX_MSG_SIZE : 0 ,
withMaxMsgSize ? SyncOptions : : DEFAULT_MAX_OBJ_SIZE : 0 ,
2009-03-17 14:16:49 +01:00
withLargeObject ) ) ;
2007-06-27 22:16:17 +02:00
// copy to second client
2009-12-11 10:22:47 +01:00
const char * value = getenv ( " CLIENT_TEST_NOREFRESH " ) ;
// If refresh_from_server or refresh_from_client (depending on this is a
// server or client) is not supported, we can still test via slow sync.
if ( value ) {
accessClientB - > refreshClient ( ) ;
} else {
accessClientB - > doSync ( " recv " ,
SyncOptions ( SYNC_REFRESH_FROM_SERVER ,
CheckSyncReport ( - 1 , 0 , - 1 , 0 , 0 , 0 , true , SYNC_REFRESH_FROM_SERVER ) , // 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 ) ) ;
}
2007-06-27 22:16:17 +02:00
// compare
compareDatabases ( ) ;
}
2006-12-09 18:50:06 +01:00
2010-02-26 10:49:35 +01:00
/**
* Send message to server , then pretend that we timed out at exactly
* one specific message , specified via m_interruptAtMessage . The
* caller is expected to resend the message , without aborting the
* session . That resend and all following message will get through
* again .
*
* Each send ( ) is counted as one message , starting at 1 for the first
* message .
*/
2009-07-22 10:44:06 +02:00
class TransportResendInjector : public TransportWrapper {
private :
int timeout ;
public :
TransportResendInjector ( )
: TransportWrapper ( ) {
const char * s = getenv ( " CLIENT_TEST_RESEND_TIMEOUT " ) ;
timeout = s ? atoi ( s ) : 0 ;
}
~ TransportResendInjector ( ) {
}
virtual void send ( const char * data , size_t len )
{
m_messageCount + + ;
if ( m_interruptAtMessage > = 0 & &
m_messageCount = = m_interruptAtMessage + 1 ) {
m_wrappedAgent - > send ( data , len ) ;
m_status = m_wrappedAgent - > wait ( ) ;
//trigger client side resend
sleep ( timeout ) ;
m_status = TIME_OUT ;
}
else
{
m_wrappedAgent - > send ( data , len ) ;
m_status = m_wrappedAgent - > wait ( ) ;
}
}
virtual void getReply ( const char * & data , size_t & len , std : : string & contentType ) {
if ( m_status = = FAILED ) {
data = " " ;
len = 0 ;
} else {
m_wrappedAgent - > getReply ( data , len , contentType ) ;
}
}
} ;
2010-02-26 10:49:35 +01:00
/**
* Stop sending at m_interruptAtMessage . The caller is forced to abort
* the current session and will recover by retrying in another
* session .
*
* Each send ( ) increments the counter by two , so that 1 aborts before
* the first message and 2 after it .
*/
2009-06-26 08:01:02 +02:00
class TransportFaultInjector : public TransportWrapper {
2008-12-22 19:52:00 +01:00
public :
2009-06-26 08:01:02 +02:00
TransportFaultInjector ( )
: TransportWrapper ( ) {
2008-12-22 19:52:00 +01:00
}
2009-06-26 08:01:02 +02:00
2008-12-22 19:52:00 +01:00
~ TransportFaultInjector ( ) {
}
2009-02-18 12:39:51 +01:00
virtual void send ( const char * data , size_t len )
{
2008-12-22 19:52:00 +01:00
if ( m_interruptAtMessage = = m_messageCount ) {
2009-02-18 12:39:51 +01:00
SE_LOG_DEBUG ( NULL , NULL , " TransportFaultInjector: interrupt before sending message #%d " , m_messageCount ) ;
2008-12-22 19:52:00 +01:00
}
m_messageCount + + ;
if ( m_interruptAtMessage > = 0 & &
m_messageCount > m_interruptAtMessage ) {
2009-02-18 12:39:51 +01:00
throw string ( " TransportFaultInjector: interrupt before send " ) ;
2008-12-22 19:52:00 +01:00
}
2009-02-18 12:39:51 +01:00
m_wrappedAgent - > send ( data , len ) ;
m_status = m_wrappedAgent - > wait ( ) ;
2008-12-22 19:52:00 +01:00
if ( m_interruptAtMessage = = m_messageCount ) {
2009-02-18 12:39:51 +01:00
SE_LOG_DEBUG ( NULL , NULL , " TransportFaultInjector: interrupt after receiving reply #%d " , m_messageCount ) ;
2008-12-22 19:52:00 +01:00
}
m_messageCount + + ;
if ( m_interruptAtMessage > = 0 & &
m_messageCount > m_interruptAtMessage ) {
2009-02-18 12:39:51 +01:00
m_status = FAILED ;
}
}
2009-03-31 15:25:47 +02:00
virtual void getReply ( const char * & data , size_t & len , std : : string & contentType ) {
2009-02-18 12:39:51 +01:00
if ( m_status = = FAILED ) {
data = " " ;
len = 0 ;
} else {
2009-03-31 15:25:47 +02:00
m_wrappedAgent - > getReply ( data , len , contentType ) ;
2008-12-22 19:52:00 +01:00
}
}
} ;
2009-06-26 08:01:02 +02:00
/**
* Emulates a user suspend just after receving response
* from server .
*/
class UserSuspendInjector : public TransportWrapper {
public :
UserSuspendInjector ( )
: TransportWrapper ( ) {
}
~ UserSuspendInjector ( ) {
}
virtual void send ( const char * data , size_t len )
{
m_wrappedAgent - > send ( data , len ) ;
m_status = m_wrappedAgent - > wait ( ) ;
}
virtual void getReply ( const char * & data , size_t & len , std : : string & contentType ) {
if ( m_status = = FAILED ) {
data = " " ;
len = 0 ;
} else {
if ( m_interruptAtMessage = = m_messageCount ) {
SE_LOG_DEBUG ( NULL , NULL , " UserSuspendInjector: user suspend after getting reply #%d " , m_messageCount ) ;
}
m_messageCount + + ;
if ( m_interruptAtMessage > = 0 & &
m_messageCount > m_interruptAtMessage ) {
m_options - > m_isSuspended = true ;
}
m_wrappedAgent - > getReply ( data , len , contentType ) ;
}
}
} ;
2008-12-22 19:52:00 +01:00
/**
* This function covers different error scenarios that can occur
* during real synchronization . To pass , clients must either force a
* slow synchronization after a failed synchronization or implement
* the error handling described in the design guide ( track server ' s
* status for added / updated / deleted items and resend unacknowledged
* changes ) .
*
* The items used during these tests are synthetic . They are
* constructed so that normally a server should be able to handle
* twinning during a slow sync correctly .
*
* Errors are injected into a synchronization by wrapping the normal
* HTTP transport agent . The wrapper enumerates messages sent between
* client and server ( i . e . , one message exchange increments the
* counter by two ) , starting from zero . It " cuts " the connection before
* sending out the next message to the server respectively after the
* server has replied , but before returning the reply to the client .
* The first case simulates a lost message from the client to the server
* and the second case a lost message from the server to the client .
*
* The expected result is the same as in an uninterrupted sync , which
* is done once at the beginning .
*
* Each test goes through the following steps :
* - client A and B reset local data store
* - client A creates 3 new items , remembers LUIDs
* - refresh - from - client A sync
* - refresh - from - client B sync
* - client B creates 3 different items , remembers LUIDs
* - client B syncs
* - client A syncs = > A , B , server are in sync
* - client A modifies his items ( depends on test ) and
* sends changes to server = > server has changes for B
* - client B modifies his items ( depends on test )
* - client B syncs , transport wrapper simulates lost message n
* - client B syncs again , resuming synchronization if possible or
* slow sync otherwise ( responsibility of the client ! )
* - client A syncs ( not tested yet : A should be sent exactly the changes made by B )
* - test that A and B contain same items
* - test that A contains the same items as the uninterrupted reference run
* - repeat the steps above ranging starting with lost message 0 until no
* message got lost
2008-12-27 16:10:03 +01:00
*
* Set the CLIENT_TEST_INTERRUPT_AT env variable to a message number
* > = 0 to execute one uninterrupted run and then interrupt at that
2010-02-26 10:49:35 +01:00
* message . Set to - 1 to just do the uninterrupted run .
2008-12-22 19:52:00 +01:00
*/
2009-06-26 08:01:02 +02:00
void SyncTests : : doInterruptResume ( int changes ,
boost : : shared_ptr < TransportWrapper > wrapper )
2008-12-22 19:52:00 +01:00
{
int interruptAtMessage = - 1 ;
2008-12-27 16:10:03 +01:00
const char * t = getenv ( " CLIENT_TEST_INTERRUPT_AT " ) ;
2010-02-26 10:49:35 +01:00
int requestedInterruptAt = t ? atoi ( t ) : - 2 ;
2009-06-26 08:01:02 +02:00
const char * s = getenv ( " CLIENT_TEST_INTERRUPT_SLEEP " ) ;
int sleep_t = s ? atoi ( s ) : 0 ;
2009-02-18 12:39:51 +01:00
size_t i ;
2008-12-28 21:29:26 +01:00
std : : string refFileBase = getCurrentTest ( ) + " .ref. " ;
bool equal = true ;
2010-02-26 10:49:35 +01:00
bool resend = dynamic_cast < TransportResendInjector * > ( wrapper . get ( ) ) ! = NULL ;
2010-03-16 17:22:46 +01:00
bool suspend = dynamic_cast < UserSuspendInjector * > ( wrapper . get ( ) ) ! = NULL ;
bool interrupt = dynamic_cast < TransportFaultInjector * > ( wrapper . get ( ) ) ! = NULL ;
2008-12-22 19:52:00 +01:00
2010-02-26 17:19:12 +01:00
// better be large enough for complete DevInf, 20000 is already a
// bit small when running with many stores
size_t maxMsgSize = 20000 ;
size_t changedItemSize = ( changes & BIG ) ?
2010-03-15 16:27:30 +01:00
5 * maxMsgSize / 2 : // large enough to be split over three messages
2010-02-26 17:19:12 +01:00
0 ;
2010-03-05 18:12:45 +01:00
// After running the uninterrupted sync, we remember the number
// of sent messages. We never interrupt between sending our
// own last message and receiving the servers last reply,
// because the server is unable to detect that we didn't get
// the reply. It will complete the session whereas the client
// suspends, leading to an unexpected slow sync the next time.
int maxMsgNum = 0 ;
2008-12-22 19:52:00 +01:00
while ( true ) {
char buffer [ 80 ] ;
sprintf ( buffer , " %d " , interruptAtMessage ) ;
const char * prefix = interruptAtMessage = = - 1 ? " complete " : buffer ;
SyncPrefix prefixA ( prefix , * this ) ;
SyncPrefix prefixB ( prefix , * accessClientB ) ;
std : : vector < std : : list < std : : string > > clientAluids ;
std : : vector < std : : list < std : : string > > clientBluids ;
// create new items in client A and sync to server
clientAluids . resize ( sources . size ( ) ) ;
for ( i = 0 ; i < sources . size ( ) ; i + + ) {
sources [ i ] . second - > deleteAll ( sources [ i ] . second - > createSourceA ) ;
clientAluids [ i ] =
sources [ i ] . second - > insertManyItems ( sources [ i ] . second - > createSourceA ,
1 , 3 , 0 ) ;
}
2009-03-11 11:22:23 +01:00
doSync ( " fromA " , SyncOptions ( SYNC_REFRESH_FROM_CLIENT ) ) ;
2008-12-22 19:52:00 +01:00
// init client B and add its items to server and client A
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " initB " , SyncOptions ( SYNC_REFRESH_FROM_SERVER ) ) ;
2008-12-22 19:52:00 +01:00
clientBluids . resize ( sources . size ( ) ) ;
for ( i = 0 ; i < sources . size ( ) ; i + + ) {
clientBluids [ i ] =
accessClientB - > sources [ i ] . second - > insertManyItems ( accessClientB - > sources [ i ] . second - > createSourceA ,
11 , 3 , 0 ) ;
}
2009-03-11 11:22:23 +01:00
accessClientB - > doSync ( " fromB " , SyncOptions ( SYNC_TWO_WAY ) ) ;
doSync ( " updateA " , SyncOptions ( SYNC_TWO_WAY ) ) ;
2008-12-22 19:52:00 +01:00
// => client A, B and server in sync with a total of six items
// make changes as requested on client A and sync to server
for ( i = 0 ; i < sources . size ( ) ; i + + ) {
if ( changes & SERVER_ADD ) {
sources [ i ] . second - > insertManyItems ( sources [ i ] . second - > createSourceA ,
2010-02-26 17:19:12 +01:00
4 , 1 , changedItemSize ) ;
2008-12-22 19:52:00 +01:00
}
if ( changes & SERVER_REMOVE ) {
2008-12-28 19:12:17 +01:00
// remove second item
removeItem ( sources [ i ] . second - > createSourceA ,
* ( + + clientAluids [ i ] . begin ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
if ( changes & SERVER_UPDATE ) {
2008-12-28 19:12:17 +01:00
// update third item
updateItem ( sources [ i ] . second - > createSourceA ,
2010-10-14 11:40:45 +02:00
sources [ i ] . second - > config ,
2008-12-28 19:12:17 +01:00
* ( + + + + clientAluids [ i ] . begin ( ) ) ,
2010-02-26 17:19:12 +01:00
sources [ i ] . second - > createItem ( 3 , " updated " , changedItemSize ) . c_str ( ) ) ;
2008-12-28 19:12:17 +01:00
2008-12-22 19:52:00 +01:00
}
}
2010-02-26 17:19:12 +01:00
// send using the same mode as in the interrupted sync with client B
2008-12-22 19:52:00 +01:00
if ( changes & ( SERVER_ADD | SERVER_REMOVE | SERVER_UPDATE ) ) {
2010-02-26 17:19:12 +01:00
doSync ( " changesFromA " , SyncOptions ( SYNC_TWO_WAY ) . setMaxMsgSize ( maxMsgSize ) ) ;
2008-12-22 19:52:00 +01:00
}
// make changes as requested on client B
for ( i = 0 ; i < sources . size ( ) ; i + + ) {
if ( changes & CLIENT_ADD ) {
accessClientB - > sources [ i ] . second - > insertManyItems ( accessClientB - > sources [ i ] . second - > createSourceA ,
2010-02-26 17:19:12 +01:00
14 , 1 , changedItemSize ) ;
2008-12-22 19:52:00 +01:00
}
if ( changes & CLIENT_REMOVE ) {
2008-12-28 19:12:17 +01:00
// remove second item
removeItem ( accessClientB - > sources [ i ] . second - > createSourceA ,
* ( + + clientBluids [ i ] . begin ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
if ( changes & CLIENT_UPDATE ) {
2008-12-28 19:12:17 +01:00
// update third item
updateItem ( accessClientB - > sources [ i ] . second - > createSourceA ,
2010-10-14 11:40:45 +02:00
accessClientB - > sources [ i ] . second - > config ,
2008-12-28 19:12:17 +01:00
* ( + + + + clientBluids [ i ] . begin ( ) ) ,
2010-02-26 17:19:12 +01:00
accessClientB - > sources [ i ] . second - > createItem ( 13 , " updated " , changedItemSize ) . c_str ( ) ) ;
2008-12-22 19:52:00 +01:00
}
}
// Now do an interrupted sync between B and server.
2009-06-26 08:01:02 +02:00
// The explicit delete of the TransportAgent is suppressed
2008-12-22 19:52:00 +01:00
// by overloading the delete operator.
int wasInterrupted ;
{
2010-03-15 13:22:34 +01:00
CheckSyncReport check ( - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , false ) ;
if ( resend & & interruptAtMessage ! = 0 ) {
// resend tests must succeed, except for the first
// message in the session, which is not resent
check . mustSucceed = true ;
}
SyncOptions options ( SYNC_TWO_WAY , check ) ;
2010-03-05 17:24:49 +01:00
options . setTransportAgent ( wrapper ) ;
options . setMaxMsgSize ( maxMsgSize ) ;
if ( ! resend ) {
// disable resending completely
options . setRetryInterval ( 0 ) ;
}
2009-06-26 08:01:02 +02:00
wrapper - > setInterruptAtMessage ( interruptAtMessage ) ;
2010-03-05 17:24:49 +01:00
accessClientB - > doSync ( " changesFromB " , options ) ;
2008-12-22 19:52:00 +01:00
wasInterrupted = interruptAtMessage ! = - 1 & &
2009-06-26 08:01:02 +02:00
wrapper - > getMessageCount ( ) < = interruptAtMessage ;
2010-03-05 18:12:45 +01:00
if ( ! maxMsgNum ) {
maxMsgNum = wrapper - > getMessageCount ( ) ;
}
2009-11-10 06:50:35 +01:00
wrapper - > rewind ( ) ;
2008-12-22 19:52:00 +01:00
}
if ( interruptAtMessage ! = - 1 ) {
if ( wasInterrupted ) {
// uninterrupted sync, done
break ;
}
2009-06-26 08:01:02 +02:00
// continue, wait until server timeout
if ( sleep_t )
sleep ( sleep_t ) ;
2009-07-22 10:44:06 +02:00
2010-03-16 17:22:46 +01:00
// no need for resend tests, unless they were interrupted at the first message
if ( ! resend | | interruptAtMessage = = 0 ) {
2010-03-18 18:32:49 +01:00
SyncReport report ;
accessClientB - > doSync ( " retryB " ,
SyncOptions ( SYNC_TWO_WAY ,
CheckSyncReport ( ) . setMode ( SYNC_TWO_WAY ) . setReport ( & report ) ) ) ;
// Suspending at first and last message doesn't need a
// resume, everything else does. When multiple sources
// are involved, some may suspend, some may not, so we
// cannot check.
if ( suspend & &
interruptAtMessage ! = 0 & &
interruptAtMessage + 1 ! = maxMsgNum & &
report . size ( ) = = 1 ) {
BOOST_FOREACH ( const SyncReport : : SourceReport_t & sourceReport , report ) {
CPPUNIT_ASSERT ( sourceReport . second . isResumeSync ( ) ) ;
}
}
2009-07-22 10:44:06 +02:00
}
2008-12-22 19:52:00 +01:00
}
// copy changes to client A
2009-03-11 11:22:23 +01:00
doSync ( " toA " , SyncOptions ( SYNC_TWO_WAY ) ) ;
2008-12-22 19:52:00 +01:00
// compare client A and B
2008-12-28 21:29:26 +01:00
if ( interruptAtMessage ! = - 1 & &
! compareDatabases ( refFileBase . c_str ( ) , false ) ) {
equal = false ;
std : : cout < < " ====> comparison of client B against reference file(s) failed after interrupting at message # " < <
interruptAtMessage < < std : : endl ;
std : : cout . flush ( ) ;
}
if ( ! compareDatabases ( NULL , false ) ) {
equal = false ;
std : : cout < < " ====> comparison of client A and B failed after interrupting at message # " < <
interruptAtMessage < < std : : endl ;
std : : cout . flush ( ) ;
}
// save reference files from uninterrupted run?
if ( interruptAtMessage = = - 1 ) {
for ( source_it it = sources . begin ( ) ;
it ! = sources . end ( ) ;
+ + it ) {
std : : string refFile = refFileBase ;
refFile + = it - > second - > config . sourceName ;
refFile + = " .dat " ;
simplifyFilename ( refFile ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
TestingSyncSourcePtr source ;
2008-12-28 21:29:26 +01:00
SOURCE_ASSERT_NO_FAILURE ( source . get ( ) , source . reset ( it - > second - > createSourceA ( ) ) ) ;
SOURCE_ASSERT_EQUAL ( source . get ( ) , 0 , it - > second - > config . dump ( client , * source . get ( ) , refFile . c_str ( ) ) ) ;
CPPUNIT_ASSERT_NO_THROW ( source . reset ( ) ) ;
}
}
2008-12-22 19:52:00 +01:00
2010-02-26 10:49:35 +01:00
// pick next iteration
if ( requestedInterruptAt = = - 1 ) {
// user requested to stop after first iteration
break ;
} else if ( requestedInterruptAt > = 0 ) {
2008-12-27 16:10:03 +01:00
// only do one interrupted run of the test
if ( requestedInterruptAt = = interruptAtMessage ) {
break ;
} else {
interruptAtMessage = requestedInterruptAt ;
}
} else {
// interrupt one message later than before
interruptAtMessage + + ;
2010-03-16 17:22:46 +01:00
if ( interrupt & &
interruptAtMessage + 1 > = maxMsgNum ) {
// Don't interrupt before the server's last reply,
// because then the server thinks we completed the
// session when we think we didn't, which leads to a
// slow sync. Testing that is better done with a
// specific test.
break ;
}
if ( interruptAtMessage > = maxMsgNum ) {
// next run would not interrupt at all, stop now
2010-03-05 18:12:45 +01:00
break ;
}
2008-12-27 16:10:03 +01:00
}
2008-12-22 19:52:00 +01:00
}
2008-12-28 21:29:26 +01:00
CPPUNIT_ASSERT ( equal ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeClientAdd ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( CLIENT_ADD , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeClientRemove ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( CLIENT_REMOVE , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeClientUpdate ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( CLIENT_UPDATE , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeServerAdd ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( SERVER_ADD , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeServerRemove ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( SERVER_REMOVE , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
void SyncTests : : testInterruptResumeServerUpdate ( )
{
2009-06-26 08:01:02 +02:00
doInterruptResume ( SERVER_UPDATE , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
2010-02-26 17:19:12 +01:00
void SyncTests : : testInterruptResumeClientAddBig ( )
{
doInterruptResume ( CLIENT_ADD | BIG , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
}
void SyncTests : : testInterruptResumeClientUpdateBig ( )
{
doInterruptResume ( CLIENT_UPDATE | BIG , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
}
void SyncTests : : testInterruptResumeServerAddBig ( )
{
doInterruptResume ( SERVER_ADD | BIG , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
}
void SyncTests : : testInterruptResumeServerUpdateBig ( )
{
doInterruptResume ( SERVER_UPDATE | BIG , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
}
2008-12-22 19:52:00 +01:00
void SyncTests : : testInterruptResumeFull ( )
{
doInterruptResume ( CLIENT_ADD | CLIENT_REMOVE | CLIENT_UPDATE |
2009-06-26 08:01:02 +02:00
SERVER_ADD | SERVER_REMOVE | SERVER_UPDATE , boost : : shared_ptr < TransportWrapper > ( new TransportFaultInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendClientAdd ( )
{
doInterruptResume ( CLIENT_ADD , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendClientRemove ( )
{
doInterruptResume ( CLIENT_REMOVE , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendClientUpdate ( )
{
doInterruptResume ( CLIENT_UPDATE , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendServerAdd ( )
{
doInterruptResume ( SERVER_ADD , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendServerRemove ( )
{
doInterruptResume ( SERVER_REMOVE , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendServerUpdate ( )
{
doInterruptResume ( SERVER_UPDATE , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
2010-03-18 18:28:23 +01:00
void SyncTests : : testUserSuspendClientAddBig ( )
{
doInterruptResume ( CLIENT_ADD | BIG , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendClientUpdateBig ( )
{
doInterruptResume ( CLIENT_UPDATE | BIG , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendServerAddBig ( )
{
doInterruptResume ( SERVER_ADD | BIG , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
void SyncTests : : testUserSuspendServerUpdateBig ( )
{
doInterruptResume ( SERVER_UPDATE | BIG , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
}
2009-06-26 08:01:02 +02:00
void SyncTests : : testUserSuspendFull ( )
{
doInterruptResume ( CLIENT_ADD | CLIENT_REMOVE | CLIENT_UPDATE |
SERVER_ADD | SERVER_REMOVE | SERVER_UPDATE , boost : : shared_ptr < TransportWrapper > ( new UserSuspendInjector ( ) ) ) ;
2008-12-22 19:52:00 +01:00
}
2009-07-22 10:44:06 +02:00
void SyncTests : : testResendClientAdd ( )
{
doInterruptResume ( CLIENT_ADD , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendClientRemove ( )
{
doInterruptResume ( CLIENT_REMOVE , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendClientUpdate ( )
{
doInterruptResume ( CLIENT_UPDATE , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendServerAdd ( )
{
doInterruptResume ( SERVER_ADD , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendServerRemove ( )
{
doInterruptResume ( SERVER_REMOVE , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendServerUpdate ( )
{
doInterruptResume ( SERVER_UPDATE , boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
void SyncTests : : testResendFull ( )
{
doInterruptResume ( CLIENT_ADD | CLIENT_REMOVE | CLIENT_UPDATE |
SERVER_ADD | SERVER_REMOVE | SERVER_UPDATE ,
boost : : shared_ptr < TransportWrapper > ( new TransportResendInjector ( ) ) ) ;
}
2009-06-26 08:01:02 +02:00
2009-03-11 11:22:23 +01:00
void SyncTests : : doSync ( const SyncOptions & options )
{
2007-06-27 22:16:17 +02:00
int res = 0 ;
static int syncCounter = 0 ;
static std : : string lastTest ;
std : : stringstream logstream ;
// reset counter when switching tests
if ( lastTest ! = getCurrentTest ( ) ) {
syncCounter = 0 ;
lastTest = getCurrentTest ( ) ;
2006-12-09 18:50:06 +01:00
}
2006-12-01 23:49:15 +01:00
2009-03-19 18:29:08 +01:00
std : : string prefix ;
prefix . reserve ( 80 ) ;
2008-12-21 22:37:53 +01:00
for ( std : : list < std : : string > : : iterator it = logPrefixes . begin ( ) ;
it ! = logPrefixes . end ( ) ;
+ + it ) {
2009-03-19 18:29:08 +01:00
prefix + = " . " ;
prefix + = * it ;
2008-12-21 22:37:53 +01:00
}
2009-03-27 16:17:55 +01:00
if ( ! prefix . empty ( ) ) {
printf ( " %s " , prefix . c_str ( ) + 1 ) ;
fflush ( stdout ) ;
}
2009-03-19 18:29:08 +01:00
logstream /* << std::setw(4) << std::setfill('0') << syncCounter << "_" */ < < getCurrentTest ( )
< < prefix
< < " .client. " < < ( accessClientB ? " A " : " B " ) ;
2007-06-27 22:16:17 +02:00
std : : string logname = logstream . str ( ) ;
simplifyFilename ( logname ) ;
syncCounter + + ;
2009-02-19 16:00:26 +01:00
SE_LOG_DEBUG ( NULL , NULL , " %d. starting %s with sync mode %s " ,
2009-03-11 11:22:23 +01:00
syncCounter , logname . c_str ( ) , PrettyPrintSyncMode ( options . m_syncMode ) . c_str ( ) ) ;
2009-02-19 16:00:26 +01:00
2007-06-27 22:16:17 +02:00
try {
2009-03-11 11:22:23 +01:00
res = client . doSync ( sourceArray ,
logname ,
options ) ;
2007-06-27 22:16:17 +02:00
client . postSync ( res , logname ) ;
2009-03-11 11:18:30 +01:00
} catch ( CppUnit : : Exception & ex ) {
res = 1 ;
client . postSync ( res , logname ) ;
// report the original exception without altering the source line
throw ;
2007-06-27 22:16:17 +02:00
} catch ( . . . ) {
res = 1 ;
client . postSync ( res , logname ) ;
2009-03-11 11:22:23 +01:00
// this logs the original exception using CPPUnit mechanisms,
// with current line as source
CPPUNIT_ASSERT_NO_THROW ( throw ) ;
2006-12-01 23:49:15 +01:00
}
2007-06-27 22:16:17 +02:00
}
2006-12-01 23:49:15 +01:00
/** generates tests on demand based on what the client supports */
class ClientTestFactory : public CppUnit : : TestFactory {
public :
ClientTestFactory ( ClientTest & c ) :
client ( c ) { }
virtual CppUnit : : Test * makeTest ( ) {
int source ;
CppUnit : : TestSuite * alltests = new CppUnit : : TestSuite ( " Client " ) ;
CppUnit : : TestSuite * tests ;
2007-06-06 10:37:35 +02:00
2006-12-01 23:49:15 +01:00
// create local source tests
tests = new CppUnit : : TestSuite ( alltests - > getName ( ) + " ::Source " ) ;
2009-12-16 07:43:08 +01:00
for ( source = 0 ; source < client . getNumLocalSources ( ) ; source + + ) {
2006-12-01 23:49:15 +01:00
ClientTest : : Config config ;
2009-12-16 07:43:08 +01:00
client . getLocalSourceConfig ( source , config ) ;
2006-12-01 23:49:15 +01:00
if ( config . sourceName ) {
LocalTests * sourcetests =
2007-06-27 22:08:46 +02:00
client . createLocalTests ( tests - > getName ( ) + " :: " + config . sourceName , source , config ) ;
2006-12-01 23:49:15 +01:00
sourcetests - > addTests ( ) ;
2009-07-13 18:24:55 +02:00
tests - > addTest ( FilterTest ( sourcetests ) ) ;
2006-12-01 23:49:15 +01:00
}
}
2009-07-13 18:24:55 +02:00
alltests - > addTest ( FilterTest ( tests ) ) ;
2006-12-05 23:23:27 +01:00
tests = 0 ;
2006-12-01 23:49:15 +01:00
// create sync tests with just one source
tests = new CppUnit : : TestSuite ( alltests - > getName ( ) + " ::Sync " ) ;
2009-12-16 07:43:08 +01:00
for ( source = 0 ; source < client . getNumSyncSources ( ) ; source + + ) {
2006-12-01 23:49:15 +01:00
ClientTest : : Config config ;
2009-12-16 07:43:08 +01:00
client . getSyncSourceConfig ( source , config ) ;
2006-12-01 23:49:15 +01:00
if ( config . sourceName ) {
std : : vector < int > sources ;
sources . push_back ( source ) ;
SyncTests * synctests =
2007-06-27 22:08:46 +02:00
client . createSyncTests ( tests - > getName ( ) + " :: " + config . sourceName , sources ) ;
2006-12-01 23:49:15 +01:00
synctests - > addTests ( ) ;
2009-07-13 18:24:55 +02:00
tests - > addTest ( FilterTest ( synctests ) ) ;
2006-12-01 23:49:15 +01:00
}
}
2007-02-08 22:58:13 +01:00
// create sync tests with all sources enabled, unless we only have one:
// that would be identical to the test above
std : : vector < int > sources ;
std : : string name , name_reversed ;
2009-12-16 07:43:08 +01:00
for ( source = 0 ; source < client . getNumSyncSources ( ) ; source + + ) {
2007-02-08 22:58:13 +01:00
ClientTest : : Config config ;
2009-12-16 07:43:08 +01:00
client . getSyncSourceConfig ( source , config ) ;
2007-02-08 22:58:13 +01:00
if ( config . sourceName ) {
sources . push_back ( source ) ;
if ( name . size ( ) > 0 ) {
name + = " _ " ;
name_reversed = std : : string ( " _ " ) + name_reversed ;
}
name + = config . sourceName ;
name_reversed = config . sourceName + name_reversed ;
}
}
if ( sources . size ( ) > 1 ) {
SyncTests * synctests =
2007-06-27 22:08:46 +02:00
client . createSyncTests ( tests - > getName ( ) + " :: " + name , sources ) ;
2007-02-08 22:58:13 +01:00
synctests - > addTests ( ) ;
2009-07-13 18:24:55 +02:00
tests - > addTest ( FilterTest ( synctests ) ) ;
2007-02-08 22:58:13 +01:00
synctests = 0 ;
// now also in reversed order - who knows, it might make a difference
std : : reverse ( sources . begin ( ) , sources . end ( ) ) ;
synctests =
2007-06-27 22:08:46 +02:00
client . createSyncTests ( tests - > getName ( ) + " :: " + name_reversed , sources ) ;
2007-02-08 22:58:13 +01:00
synctests - > addTests ( ) ;
2009-07-13 18:24:55 +02:00
tests - > addTest ( FilterTest ( synctests ) ) ;
2007-02-08 22:58:13 +01:00
synctests = 0 ;
}
2007-06-06 10:37:35 +02:00
2009-07-13 18:24:55 +02:00
alltests - > addTest ( FilterTest ( tests ) ) ;
2007-04-16 22:14:18 +02:00
tests = 0 ;
2007-06-06 10:37:35 +02:00
2006-12-01 23:49:15 +01:00
return alltests ;
}
private :
ClientTest & client ;
} ;
void ClientTest : : registerTests ( )
{
factory = ( void * ) new ClientTestFactory ( * this ) ;
CppUnit : : TestFactoryRegistry : : getRegistry ( ) . registerFactory ( ( CppUnit : : TestFactory * ) factory ) ;
}
2006-12-09 18:50:06 +01:00
ClientTest : : ClientTest ( int serverSleepSec , const std : : string & serverLog ) :
serverSleepSeconds ( serverSleepSec ) ,
serverLogFileName ( serverLog ) ,
2006-12-01 23:49:15 +01:00
factory ( NULL )
{
}
ClientTest : : ~ ClientTest ( )
{
if ( factory ) {
CppUnit : : TestFactoryRegistry : : getRegistry ( ) . unregisterFactory ( ( CppUnit : : TestFactory * ) factory ) ;
delete ( CppUnit : : TestFactory * ) factory ;
2006-12-05 23:23:27 +01:00
factory = 0 ;
2006-12-01 23:49:15 +01:00
}
}
2006-12-05 23:23:27 +01:00
2010-09-01 18:01:19 +02:00
void ClientTest : : registerCleanup ( Cleanup_t cleanup )
{
cleanupSet . insert ( cleanup ) ;
}
void ClientTest : : shutdown ( )
{
BOOST_FOREACH ( Cleanup_t cleanup , cleanupSet ) {
cleanup ( ) ;
}
}
2007-06-27 22:08:46 +02:00
LocalTests * ClientTest : : createLocalTests ( const std : : string & name , int sourceParam , ClientTest : : Config & co )
{
return new LocalTests ( name , * this , sourceParam , co ) ;
}
SyncTests * ClientTest : : createSyncTests ( const std : : string & name , std : : vector < int > sourceIndices , bool isClientA )
{
return new SyncTests ( name , * this , sourceIndices , isClientA ) ;
}
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
int ClientTest : : dump ( ClientTest & client , TestingSyncSource & source , const char * file )
2006-12-05 23:23:27 +01:00
{
2009-07-01 14:10:59 +02:00
BackupReport report ;
2010-02-05 17:57:03 +01:00
boost : : shared_ptr < ConfigNode > node ( new VolatileConfigNode ) ;
2009-07-01 14:10:59 +02:00
rm_r ( file ) ;
mkdir_p ( file ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
CPPUNIT_ASSERT ( source . getOperations ( ) . m_backupData ) ;
2010-02-05 17:57:03 +01:00
source . getOperations ( ) . m_backupData ( SyncSource : : Operations : : ConstBackupInfo ( ) ,
SyncSourceRevisions: cache result of listAllItems() (MB #7708)
When automatic backups are enabled (the default), SyncSourceRevisions
and derived classes like TrackingSyncSource called listAllItems()
twice, once during backup and once while checking for changes.
This patch introduces caching of the result returned by the first
call. During a normal session, that will be during backup, with
change detection reusing the information. If backups are off, the
call will happen during change detection, as before.
Sharing of the listAllItems() result with change tracking only
works for the backup that is created at the start of a sync.
This piece of information is passed to the backend as part of
the BackupInfo structure.
The advantages of this change are:
- more efficient, in particular for sources where listAllItems() is slow
- avoids a race condition (backup stores one set of items, changes
are made, change detection works with another set)
That race condition is both fairly theoretical (short time window) and
had no impact on the correctness of the sync, only on the output (data
comparison would not show all changes synced later).
Now the race condition still exists if changes are made while a sync
runs, which is the bigger problem that still needs to be solved (for EDS,
see MB #3479).
Restoring data also calls listAllItems(). It does not use the cached
information, just in case that it is to be called more than once per
instance, and because there is no benefit.
2010-02-16 17:43:41 +01:00
SyncSource : : Operations : : BackupInfo ( SyncSource : : Operations : : BackupInfo : : BACKUP_OTHER , file , node ) ,
2010-02-05 17:57:03 +01:00
report ) ;
2009-07-01 14:10:59 +02:00
return 0 ;
2006-12-05 23:23:27 +01:00
}
2009-07-08 18:38:58 +02:00
void ClientTest : : getItems ( const char * file , list < string > & items , std : : string & testcases )
2006-12-05 23:23:27 +01:00
{
2009-03-11 11:22:23 +01:00
items . clear ( ) ;
2010-05-04 22:05:15 +02:00
// import the file, trying a .tem file (base file plus patch)
// first
2006-12-05 23:23:27 +01:00
std : : ifstream input ;
2009-07-06 03:28:32 +02:00
string server = getenv ( " CLIENT_TEST_SERVER " ) ;
2009-07-08 18:38:58 +02:00
testcases = string ( file ) + ' . ' + server + " .tem " ;
input . open ( testcases . c_str ( ) ) ;
2009-07-06 03:28:32 +02:00
2010-05-04 22:05:15 +02:00
if ( input . fail ( ) ) {
// try server-specific file (like ical20.ics.local)
testcases = string ( file ) + ' . ' + server ;
input . open ( testcases . c_str ( ) ) ;
}
if ( input . fail ( ) ) {
// try base file
2009-07-08 18:38:58 +02:00
testcases = file ;
input . open ( testcases . c_str ( ) ) ;
}
2006-12-05 23:23:27 +01:00
CPPUNIT_ASSERT ( ! input . bad ( ) ) ;
CPPUNIT_ASSERT ( input . is_open ( ) ) ;
std : : string data , line ;
while ( input ) {
2007-02-11 12:14:26 +01:00
bool wasend = false ;
2006-12-05 23:23:27 +01:00
do {
getline ( input , line ) ;
CPPUNIT_ASSERT ( ! input . bad ( ) ) ;
2007-02-11 12:14:26 +01:00
// empty lines directly after line which starts with END mark end of record;
// check for END necessary becayse vCard 2.1 ENCODING=BASE64 may have empty lines in body of VCARD!
2009-03-01 15:20:16 +01:00
if ( ( line ! = " \r " & & line . size ( ) > 0 ) | | ! wasend ) {
2006-12-05 23:23:27 +01:00
data + = line ;
data + = " \n " ;
} else {
2009-03-11 15:01:07 +01:00
if ( ! data . empty ( ) ) {
items . push_back ( data ) ;
}
2006-12-05 23:23:27 +01:00
data = " " ;
}
2007-02-11 12:14:26 +01:00
wasend = ! line . compare ( 0 , 4 , " END: " ) ;
2006-12-05 23:23:27 +01:00
} while ( ! input . eof ( ) ) ;
}
2009-03-11 15:01:07 +01:00
if ( ! data . empty ( ) ) {
items . push_back ( data ) ;
}
2009-03-11 11:22:23 +01:00
}
2006-12-05 23:23:27 +01:00
2010-10-14 11:40:45 +02:00
int ClientTest : : import ( ClientTest & client , TestingSyncSource & source , const ClientTestConfig & config ,
const char * file , std : : string & realfile )
2009-03-11 11:22:23 +01:00
{
list < string > items ;
2009-07-08 18:38:58 +02:00
getItems ( file , items , realfile ) ;
2009-03-11 11:22:23 +01:00
BOOST_FOREACH ( string & data , items ) {
2010-10-14 11:40:45 +02:00
importItem ( & source , config , data ) ;
2009-03-11 11:22:23 +01:00
}
2006-12-05 23:23:27 +01:00
return 0 ;
}
2006-12-09 18:50:06 +01:00
2006-12-17 17:36:17 +01:00
bool ClientTest : : compare ( ClientTest & client , const char * fileA , const char * fileB )
{
2009-03-11 16:30:23 +01:00
std : : string cmdstr = std : : string ( " env PATH=.:$PATH synccompare " ) + fileA + " " + fileB ;
setenv ( " CLIENT_TEST_HEADER " , " \n \n " , 1 ) ;
2008-12-28 21:26:58 +01:00
setenv ( " CLIENT_TEST_LEFT_NAME " , fileA , 1 ) ;
setenv ( " CLIENT_TEST_RIGHT_NAME " , fileB , 1 ) ;
setenv ( " CLIENT_TEST_REMOVED " , " only in left file " , 1 ) ;
setenv ( " CLIENT_TEST_ADDED " , " only in right file " , 1 ) ;
2009-07-24 09:18:19 +02:00
const char * compareLog = getenv ( " CLIENT_TEST_COMPARE_LOG " ) ;
if ( compareLog & & strlen ( compareLog ) )
{
string tmpfile = " ____compare.log " ;
cmdstr = string ( " bash -c 'set -o pipefail; " ) + cmdstr ;
cmdstr + = " 2>&1|tee " + tmpfile + " ' " ;
}
2009-03-11 16:30:23 +01:00
bool success = system ( cmdstr . c_str ( ) ) = = 0 ;
if ( ! success ) {
printf ( " failed: env CLIENT_TEST_SERVER=%s PATH=.:$PATH synccompare %s %s \n " ,
getenv ( " CLIENT_TEST_SERVER " ) ? getenv ( " CLIENT_TEST_SERVER " ) : " " ,
fileA , fileB ) ;
}
return success ;
2006-12-17 17:36:17 +01:00
}
2006-12-09 18:50:06 +01:00
void ClientTest : : postSync ( int res , const std : : string & logname )
{
2006-12-21 23:57:40 +01:00
# ifdef WIN32
2007-06-27 22:16:17 +02:00
Sleep ( serverSleepSeconds * 1000 ) ;
2006-12-21 23:57:40 +01:00
# else
2006-12-09 18:50:06 +01:00
sleep ( serverSleepSeconds ) ;
// make a copy of the server's log (if found), then truncate it
if ( serverLogFileName . size ( ) ) {
int fd = open ( serverLogFileName . c_str ( ) , O_RDWR ) ;
2007-06-06 10:37:35 +02:00
2006-12-09 18:50:06 +01:00
if ( fd > = 0 ) {
std : : string cmd = std : : string ( " cp " ) + serverLogFileName + " " + logname + " .server.log " ;
2009-03-01 15:20:16 +01:00
if ( system ( cmd . c_str ( ) ) ) {
fprintf ( stderr , " copying log file failed: %s \n " , cmd . c_str ( ) ) ;
}
if ( ftruncate ( fd , 0 ) ) {
perror ( " truncating log file " ) ;
}
2006-12-09 18:50:06 +01:00
} else {
perror ( serverLogFileName . c_str ( ) ) ;
}
}
# endif
}
2006-12-17 17:36:17 +01:00
2010-10-14 11:40:45 +02:00
static string mangleNOP ( const char * data ) { return data ; }
static string mangleICalendar20 ( const char * data )
{
std : : string item = data ;
if ( getenv ( " CLIENT_TEST_NO_UID " ) ) {
boost : : replace_all ( item , " UID:1234567890!@#$%^&*()<>@dummy \n " , " " ) ;
} else if ( getenv ( " CLIENT_TEST_SIMPLE_UID " ) ) {
boost : : replace_all ( item , " UID:1234567890!@#$%^&*()<>@dummy " , " UID:1234567890@dummy " ) ;
}
if ( getenv ( " CLIENT_TEST_UNIQUE_UID " ) ) {
// Making UID unique per client-test run avoids issues
// when the source already holds older copies.
// Might still be an issue in real life?!
static time_t start = time ( NULL ) ;
std : : string unique = StringPrintf ( " UID:%llu- " , ( long long unsigned ) start ) ;
boost : : replace_all ( item , " UID: " , unique ) ;
}
size_t offset = item . find ( " \n LAST-MODIFIED: " ) ;
static const size_t len = strlen ( " \n LAST-MODIFIED:20100131T235959Z " ) ;
if ( offset ! = item . npos ) {
// Special semantic for iCalendar 2.0: LAST-MODIFIED should be
// incremented in updated items. Emulate that by inserting the
// current time.
time_t now = time ( NULL ) ;
struct tm tm ;
gmtime_r ( & now , & tm ) ;
std : : string mod = StringPrintf ( " \n LAST-MODIFIED:%04d%02d%02dT%02d%02d%02dZ " ,
tm . tm_year + 1900 , tm . tm_mon + 1 , tm . tm_mday ,
tm . tm_hour , tm . tm_min , tm . tm_sec ) ;
item . replace ( offset , len , mod ) ;
}
const static string sequence ( " \n SEQUENCE:XXX " ) ;
offset = item . find ( sequence ) ;
if ( offset ! = item . npos ) {
2010-11-04 08:57:39 +01:00
if ( getenv ( " CLIENT_TEST_INCREASE_SEQUENCE " ) ) {
// Increment sequence number in steps of 100 to ensure that our
// new item is considered more recent than any corresponding
// item in the source. Some storages (Google CalDAV) check that.
static int counter = 100 ;
item . replace ( offset , sequence . size ( ) , StringPrintf ( " \n SEQUENCE:%d " , counter ) ) ;
counter + = 100 ;
} else {
item . replace ( offset , sequence . size ( ) , " \n SEQUENCE:1 " ) ;
}
2010-10-14 11:40:45 +02:00
}
return item ;
}
2006-12-17 17:36:17 +01:00
void ClientTest : : getTestData ( const char * type , Config & config )
{
memset ( & config , 0 , sizeof ( config ) ) ;
2007-11-05 20:14:09 +01:00
char * numitems = getenv ( " CLIENT_TEST_NUM_ITEMS " ) ;
config . numItems = numitems ? atoi ( numitems ) : 100 ;
2009-08-31 03:54:36 +02:00
char * env = getenv ( " CLIENT_TEST_RETRY " ) ;
config . retrySync = ( env & & ! strcmp ( env , " t " ) ) ? true : false ;
env = getenv ( " CLIENT_TEST_RESEND " ) ;
config . resendSync = ( env & & ! strcmp ( env , " t " ) ) ? true : false ;
env = getenv ( " CLIENT_TEST_SUSPEND " ) ;
config . suspendSync = ( env & & ! strcmp ( env , " t " ) ) ? true : false ;
2009-02-18 12:39:51 +01:00
config . sourceKnowsItemSemantic = true ;
2010-10-26 11:09:17 +02:00
config . linkedItemsRelaxedSemantic = true ;
2009-04-01 16:46:55 +02:00
config . itemType = " " ;
2009-06-26 15:56:04 +02:00
config . import = import ;
config . dump = dump ;
config . compare = compare ;
2006-12-17 17:36:17 +01:00
2009-12-18 10:47:29 +01:00
// redirect requests for "ical20" towards "ical20_noutc"?
bool noutc = false ;
2009-12-11 10:50:00 +01:00
env = getenv ( " CLIENT_TEST_NOUTC " ) ;
if ( env & & ! strcmp ( env , " t " ) ) {
2009-12-18 10:47:29 +01:00
noutc = true ;
2009-12-11 10:50:00 +01:00
}
2009-12-18 10:47:29 +01:00
2010-10-14 11:40:45 +02:00
config . mangleItem = mangleNOP ;
2006-12-17 17:36:17 +01:00
if ( ! strcmp ( type , " vcard30 " ) ) {
config . sourceName = " vcard30 " ;
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " addressbook " ;
2007-02-11 12:14:26 +01:00
config . uri = " card3 " ; // ScheduleWorld
2006-12-17 17:36:17 +01:00
config . type = " text/vcard " ;
config . insertItem =
" BEGIN:VCARD \n "
" VERSION:3.0 \n "
" TITLE:tester \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" X-EVOLUTION-FILE-AS:Doe \\ , John \n "
" X-MOZILLA-HTML:FALSE \n "
2008-12-28 19:11:38 +01:00
" NOTE:<<REVISION>> \n "
2006-12-17 17:36:17 +01:00
" END:VCARD \n " ;
config . updateItem =
" BEGIN:VCARD \n "
" VERSION:3.0 \n "
" TITLE:tester \n "
" FN:Joan Doe \n "
" N:Doe;Joan;;; \n "
" X-EVOLUTION-FILE-AS:Doe \\ , Joan \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 2 \n "
" BDAY:2006-01-08 \n "
" X-MOZILLA-HTML:TRUE \n "
" END:VCARD \n " ;
/* adds a second phone number: */
config . complexUpdateItem =
" BEGIN:VCARD \n "
" VERSION:3.0 \n "
" TITLE:tester \n "
" FN:Joan Doe \n "
" N:Doe;Joan;;; \n "
" X-EVOLUTION-FILE-AS:Doe \\ , Joan \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" TEL;TYPE=HOME;TYPE=VOICE:home 2 \n "
" BDAY:2006-01-08 \n "
" X-MOZILLA-HTML:TRUE \n "
" END:VCARD \n " ;
/* add a telephone number, email and X-AIM to initial item */
config . mergeItem1 =
" BEGIN:VCARD \n "
" VERSION:3.0 \n "
" TITLE:tester \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
" X-EVOLUTION-FILE-AS:Doe \\ , John \n "
" X-MOZILLA-HTML:FALSE \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" EMAIL:john.doe@work.com \n "
" X-AIM:AIM JOHN \n "
" END:VCARD \n " ;
config . mergeItem2 =
" BEGIN:VCARD \n "
" VERSION:3.0 \n "
" TITLE:developer \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
2009-08-11 03:38:01 +02:00
" TEL;TYPE=WORK;TYPE=VOICE:123456 \n "
2006-12-17 17:36:17 +01:00
" X-EVOLUTION-FILE-AS:Doe \\ , John \n "
" X-MOZILLA-HTML:TRUE \n "
" BDAY:2006-01-08 \n "
" END:VCARD \n " ;
config . templateItem = config . insertItem ;
config . uniqueProperties = " FN:N:X-EVOLUTION-FILE-AS " ;
config . sizeProperty = " NOTE " ;
2009-05-14 19:51:58 +02:00
config . testcases = " testcases/vcard30.vcf " ;
2007-02-11 12:14:26 +01:00
} else if ( ! strcmp ( type , " vcard21 " ) ) {
config . sourceName = " vcard21 " ;
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " addressbook " ;
2007-02-11 12:14:26 +01:00
config . uri = " card " ; // Funambol
config . type = " text/x-vcard " ;
config . insertItem =
" BEGIN:VCARD \n "
" VERSION:2.1 \n "
" TITLE:tester \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" X-MOZILLA-HTML:FALSE \n "
2008-12-28 19:11:38 +01:00
" NOTE:<<REVISION>> \n "
2007-02-11 12:14:26 +01:00
" END:VCARD \n " ;
config . updateItem =
" BEGIN:VCARD \n "
" VERSION:2.1 \n "
" TITLE:tester \n "
" FN:Joan Doe \n "
" N:Doe;Joan;;; \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 2 \n "
" BDAY:2006-01-08 \n "
" X-MOZILLA-HTML:TRUE \n "
" END:VCARD \n " ;
/* adds a second phone number: */
config . complexUpdateItem =
" BEGIN:VCARD \n "
" VERSION:2.1 \n "
" TITLE:tester \n "
" FN:Joan Doe \n "
" N:Doe;Joan;;; \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" TEL;TYPE=HOME;TYPE=VOICE:home 2 \n "
" BDAY:2006-01-08 \n "
" X-MOZILLA-HTML:TRUE \n "
" END:VCARD \n " ;
2009-06-12 12:22:21 +02:00
/* add email and X-AIM to initial item */
2007-02-11 12:14:26 +01:00
config . mergeItem1 =
" BEGIN:VCARD \n "
" VERSION:2.1 \n "
" TITLE:tester \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
" X-MOZILLA-HTML:FALSE \n "
" TEL;TYPE=WORK;TYPE=VOICE:business 1 \n "
" EMAIL:john.doe@work.com \n "
" X-AIM:AIM JOHN \n "
" END:VCARD \n " ;
2009-06-12 12:22:21 +02:00
/* change X-MOZILLA-HTML */
2007-02-11 12:14:26 +01:00
config . mergeItem2 =
" BEGIN:VCARD \n "
" VERSION:2.1 \n "
" TITLE:developer \n "
" FN:John Doe \n "
" N:Doe;John;;; \n "
" X-MOZILLA-HTML:TRUE \n "
" BDAY:2006-01-08 \n "
" END:VCARD \n " ;
config . templateItem = config . insertItem ;
config . uniqueProperties = " FN:N " ;
config . sizeProperty = " NOTE " ;
2009-05-14 19:51:58 +02:00
config . testcases = " testcases/vcard21.vcf " ;
2009-12-18 10:47:29 +01:00
} else if ( ! strcmp ( type , " ical20 " ) & & ! noutc ) {
2006-12-17 17:36:17 +01:00
config . sourceName = " ical20 " ;
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " calendar " ;
2007-02-11 12:14:26 +01:00
config . uri = " cal2 " ; // ScheduleWorld
2006-12-17 17:36:17 +01:00
config . type = " text/x-vcalendar " ;
2010-10-14 11:40:45 +02:00
config . mangleItem = mangleICalendar20 ;
config . insertItem =
2006-12-17 17:36:17 +01:00
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
2007-02-11 12:14:26 +01:00
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2006-12-17 17:36:17 +01:00
" UID:1234567890!@#$%^&*()<>@dummy \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2006-12-17 17:36:17 +01:00
" CREATED:20060409T213201 \n "
" LOCATION:my office \n "
2008-12-28 19:11:38 +01:00
" DESCRIPTION:let's talk<<REVISION>> \n "
2006-12-17 17:36:17 +01:00
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2006-12-17 17:36:17 +01:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
2010-10-14 11:40:45 +02:00
config . updateItem =
2006-12-17 17:36:17 +01:00
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" SUMMARY:meeting on site \n "
2007-02-11 12:14:26 +01:00
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2006-12-17 17:36:17 +01:00
" UID:1234567890!@#$%^&*()<>@dummy \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2006-12-17 17:36:17 +01:00
" CREATED:20060409T213201 \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2006-12-17 17:36:17 +01:00
" LOCATION:big meeting room \n "
" DESCRIPTION:nice to see you \n "
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
2009-06-12 12:22:21 +02:00
/* change location and description of insertItem in testMerge(), add alarm */
2010-10-14 11:40:45 +02:00
config . mergeItem1 =
2006-12-17 17:36:17 +01:00
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
2007-02-11 12:14:26 +01:00
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2006-12-17 17:36:17 +01:00
" UID:1234567890!@#$%^&*()<>@dummy \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2006-12-17 17:36:17 +01:00
" CREATED:20060409T213201 \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2006-12-17 17:36:17 +01:00
" LOCATION:calling from home \n "
" DESCRIPTION:let's talk \n "
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
2009-06-12 12:22:21 +02:00
" BEGIN:VALARM \n "
" DESCRIPTION:alarm \n "
" ACTION:DISPLAY \n "
" TRIGGER;VALUE=DURATION;RELATED=START:-PT15M \n "
" END:VALARM \n "
2006-12-17 17:36:17 +01:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
2009-06-12 12:22:21 +02:00
/* change location to something else, add category */
2010-10-14 11:40:45 +02:00
config . mergeItem2 =
2006-12-17 17:36:17 +01:00
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
2007-02-11 12:14:26 +01:00
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2006-12-17 17:36:17 +01:00
" UID:1234567890!@#$%^&*()<>@dummy \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2006-12-17 17:36:17 +01:00
" CREATED:20060409T213201 \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2006-12-17 17:36:17 +01:00
" LOCATION:my office \n "
2009-06-12 12:22:21 +02:00
" CATEGORIES:WORK \n "
2006-12-17 17:36:17 +01:00
" DESCRIPTION:what the heck \\ , let's even shout a bit \n "
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
2010-04-09 16:05:35 +02:00
2008-04-16 19:23:06 +02:00
config . parentItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" UID:20080407T193125Z-19554-727-1-50@gollum \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20080407T193125Z \n "
2008-04-16 19:23:06 +02:00
" DTSTART:20080406T090000Z \n "
" DTEND:20080406T093000Z \n "
" TRANSP:OPAQUE \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2008-04-16 19:23:06 +02:00
" SUMMARY:Recurring \n "
" DESCRIPTION:recurs each Monday \\ , 10 times \n "
" CLASS:PUBLIC \n "
" RRULE:FREQ=WEEKLY;COUNT=10;INTERVAL=1;BYDAY=SU \n "
" CREATED:20080407T193241 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20080407T193241Z \n "
2008-04-16 19:23:06 +02:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
config . childItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VEVENT \n "
" UID:20080407T193125Z-19554-727-1-50@gollum \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20080407T193125Z \n "
2008-04-16 19:23:06 +02:00
" DTSTART:20080413T090000Z \n "
" DTEND:20080413T093000Z \n "
" TRANSP:OPAQUE \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2008-04-16 19:23:06 +02:00
" SUMMARY:Recurring: Modified \n "
" CLASS:PUBLIC \n "
" CREATED:20080407T193241 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20080407T193647Z \n "
2008-04-16 19:23:06 +02:00
" RECURRENCE-ID:20080413T090000Z \n "
" DESCRIPTION:second instance modified \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
2010-10-14 11:40:45 +02:00
2006-12-17 17:36:17 +01:00
config . templateItem = config . insertItem ;
2007-02-14 22:01:27 +01:00
config . uniqueProperties = " SUMMARY:UID:LOCATION " ;
2006-12-17 17:36:17 +01:00
config . sizeProperty = " DESCRIPTION " ;
2009-05-14 19:51:58 +02:00
config . testcases = " testcases/ical20.ics " ;
2007-02-11 12:14:26 +01:00
} if ( ! strcmp ( type , " vcal10 " ) ) {
config . sourceName = " vcal10 " ;
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " calendar " ;
2007-02-11 12:14:26 +01:00
config . uri = " cal " ; // Funambol 3.0
config . type = " text/x-vcalendar " ;
config . insertItem =
" BEGIN:VCALENDAR \n "
" VERSION:1.0 \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2007-02-11 12:14:26 +01:00
" LOCATION:my office \n "
2008-12-28 19:11:38 +01:00
" DESCRIPTION:let's talk<<REVISION>> \n "
2007-02-11 12:14:26 +01:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
config . updateItem =
" BEGIN:VCALENDAR \n "
" VERSION:1.0 \n "
" BEGIN:VEVENT \n "
" SUMMARY:meeting on site \n "
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
2010-10-07 17:52:07 +02:00
" DTSTAMP:20060406T211449Z \n "
2007-02-11 12:14:26 +01:00
" LOCATION:big meeting room \n "
" DESCRIPTION:nice to see you \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
/* change location in insertItem in testMerge() */
config . mergeItem1 =
" BEGIN:VCALENDAR \n "
" VERSION:1.0 \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
" DTSTAMP:20060406T211449Z \n "
" LOCATION:calling from home \n "
" DESCRIPTION:let's talk \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
config . mergeItem2 =
" BEGIN:VCALENDAR \n "
" VERSION:1.0 \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
" DTEND:20060406T163000Z \n "
" DTSTART:20060406T160000Z \n "
" DTSTAMP:20060406T211449Z \n "
" LOCATION:my office \n "
" DESCRIPTION:what the heck, let's even shout a bit \n "
" END:VEVENT \n "
" END:VCALENDAR \n " ;
config . templateItem = config . insertItem ;
2007-02-14 22:01:27 +01:00
config . uniqueProperties = " SUMMARY:UID:LOCATION " ;
2007-02-11 12:14:26 +01:00
config . sizeProperty = " DESCRIPTION " ;
2009-05-14 19:51:58 +02:00
config . testcases = " testcases/vcal10.ics " ;
2009-12-18 10:47:29 +01:00
} else if ( ! strcmp ( type , " ical20_noutc " ) | |
( ! strcmp ( type , " ical20 " ) & & noutc ) ) {
2009-12-11 10:50:00 +01:00
config . sourceName = " ical20 " ;
config . sourceNameServerTemplate = " calendar " ;
config . uri = " cal2 " ; // ScheduleWorld
config . type = " text/x-vcalendar " ;
2010-10-14 11:40:45 +02:00
config . mangleItem = mangleICalendar20 ;
2009-12-11 10:50:00 +01:00
config . insertItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTIMEZONE \n "
" TZID:Asia/Shanghai \n "
" BEGIN:STANDARD \n "
" DTSTART:19670101T000000 \n "
" TZOFFSETFROM:+0800 \n "
" TZOFFSETTO:+0800 \n "
" END:STANDARD \n "
" END:VTIMEZONE \n "
" BEGIN:VTIMEZONE \n "
" TZID:/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai \n "
" X-LIC-LOCATION:Asia/Shanghai \n "
" BEGIN:STANDARD \n "
" TZNAME:CST \n "
" DTSTART:19700914T230000 \n "
" TZOFFSETFROM:+0800 \n "
" TZOFFSETTO:+0800 \n "
" END:STANDARD \n "
" END:VTIMEZONE \n "
" BEGIN:VEVENT \n "
" SUMMARY:phone meeting \n "
" DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai:20060406T163000 \n "
" DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai:20060406T160000 \n "
" UID:1234567890!@#$%^&*()<>@dummy \n "
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2009-12-11 10:50:00 +01:00
" CREATED:20060409T213201 \n "
" LOCATION:my office \n "
" DESCRIPTION:let's talk<<REVISION>> \n "
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2009-12-11 10:50:00 +01:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
config . updateItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTIMEZONE \n "
" TZID:Asia/Shanghai \n "
" BEGIN:STANDARD \n "
" DTSTART:19670101T000000 \n "
" TZOFFSETFROM:+0800 \n "
" TZOFFSETTO:+0800 \n "
" END:STANDARD \n "
" END:VTIMEZONE \n "
" BEGIN:VTIMEZONE \n "
" TZID:/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai \n "
" X-LIC-LOCATION:Asia/Shanghai \n "
" BEGIN:STANDARD \n "
" TZNAME:CST \n "
" DTSTART:19700914T230000 \n "
" TZOFFSETFROM:+0800 \n "
" TZOFFSETTO:+0800 \n "
" END:STANDARD \n "
" END:VTIMEZONE \n "
" BEGIN:VEVENT \n "
" SUMMARY:meeting on site \n "
" DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai:20060406T163000 \n "
" DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/Asia/Shanghai:20060406T160000 \n "
" UID:1234567890!@#$%^&*()<>@dummy \n "
" DTSTAMP:20060406T211449Z \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060409T213201Z \n "
2009-12-11 10:50:00 +01:00
" CREATED:20060409T213201 \n "
" LOCATION:big meeting room \n "
" DESCRIPTION:nice to see you \n "
" CLASS:PUBLIC \n "
" TRANSP:OPAQUE \n "
2010-10-14 11:40:45 +02:00
" SEQUENCE:XXX \n "
2009-12-11 10:50:00 +01:00
" END:VEVENT \n "
" END:VCALENDAR \n " ;
/* change location and description of insertItem in testMerge(), add alarm */
config . mergeItem1 = " " ;
config . mergeItem2 = " " ;
config . parentItem = " " ;
config . childItem = " " ;
config . templateItem = config . insertItem ;
config . uniqueProperties = " SUMMARY:UID:LOCATION " ;
config . sizeProperty = " DESCRIPTION " ;
config . testcases = " testcases/ical20.ics " ;
2006-12-17 17:36:17 +01:00
} else if ( ! strcmp ( type , " itodo20 " ) ) {
config . sourceName = " itodo20 " ;
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " todo " ;
2007-02-11 12:14:26 +01:00
config . uri = " task2 " ; // ScheduleWorld
2006-12-17 17:36:17 +01:00
config . type = " text/x-vcalendar " ;
2010-10-14 11:40:45 +02:00
config . mangleItem = mangleICalendar20 ;
2006-12-17 17:36:17 +01:00
config . insertItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTODO \n "
" UID:20060417T173712Z-4360-727-1-2730@gollum \n "
" DTSTAMP:20060417T173712Z \n "
" SUMMARY:do me \n "
2008-12-28 19:11:38 +01:00
" DESCRIPTION:to be done<<REVISION>> \n "
2006-12-17 17:36:17 +01:00
" PRIORITY:0 \n "
" STATUS:IN-PROCESS \n "
" CREATED:20060417T173712 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060417T173712Z \n "
2006-12-17 17:36:17 +01:00
" END:VTODO \n "
" END:VCALENDAR \n " ;
config . updateItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTODO \n "
" UID:20060417T173712Z-4360-727-1-2730@gollum \n "
" DTSTAMP:20060417T173712Z \n "
" SUMMARY:do me ASAP \n "
" DESCRIPTION:to be done \n "
" PRIORITY:1 \n "
" STATUS:IN-PROCESS \n "
" CREATED:20060417T173712 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060417T173712Z \n "
2006-12-17 17:36:17 +01:00
" END:VTODO \n "
" END:VCALENDAR \n " ;
/* change summary in insertItem in testMerge() */
config . mergeItem1 =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTODO \n "
" UID:20060417T173712Z-4360-727-1-2730@gollum \n "
" DTSTAMP:20060417T173712Z \n "
" SUMMARY:do me please \\ , please \n "
" DESCRIPTION:to be done \n "
" PRIORITY:0 \n "
" STATUS:IN-PROCESS \n "
" CREATED:20060417T173712 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060417T173712Z \n "
2006-12-17 17:36:17 +01:00
" END:VTODO \n "
" END:VCALENDAR \n " ;
config . mergeItem2 =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VTODO \n "
" UID:20060417T173712Z-4360-727-1-2730@gollum \n "
" DTSTAMP:20060417T173712Z \n "
" SUMMARY:do me \n "
" DESCRIPTION:to be done \n "
" PRIORITY:7 \n "
" STATUS:IN-PROCESS \n "
" CREATED:20060417T173712 \n "
2010-10-14 11:40:45 +02:00
" LAST-MODIFIED:20060417T173712Z \n "
2006-12-17 17:36:17 +01:00
" END:VTODO \n "
" END:VCALENDAR \n " ;
config . templateItem = config . insertItem ;
config . uniqueProperties = " SUMMARY:UID " ;
config . sizeProperty = " DESCRIPTION " ;
2009-05-14 19:51:58 +02:00
config . testcases = " testcases/itodo20.ics " ;
2009-06-26 15:56:04 +02:00
} else if ( ! strcmp ( type , " text " ) ) {
// The "text" test uses iCalendar 2.0 VJOURNAL
// as format because synccompare doesn't handle
// plain text. A backend which wants to use this
// test data must support importing/exporting
// the test data in that format, see EvolutionMemoSource
// for an example.
config . uri = " note " ; // ScheduleWorld
2009-08-04 10:40:26 +02:00
config . sourceNameServerTemplate = " memo " ;
2009-06-26 15:56:04 +02:00
config . type = " memo " ;
config . itemType = " text/calendar " ;
2010-10-14 11:40:45 +02:00
config . mangleItem = mangleICalendar20 ;
2009-06-26 15:56:04 +02:00
config . insertItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VJOURNAL \n "
" SUMMARY:Summary \n "
2009-09-10 07:11:12 +02:00
" DESCRIPTION:Summary \\ nBody text REVISION \n "
2009-06-26 15:56:04 +02:00
" END:VJOURNAL \n "
" END:VCALENDAR \n " ;
config . updateItem =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VJOURNAL \n "
" SUMMARY:Summary Modified \n "
" DESCRIPTION:Summary Modified \\ nBody text \n "
" END:VJOURNAL \n "
" END:VCALENDAR \n " ;
/* change summary, as in updateItem, and the body in the other merge item */
config . mergeItem1 = config . updateItem ;
config . mergeItem2 =
" BEGIN:VCALENDAR \n "
" PRODID:-//Ximian//NONSGML Evolution Calendar//EN \n "
" VERSION:2.0 \n "
" METHOD:PUBLISH \n "
" BEGIN:VJOURNAL \n "
" SUMMARY:Summary \n "
" DESCRIPTION:Summary \\ nBody modified \n "
" END:VJOURNAL \n "
" END:VCALENDAR \n " ;
config . templateItem = config . insertItem ;
config . uniqueProperties = " SUMMARY:DESCRIPTION " ;
config . sizeProperty = " DESCRIPTION " ;
config . testcases = " testcases/imemo20.ics " ;
2010-02-21 10:35:12 +01:00
} else if ( ! strcmp ( type , " calendar+todo " ) ) {
2009-12-22 02:51:42 +01:00
config . uri = " " ;
2010-02-21 10:35:12 +01:00
config . sourceNameServerTemplate = " calendar+todo " ;
2006-12-17 17:36:17 +01:00
}
}
2007-02-14 22:01:27 +01:00
2009-02-19 14:53:55 +01:00
void CheckSyncReport : : check ( SyncMLStatus status , SyncReport & report ) const
2007-06-06 10:37:35 +02:00
{
2010-03-18 18:32:49 +01:00
if ( m_report ) {
* m_report = report ;
}
2009-02-19 14:53:55 +01:00
stringstream str ;
2007-02-14 22:01:27 +01:00
2009-02-19 14:53:55 +01:00
str < < report ;
str < < " ----------|--------CLIENT---------|--------SERVER---------| \n " ;
str < < " | NEW | MOD | DEL | NEW | MOD | DEL | \n " ;
str < < " ----------|-----------------------------------------------| \n " ;
str < < StringPrintf ( " Expected | %3d | %3d | %3d | %3d | %3d | %3d | \n " ,
clientAdded , clientUpdated , clientDeleted ,
serverAdded , serverUpdated , serverDeleted ) ;
2009-02-19 16:00:26 +01:00
str < < " Expected sync mode: " < < PrettyPrintSyncMode ( syncMode ) < < " \n " ;
SE_LOG_INFO ( NULL , NULL , " sync report: \n %s \n " , str . str ( ) . c_str ( ) ) ;
2009-03-11 15:01:07 +01:00
if ( mustSucceed ) {
2010-02-26 15:12:40 +01:00
// both STATUS_OK and STATUS_HTTP_OK map to the same
// string, so check the formatted status first, then
// the numerical one
CPPUNIT_ASSERT_EQUAL ( string ( " no error (remote, status 0) " ) , Status2String ( status ) ) ;
2009-03-11 15:01:07 +01:00
CPPUNIT_ASSERT_EQUAL ( STATUS_OK , status ) ;
}
2007-03-31 18:00:05 +02:00
2007-02-14 22:01:27 +01:00
// this code is intentionally duplicated to produce nicer CPPUNIT asserts
2009-02-19 14:53:55 +01:00
BOOST_FOREACH ( SyncReport : : value_type & entry , report ) {
const std : : string & name = entry . first ;
const SyncSourceReport & source = entry . second ;
SE_LOG_DEBUG ( NULL , NULL , " Checking sync source %s... " , name . c_str ( ) ) ;
2009-03-11 15:01:07 +01:00
if ( mustSucceed ) {
CLIENT_TEST_EQUAL ( name , STATUS_OK , source . getStatus ( ) ) ;
}
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , 0 , source . getItemStat ( SyncSourceReport : : ITEM_LOCAL ,
SyncSourceReport : : ITEM_ANY ,
SyncSourceReport : : ITEM_REJECT ) ) ;
CLIENT_TEST_EQUAL ( name , 0 , source . getItemStat ( SyncSourceReport : : ITEM_REMOTE ,
SyncSourceReport : : ITEM_ANY ,
SyncSourceReport : : ITEM_REJECT ) ) ;
2009-08-11 03:36:15 +02:00
const char * checkSyncModeStr = getenv ( " CLIENT_TEST_NOCHECK_SYNCMODE " ) ;
bool checkSyncMode = true ;
2009-12-11 06:44:48 +01:00
bool checkSyncStats = getenv ( " CLIENT_TEST_NOCHECK_SYNCSTATS " ) ? false : true ;
2009-08-11 03:36:15 +02:00
if ( checkSyncModeStr & &
( ! strcmp ( checkSyncModeStr , " 1 " ) | | ! strcasecmp ( checkSyncModeStr , " t " ) ) ) {
checkSyncMode = false ;
}
2009-02-19 16:00:26 +01:00
2009-08-11 03:36:15 +02:00
if ( syncMode ! = SYNC_NONE & & checkSyncMode ) {
2009-02-19 16:00:26 +01:00
CLIENT_TEST_EQUAL ( name , syncMode , source . getFinalSyncMode ( ) ) ;
}
2007-02-14 22:01:27 +01:00
2009-12-11 06:44:48 +01:00
if ( clientAdded ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , clientAdded ,
source . getItemStat ( SyncSourceReport : : ITEM_LOCAL ,
SyncSourceReport : : ITEM_ADDED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
2009-12-11 06:44:48 +01:00
if ( clientUpdated ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , clientUpdated ,
source . getItemStat ( SyncSourceReport : : ITEM_LOCAL ,
SyncSourceReport : : ITEM_UPDATED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
2009-12-11 06:44:48 +01:00
if ( clientDeleted ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , clientDeleted ,
source . getItemStat ( SyncSourceReport : : ITEM_LOCAL ,
SyncSourceReport : : ITEM_REMOVED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
2009-12-11 06:44:48 +01:00
if ( serverAdded ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , serverAdded ,
source . getItemStat ( SyncSourceReport : : ITEM_REMOTE ,
SyncSourceReport : : ITEM_ADDED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
2009-12-11 06:44:48 +01:00
if ( serverUpdated ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , serverUpdated ,
source . getItemStat ( SyncSourceReport : : ITEM_REMOTE ,
SyncSourceReport : : ITEM_UPDATED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
2009-12-11 06:44:48 +01:00
if ( serverDeleted ! = - 1 & & checkSyncStats ) {
2009-02-19 14:53:55 +01:00
CLIENT_TEST_EQUAL ( name , serverDeleted ,
source . getItemStat ( SyncSourceReport : : ITEM_REMOTE ,
SyncSourceReport : : ITEM_REMOVED ,
SyncSourceReport : : ITEM_TOTAL ) ) ;
2007-02-14 22:01:27 +01:00
}
}
2009-02-19 14:53:55 +01:00
SE_LOG_DEBUG ( NULL , NULL , " Done with checking sync report. " ) ;
2007-02-14 22:01:27 +01:00
}
2007-03-04 12:21:15 +01:00
2007-03-19 20:41:01 +01:00
/** @} */
/** @endcond */
2007-03-04 12:21:15 +01:00
# endif // ENABLE_INTEGRATION_TESTS
2009-10-02 17:23:53 +02:00
SE_END_CXX