syncevolution/test/ClientTest.h

1042 lines
39 KiB
C
Raw Permalink Normal View History

/*
* Copyright (C) 2008 Funambol, Inc.
* Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
* Copyright (C) 2009 Intel Corporation
*
* 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.
*
* 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.
*
* 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
*/
#ifndef INCL_TESTSYNCCLIENT
#define INCL_TESTSYNCCLIENT
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <vector>
#include <SyncML.h>
#include <TransportAgent.h>
#include <SyncSource.h>
#include <syncevo/SuspendFlags.h>
#include "test.h"
#include "ClientTestAssert.h"
#ifdef ENABLE_INTEGRATION_TESTS
#include <cppunit/TestSuite.h>
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <syncevo/Logging.h>
#include <syncevo/util.h>
#include <boost/utility.hpp>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
class SyncContext;
class EvolutionSyncSource;
class TransportWrapper;
class TestingSyncSource;
/**
* This class encapsulates logging and checking of a SyncReport.
* When constructed with default parameters, no checking will be done.
* Otherwise the sync report has to contain exactly the expected result.
* When multiple sync sources are active, @b all of them have to behave
* alike (which is how the tests are constructed).
*
* No item is ever supposed to fail.
*/
class CheckSyncReport {
public:
CheckSyncReport(int clAdded = -1, int clUpdated = -1, int clDeleted = -1,
int srAdded = -1, int srUpdated = -1, int srDeleted = -1,
bool mstSucceed = true, SyncMode mode = SYNC_NONE) :
clientAdded(clAdded),
clientUpdated(clUpdated),
clientDeleted(clDeleted),
serverAdded(srAdded),
serverUpdated(srUpdated),
serverDeleted(srDeleted),
restarts(0),
mustSucceed(mstSucceed),
syncMode(mode),
m_report(nullptr)
{}
int clientAdded, clientUpdated, clientDeleted,
serverAdded, serverUpdated, serverDeleted;
int restarts;
bool mustSucceed;
SyncMode syncMode;
// if set, then the report is copied here
SyncReport *m_report;
CheckSyncReport &setMode(SyncMode mode) { syncMode = mode; return *this; }
CheckSyncReport &setReport(SyncReport *report) { m_report = report; return *this; }
CheckSyncReport &setRestarts(int r) { restarts = r; return *this; }
/**
* checks that the sync completed as expected and throws
* CPPUnit exceptions if something is wrong
*
* @param res return code from SyncClient::sync()
* @param report the sync report stored in the SyncClient
*/
void check(SyncMLStatus status, SyncReport &report) const;
/**
* checks that the source report matches with expectations
*/
void check(const std::string &name, const SyncSourceReport &report) const;
};
/**
* parameters for running a sync
*/
struct SyncOptions {
/** default maximum message size */
static const long DEFAULT_MAX_MSG_SIZE = 128 * 1024;
/** default maximum object size */
static const long DEFAULT_MAX_OBJ_SIZE = 1024 * 1024 * 1024;
/** sync mode chosen by client */
SyncMode m_syncMode;
/**
* has to be called after a successful or unsuccessful sync,
* will dump the report and (optionally) check the result;
* beware, the later may throw exceptions inside CPPUNIT macros
*/
CheckSyncReport m_checkReport;
/** maximum message size supported by client */
long m_maxMsgSize;
/** maximum object size supported by client */
long m_maxObjSize;
/** enabled large object support */
bool m_loSupport;
/** enabled WBXML (default) */
bool m_isWBXML;
/** overrides resend properties */
int m_retryDuration;
int m_retryInterval;
std::shared_ptr<SuspendFlags::StateBlocker> m_isSuspended;
std::shared_ptr<SuspendFlags::StateBlocker> m_isAborted;
/**
* Callback to be invoked after setting up local sources, but
* before running the engine. May throw exception to indicate
* error and return true to stop sync without error.
*/
typedef std::function<bool (SyncContext &,
SyncOptions &)> Callback_t;
Callback_t m_startCallback;
/**
* called while configuration is prepared for sync, see
* SyncContext::prepare()
*/
Callback_t m_prepareCallback;
std::shared_ptr<TransportAgent> m_transport;
SyncOptions(SyncMode syncMode = SYNC_NONE,
const CheckSyncReport &checkReport = CheckSyncReport(),
long maxMsgSize = DEFAULT_MAX_MSG_SIZE, // 128KB = large enough that normal tests should run with a minimal number of messages
long maxObjSize = DEFAULT_MAX_OBJ_SIZE, // 1GB = basically unlimited...
bool loSupport = false,
bool isWBXML = defaultWBXML(),
const Callback_t &startCallback = [] (SyncContext &, SyncOptions &) { return false; },
const std::shared_ptr<TransportAgent> &transport = {}) :
m_syncMode(syncMode),
m_checkReport(checkReport),
m_maxMsgSize(maxMsgSize),
m_maxObjSize(maxObjSize),
m_loSupport(loSupport),
m_isWBXML(isWBXML),
m_retryDuration(300),
m_retryInterval(60),
m_startCallback(startCallback),
m_transport (transport)
{}
SyncOptions &setSyncMode(SyncMode syncMode) { m_syncMode = syncMode; return *this; }
SyncOptions &setCheckReport(const CheckSyncReport &checkReport) { m_checkReport = checkReport; return *this; }
SyncOptions &setMaxMsgSize(long maxMsgSize) { m_maxMsgSize = maxMsgSize; return *this; }
SyncOptions &setMaxObjSize(long maxObjSize) { m_maxObjSize = maxObjSize; return *this; }
SyncOptions &setLOSupport(bool loSupport) { m_loSupport = loSupport; return *this; }
SyncOptions &setWBXML(bool isWBXML) { m_isWBXML = isWBXML; return *this; }
SyncOptions &setRetryDuration(int retryDuration) { m_retryDuration = retryDuration; return *this; }
SyncOptions &setRetryInterval(int retryInterval) { m_retryInterval = retryInterval; return *this; }
SyncOptions &setStartCallback(const Callback_t &callback) { m_startCallback = callback; return *this; }
SyncOptions &setPrepareCallback(const Callback_t &callback) { m_prepareCallback = callback; return *this; }
SyncOptions &setTransportAgent(const std::shared_ptr<TransportAgent> &transport)
{m_transport = transport; return *this;}
/** if CLIENT_TEST_XML=1, then XML, otherwise WBXML */
static bool defaultWBXML();
};
class LocalTests;
class SyncTests;
/**
* This is the interface expected by the testing framework for sync
* clients. It defines several methods that a derived class must
* implement if it wants to use that framework. Note that this class
* itself is not derived from SyncClient. This gives a user of this
* framework the freedom to implement it in two different ways:
* - implement a class derived from both SyncClient and ClientTest
* - add testing of an existing subclass of SyncClient by implementing
* a ClientTest which uses that subclass
*
* The client is expected to support change tracking for multiple
* servers. Although the framework always always tests against the
* same server, for most tests it is necessary to access the database
* without affecting the next synchronization with the server. This is
* done by asking the client for two different sync sources via
* Config::createSourceA and Config::createSourceB which have to
* create them in a suitable way - pretty much as if the client was
* synchronized against different server. A third, different change
* tracking is needed for real synchronizations of the data.
*
* Furthermore the client is expected to support multiple data sources
* of the same kind, f.i. two different address books. This is used to
* test full client A <-> server <-> client B synchronizations in some
* tests or to check server modifications done by client A with a
* synchronization against client B. In those tests client A is mapped
* to the first data source and client B to the second one.
*
* Handling configuration and creating classes is entirely done by the
* subclass of ClientTest, the frameworks makes no assumptions
* about how this is done. Instead it queries the ClientTest for
* properties (like available sync sources) and then creates several
* tests.
*/
class ClientTest : private boost::noncopyable {
public:
ClientTest(int serverSleepSec = 0, const std::string &serverLog= "");
virtual ~ClientTest();
testing: enhanced DAV source testing + infrastructure The main goal is to test CalDAV/CardDAV sources as part of a SyncML client and/or server. A test involving syncevo-http-server is now named "<client storage><server storage>": - edsfile = EDS in client, file in server (used to be syncevohttp) - davfile = CalDAV/CardDAV in client, file in server (new) - edsdav = EDS in client, CalDAV/CardDAV in server (new) For this, WebDAVSourceRegister.cpp must be able to create test sources which match the client 1/2 sync configs. The client "1" or "2" strings are passed through the abstract ClientTest into the source A/B create callbacks. WebDAVSourceRegister.cpp cannot get this directly from ClientTest because it lives in a plugin which is not necessarily linked against ClientTest. A conceptual change is that CLIENT_TEST_EVOLUTION_PREFIX/USER/PASSWORD no longer override existing config properties. That is necessary because the shared prefix is too simplistic for WebDAV (needs full URL in "database"); also helps KDE (needs resource URI). The env variables and the default "SyncEvolution_Test_" value for the database prefix are still used if the config does not exist. That is useful to prevent accidentally running client-test against the default databases. The nightly setup script might (should!?) be made public to simplify configuring a server. Another change is the user-configurable part of client-test now lives entirely in the _1/_2 client sync configs and contexts. From there the source properties are copied into the Client::Source context each time client-test runs.
2012-04-23 13:03:32 +02:00
/** a unique string - "1" or "2" in practice */
virtual std::string getClientID() const = 0;
/** set up before running a test */
virtual void setup() { }
/** cleanup function to be called when shutting down testing */
typedef void (*Cleanup_t)(void);
/**
* Call this to register another shutdown cleanup functions.
* Every unique function will be called exactly once.
*/
static void registerCleanup(Cleanup_t cleanup);
/**
* Call cleanup functions.
*/
static void shutdown();
/**
* This function registers tests using this instance of ClientTest for
* later use during a test run.
*
* The instance must remain valid until after the tests were
* run. To run them use a separate test runner, like the one from
* client-test-main.cpp.
*/
virtual void registerTests();
typedef ClientTestConfig Config;
/**
* Creates an instance of LocalTests (default implementation) or a
* class derived from it. LocalTests provides tests which cover
* the SyncSource interface and can be executed without a SyncML
* server. It also contains utility functions for working with
* SyncSources.
*
* A ClientTest implementation can, but doesn't have to extend
* these tests by instantiating a derived class here.
*/
virtual LocalTests *createLocalTests(const std::string &name, int sourceParam, ClientTest::Config &co);
/**
* Creates an instance of SyncTests (default) or a class derived
* from it. SyncTests provides tests which cover the actual
* interaction with a SyncML server.
*
* A ClientTest implementation can, but doesn't have to extend
* these tests by instantiating a derived class here.
*/
virtual SyncTests *createSyncTests(const std::string &name, std::vector<int> sourceIndices, bool isClientA = true);
/**
* utility function for dumping items which are C strings with blank lines as separator
*/
static int dump(ClientTest &client, TestingSyncSource &source, const std::string &file);
/**
* utility function for splitting file into items with blank lines as separator
*
* @retval realfile If <file>.<server>.tem exists, then it is used instead
* of the generic version. The caller gets the name of the
* file that was opened here.
*/
static void getItems(const std::string &file, std::list<std::string> &items, std::string &realfile);
/**
* utility function for importing items with blank lines as separator,
* for ClientTestConfig::m_import
*/
static std::string import(ClientTest &client, TestingSyncSource &source,
const ClientTestConfig &config,
const std::string &file, std::string &realfile,
std::list<std::string> *luids);
/**
* utility function for comparing vCard and iCal files with the external
* synccompare.pl Perl script
*/
static bool compare(ClientTest &client, const std::string &fileA, const std::string &fileB);
/**
* utility function: update a vCard or iCalendar item by inserting "MOD-" into
* FN, N, resp. SUMMARY; used for ClientTestConfig::update
*/
static void update(std::string &item);
struct ClientTestConfig config;
/**
* A derived class can use this call to get default test
* cases, but still has to add callbacks which create sources
* and execute a sync session.
*
* Some of the test cases are compiled into the library, other
* depend on the auxiliary files from the "test" directory.
* Currently supported types:
* - eds_contact = vCard 3.0 contacts, with Evolution extensions
* - eds_event = iCalendar 2.0 events, as used by Evolution
* - eds_task = iCalendar 2.0 tasks, as used by Evolution
* - eds_memo = iCalendar 2.0 journals, as used by Evolution
*/
static void getTestData(const char *type, Config &config);
/**
* Data sources are enumbered from 0 to n-1 for the purpose of
* testing. This call returns n.
*/
virtual int getNumLocalSources() = 0;
virtual int getNumSyncSources() = 0;
/**
* Called to fill the given test source config with information
* about a sync source identified by its index. It's okay to only
* fill in the available pieces of information and set everything
* else to zero.
* Two kinds of source config indexs are maintained, used for localSources
* and SyncSources, this is because virtual datasoures should be visible as
* a whole to the synccontext while should be viewed as a list of sub
* datasoures for Localtests.
*/
virtual void getLocalSourceConfig(int source, Config &config) = 0;
virtual void getSyncSourceConfig(int source, Config &config) = 0;
/**
* Find the correspoding test source config via config name.
*/
virtual void getSourceConfig(const string &configName, Config &config) =0;
/*
* Give me a test source config name, return the index in localSyncSources.
* */
virtual int getLocalSourcePosition (const string &configName) =0;
/**
* The instance to use as second client. Returning nullptr disables
* all checks which require a second client. The returned pointer
* must remain valid throughout the life time of the tests.
*
* The second client must be configured to access the same server
* and have data sources which match the ones from the primary
* client.
*/
virtual ClientTest *getClientB() = 0;
/**
* Execute a synchronization with the selected sync sources
* and the selected synchronization options. The log file
* in LOG has been set up already for the synchronization run
* and should not be changed by the client.
*
* @param activeSources a -1 terminated array of sync source indices
* @param logbase basename for logging: can be used for directory or as file (by adding .log suffix)
* @param options sync options to be used
* @return return code of SyncClient::sync()
*/
virtual SyncMLStatus doSync(
const int *activeSources,
const std::string &logbase,
const SyncOptions &options) = 0;
/**
* This is called after successful sync() calls (res == 0) as well
* as after unsuccessful ones (res != 1). The default implementation
* sleeps for the number of seconds specified when constructing this
* instance and copies the server log if one was named.
*
* @param res result of sync()
* @param logname base name of the current sync log (without ".client.[AB].log" suffix)
*/
virtual void postSync(int res, const std::string &logname);
protected:
/**
* time to sleep in postSync()
*/
int serverSleepSeconds;
/**
* server log file which is copied by postSync() and then
* truncated (Unix only, Windows does not allow such access
* to an open file)
*/
std::string serverLogFileName;
private:
/**
* really a CppUnit::TestFactory, but declared as void * to avoid
* dependencies on the CPPUnit header files: created by
* registerTests() and remains valid until the client is deleted
*/
void *factory;
void freeFactory();
};
/**
* helper class to encapsulate ClientTest::Config::createsource_t
* pointer and the corresponding parameters
*/
class CreateSource {
public:
CreateSource(const ClientTest::Config::createsource_t &createSourceParam, ClientTest &clientParam, int sourceParam, bool isSourceAParam) :
createSource(createSourceParam),
client(clientParam),
source(sourceParam),
isSourceA(isSourceAParam) {}
std::unique_ptr<TestingSyncSource> operator() () const {
CPPUNIT_ASSERT(createSource);
testing: enhanced DAV source testing + infrastructure The main goal is to test CalDAV/CardDAV sources as part of a SyncML client and/or server. A test involving syncevo-http-server is now named "<client storage><server storage>": - edsfile = EDS in client, file in server (used to be syncevohttp) - davfile = CalDAV/CardDAV in client, file in server (new) - edsdav = EDS in client, CalDAV/CardDAV in server (new) For this, WebDAVSourceRegister.cpp must be able to create test sources which match the client 1/2 sync configs. The client "1" or "2" strings are passed through the abstract ClientTest into the source A/B create callbacks. WebDAVSourceRegister.cpp cannot get this directly from ClientTest because it lives in a plugin which is not necessarily linked against ClientTest. A conceptual change is that CLIENT_TEST_EVOLUTION_PREFIX/USER/PASSWORD no longer override existing config properties. That is necessary because the shared prefix is too simplistic for WebDAV (needs full URL in "database"); also helps KDE (needs resource URI). The env variables and the default "SyncEvolution_Test_" value for the database prefix are still used if the config does not exist. That is useful to prevent accidentally running client-test against the default databases. The nightly setup script might (should!?) be made public to simplify configuring a server. Another change is the user-configurable part of client-test now lives entirely in the _1/_2 client sync configs and contexts. From there the source properties are copied into the Client::Source context each time client-test runs.
2012-04-23 13:03:32 +02:00
return createSource(client, client.getClientID(), source, isSourceA);
}
const ClientTest::Config::createsource_t createSource;
ClientTest &client;
const int source;
const bool isSourceA;
};
/**
* local test of one sync source and utility functions also used by
* sync tests
*/
class LocalTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
public:
/** the client we are testing */
ClientTest &client;
/** number of the source we are testing in that client */
const int source;
/** configuration that corresponds to source */
const ClientTest::Config config;
/** shortcut for config.m_sourceName */
const std::string &getSourceName() const { return config.m_sourceName; }
/**
* A list of config pointers which share the same
* database. Normally, sources are tested in isolation, but for
* such linked sources we also need to test interdependencies, in
* particular regarding change tracking and item listing.
*
* This includes *all* configs, not just the other ones.
*/
std::list<LocalTests *> m_linkedSources;
/** helper funclets to create sources */
CreateSource createSourceA, createSourceB;
LocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) :
CppUnit::TestSuite(name),
client(cl),
source(sourceParam),
config(co),
createSourceA(co.m_createSourceA, cl, sourceParam, true),
createSourceB(co.m_createSourceB, cl, sourceParam, false)
{}
/** set up before running a test */
virtual void setUp() { client.setup(); }
/**
* adds the supported tests to the instance itself;
* this is the function that a derived class can override
* to add additional tests
*/
virtual void addTests();
/**
* opens source and inserts the given item; can be called
* regardless whether the data source already contains items or not
*
* @param relaxed if true, then disable some of the additional checks after adding the item
* @retval inserted actual data that was inserted, optional
* @param uniqueUIDSuffix gets added to UID of the inserted item if unique UIDs are necessary
* @return the LUID of the inserted item
*/
virtual std::string insert(const CreateSource &createSource, const std::string &data, bool relaxed = false, std::string *inserted = nullptr, const std::string &uniqueUIDSuffix = "");
/**
* assumes that exactly one element is currently inserted and updates it with the given item
*
* @param check if true, then reopen the source and verify that the reported items are as expected
* @param uniqueUIDSuffix same UID suffix as when creating the item
*/
virtual void update(const CreateSource &createSource, const std::string &data, bool check = true, const std::string &uniqueUIDSuffix = "");
/**
* updates one item identified by its LUID with the given item
*
* The type of the item is cleared, as in insert() above.
*/
virtual void update(const CreateSource &createSource, const std::string &data, const std::string &luid);
/** deletes all items locally via sync source */
virtual void deleteAll(const CreateSource &createSource);
/**
* takes two databases, exports them,
* then compares them using synccompare
*
* @param refFile existing file with source reference items, nullptr 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)
* @return true if the two databases are equal
*/
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
virtual bool compareDatabases(const char *refFile, TestingSyncSource &copy, bool raiseAssert = true);
/**
* compares data using synccompare
*
* @param refFile existing file with source reference items
* @param actualFile existing file with actual items which are expected to match
* @param raiseAssert raise assertion if comparison yields differences (defaults to true)
* @return true if the two databases are equal
*/
bool compareDatabases(const std::string &refFile, const std::string &actualFile, bool raiseAssert = true);
/**
* compare data in source with set of items
*/
void compareDatabasesRef(TestingSyncSource &copy,
const std::list<std::string> &items);
/**
* compare data in source with vararg list of std::string pointers, nullptr terminated
*/
void compareDatabases(TestingSyncSource *copy, ...);
/**
* insert artificial items, number of them determined by TEST_EVOLUTION_NUM_ITEMS
* 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
* @param numItems number of items to be inserted if non-null, otherwise TEST_EVOLUTION_NUM_ITEMS is used
* @param size minimum size for new items
* @return number of items inserted
*/
virtual std::list<std::string> insertManyItems(const CreateSource &createSource, int startIndex = 1, int numItems = 0, int size = -1);
virtual std::list<std::string> insertManyItems(TestingSyncSource *source, int startIndex = 1, int numItems = 0, int size = -1);
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
/**
* Update existing items. Must match a corresponding previous call to
* insertManyItems().
*
* @param revision revision number, used to distinguish different generations of each item
* @param luids result from corresponding insertManyItems() call
* @param offset skip that many items at the start of luids before updating the following ones
*/
void updateManyItems(const CreateSource &createSource, int startIndex, int numItems, int size,
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
int revision,
std::list<std::string> &luids,
int offset);
/**
* Delete items. Skips offset items in luids before deleting numItems.
*/
void removeManyItems(const CreateSource &createSource, int numItems,
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
std::list<std::string> &luids,
int offset);
/**
* update every single item, using config.update
*/
virtual void updateData(const CreateSource &createSource);
/**
* create an artificial item for the current database
*
* @param item item number: items with different number should be
* recognized as different by SyncML servers
* @param revision differentiates items with the same item number (= updates of an older item)
* @param size if > 0, then create items at least that large (in bytes)
* @return created item
*/
std::string createItem(int item, const std::string &revision, int size);
std::string createItem(int item, int revision, int size) {
char buffer[32];
sprintf(buffer, "%d", revision);
return createItem(item, std::string(buffer), size);
}
/* for more information on the different tests see their implementation */
virtual void testOpen();
virtual void testIterateTwice();
virtual void testDelete404();
virtual void testReadItem404();
void doInsert(bool withUID = true);
virtual void testSimpleInsert();
virtual void testLocalDeleteAll();
virtual void testComplexInsert();
virtual void testInsertTwice();
virtual void testLocalUpdate();
void doChanges(bool restart);
virtual void testChanges();
virtual void testChangesMultiCycles();
virtual void testLinkedSources();
void doImport(const std::string &testcases);
virtual void testImport();
virtual void testImportDelete();
virtual void testRemoveProperties();
virtual void testManyChanges();
virtual void testLinkedItemsParent();
virtual void testLinkedItemsChild();
virtual void testLinkedItemsParentChild();
virtual void testLinkedItemsChildParent();
virtual void testLinkedItemsChildChangesParent();
virtual void testLinkedItemsRemoveParentFirst();
virtual void testLinkedItemsRemoveNormal();
virtual void testLinkedItemsInsertParentTwice();
virtual void testLinkedItemsInsertChildTwice();
virtual void testLinkedItemsParentUpdate();
virtual void testLinkedItemsUpdateChild();
virtual void testLinkedItemsInsertBothUpdateChild();
virtual void testLinkedItemsInsertBothUpdateParent();
testing: renamed LinkedItems tests, added "no ID" variants Numbering Client::Source::LinkedItems_xxx with xxx being a number is confusing, in particular when the same number stands for different test data. Now each set of linked items has an additional, unique name which is used for Client::Source::LinkedItems<Name>. Done in combination with adding more linked item tests and slightly reorganizing the logic for adding them: - a default set with VTIMEZONE is added in all cases - some SyncML servers override that default set - others, in particular peers accessed via their own backend, enable additional Client::Source tests on a case-by-case basis Exchange is only tested with its own default set (with "Standard Timezone" as TZID) and the all-day recurring set (as before). All other CalDAV servers are now also tested with the all-day set (previously exclusive to Exchange) and local floating time (= no TZID, new). Google CalDAV can't be tested with local time because it converts such events into the time zone of the current user. All-day events need special test data because Google adds a time to the UNTIL clause (http://code.google.com/p/google-caldav-issues/issues/detail?id=63). synccompare also needs to ignore that Google adds a redundant VTIMEZONE to the all-day test cases. Finally, Client::Source tests for updating a child event (with and without parent) without UID and RECURRENCE-ID inside the payload were added. These properties are removed via text operations. The expectation is that the source is able to add them back (if needed) based on the meta information that it has about the existing item. The file source is unable to do that. When using it in an HTTP server, the server will look to peers like a peer which doesn't support the semantic (which indeed it doesn't) and thus the client will add back the fields.
2011-11-02 12:11:48 +01:00
virtual void testLinkedItemsInsertBothUpdateChildNoIDs();
virtual void testLinkedItemsUpdateChildNoIDs();
virtual void testLinkedItemsSingle404();
virtual void testLinkedItemsMany404();
virtual void testSubset();
/** retrieve right set of items for running test */
ClientTestConfig::LinkedItems_t getParentChildData();
};
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);
/**
* Tests synchronization with one or more sync sources enabled.
* When testing multiple sources at once only the first config
* is checked to see which tests can be executed.
*/
class SyncTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
public:
/** the client we are testing */
ClientTest &client;
SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA = true);
~SyncTests();
/**
* adds the supported tests to the instance itself
* @param isFirstSource the tests are getting generated for a single source,
* the one which was listed first; some tests are the
* same for all sources and should only be run once
*/
virtual void addTests(bool isFirstSource = false);
/** set up before running a test */
virtual void setUp() { client.setup(); }
protected:
/** list with all local test classes for manipulating the sources and their index in the client */
typedef std::vector< std::pair<int, LocalTests *> > source_array_t;
source_array_t sources;
typedef source_array_t::iterator source_it;
/**
* Stack of log file prefixes which are to be appended to the base name,
* which already contains the current test name. Add a new prefix by
* instantiating SyncPrefix. Its destructor takes care of popping
* the prefix.
*/
std::list<std::string> logPrefixes;
class SyncPrefix {
SyncTests &m_tests;
public:
SyncPrefix(const std::string &prefix, SyncTests &tests) :
m_tests(tests) {
tests.logPrefixes.push_back(prefix);
}
~SyncPrefix() {
m_tests.logPrefixes.pop_back();
}
};
friend class SyncPrefix;
/** the indices from sources, terminated by -1 (for sync()) */
int *sourceArray;
/** utility functions for second client */
SyncTests *accessClientB;
enum DeleteAllMode {
DELETE_ALL_SYNC, /**< make sure client and server are in sync,
delete locally,
sync again */
DELETE_ALL_REFRESH /**< delete locally, refresh server */
};
/**
* Compare databases second client with either reference file(s)
* or first client. The reference file(s) must follow the naming
* scheme <reFileBase><source name>.dat
*/
virtual bool compareDatabases(const char *refFileBase = nullptr,
bool raiseAssert = true);
/** deletes all items locally and on server */
virtual void deleteAll(DeleteAllMode mode = DELETE_ALL_SYNC);
/** get both clients in sync with empty server, then copy one item from client A to B */
virtual void doCopy();
/**
* 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
*/
virtual void refreshClient(SyncOptions options = SyncOptions());
/* for more information on the different tests see their implementation */
virtual void testTwoWaySync();
virtual void testSlowSync();
virtual void testRefreshFromServerSync();
virtual void testRefreshFromClientSync();
virtual void testRefreshFromRemoteSync();
virtual void testRefreshFromLocalSync();
virtual void testDeleteAllSync();
virtual void testDeleteAllRefresh();
virtual void testRefreshFromClientSemantic();
virtual void testRefreshFromServerSemantic();
virtual void testRefreshStatus();
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
void doRestartSync(SyncMode mode);
void testTwoWayRestart();
void testSlowRestart();
void testRefreshFromLocalRestart();
void testOneWayFromLocalRestart();
void testRefreshFromRemoteRestart();
void testOneWayFromRemoteRestart();
void testManyRestarts();
void testCopy();
virtual void testUpdate();
virtual void testComplexUpdate();
virtual void testDelete();
virtual void testMerge();
virtual void testTwinning();
void doOneWayFromRemote(SyncMode oneWayFromRemote);
void testOneWayFromServer();
void testOneWayFromRemote();
void doOneWayFromLocal(SyncMode oneWayFromLocal);
void testOneWayFromClient();
void testOneWayFromLocal();
virtual void testConversion();
virtual void testItems();
virtual void testItemsXML();
virtual void testExtensions();
virtual void testAddUpdate();
void testMaxMsg();
void testLargeObject();
virtual void testManyItems();
virtual void testManyDeletes();
virtual void testSlowSyncSemantic();
virtual void testComplexRefreshFromServerSemantic();
virtual void testDeleteBothSides();
virtual void testAddBothSides();
virtual void testAddBothSidesRefresh();
virtual void testLinkedItemsParentChild();
virtual void testLinkedItemsChild();
virtual void testLinkedItemsChildParent();
virtual void doInterruptResume(int changes,
std::shared_ptr<TransportWrapper> wrapper);
/**
* CLIENT_ = change made on client B before interrupting
* SERVER_ = change made on client A and applied to server before interrupting
* while sending to B
* _ADD = new item added
* _REMOVE = existing item deleted
* _UPDATE = existing item replaced
* BIG = when adding or updating, make the new item so large that it does
* not fit into a single message
*/
enum {
CLIENT_ADD = (1<<0),
CLIENT_REMOVE = (1<<1),
CLIENT_UPDATE = (1<<2),
SERVER_ADD = (1<<3),
SERVER_REMOVE = (1<<4),
SERVER_UPDATE = (1<<5),
BIG = (1<<6)
};
virtual void testInterruptResumeClientAdd();
virtual void testInterruptResumeClientRemove();
virtual void testInterruptResumeClientUpdate();
virtual void testInterruptResumeServerAdd();
virtual void testInterruptResumeServerRemove();
virtual void testInterruptResumeServerUpdate();
virtual void testInterruptResumeClientAddBig();
virtual void testInterruptResumeClientUpdateBig();
virtual void testInterruptResumeServerAddBig();
virtual void testInterruptResumeServerUpdateBig();
virtual void testInterruptResumeFull();
virtual void testUserSuspendClientAdd();
virtual void testUserSuspendClientRemove();
virtual void testUserSuspendClientUpdate();
virtual void testUserSuspendServerAdd();
virtual void testUserSuspendServerRemove();
virtual void testUserSuspendServerUpdate();
virtual void testUserSuspendClientAddBig();
virtual void testUserSuspendClientUpdateBig();
virtual void testUserSuspendServerAddBig();
virtual void testUserSuspendServerUpdateBig();
virtual void testUserSuspendFull();
virtual void testResendClientAdd();
virtual void testResendClientRemove();
virtual void testResendClientUpdate();
virtual void testResendServerAdd();
virtual void testResendServerRemove();
virtual void testResendServerUpdate();
virtual void testResendFull();
virtual void testResendProxyClientAdd();
virtual void testResendProxyClientRemove();
virtual void testResendProxyClientUpdate();
virtual void testResendProxyServerAdd();
virtual void testResendProxyServerRemove();
virtual void testResendProxyServerUpdate();
virtual void testResendProxyFull();
virtual void testTimeout();
virtual void testUpload();
virtual void testDownload();
void doUpdateConflict(const std::string &testname, bool localWins);
virtual void testUpdateLocalWins();
virtual void testUpdateRemoteWins();
/**
* implements testMaxMsg(), testLargeObject(), testLargeObjectEncoded()
* using a sequence of items with varying sizes
*/
virtual void doVarSizes(bool withMaxMsgSize,
bool withLargeObject);
/**
* executes a sync with the given options,
* checks the result and (optionally) the sync report
*/
virtual void doSync(const SyncOptions &options);
virtual void doSync(const char *logPrefix,
const SyncOptions &options) {
SyncPrefix prefix(logPrefix, *this);
doSync(options);
}
void doSync(const char *file, int line,
const char *logPrefix,
const SyncOptions &options) {
CT_WRAP_ASSERT(file, line, doSync(logPrefix, options), CT_ASSERT_EXE_CLANG_BUILD(doSync(logPrefix, options)));
}
void doSync(const char *file, int line,
const SyncOptions &options) {
CT_WRAP_ASSERT(file, line, doSync(options), CT_ASSERT_EXE_CLANG_BUILD(doSync(options)));
}
virtual void postSync(int res, const std::string &logname);
private:
void allSourcesInsert(bool withUID = true);
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
void allSourcesUpdate();
void allSourcesDeleteAll();
client-test: add Client::Sync::*::testTwoWayRestart The Client::Sync::*::testTwoWayRestart is the first of several tests which runs a sync, make changes to the local data after the each cycle has completed, and requests the sync to continue. Adding, updating and deleting items are covered with sync sessions which all consist of two cycles. The test checks the final sync mode (same as original cycle), all intermediate reports (captured before each startDataRead slot, at which time all results from the previous sync are guaranteed to be recorded) and total number of cycles. The tests for the other sync modes follow the same pattern and use the same code. refresh-from-remote is problematic. Should it try to wipe out all items added after the initial refresh-from-remote? The one-way-from-remote sync that happens in later cycles doesn't do that. The test currently expects that the item doesn't get deleted and thus reflects the current implementation. For refresh-from-remote only adding can be tested, because any further syncs remove that item as it never reaches the server and will be deleted locally. Client::Sync::*::testManyCycles makes different changes (add/modify/remove different numbers of items) before each cycle, leading to a long sync with 13 cycles altogether. CLIENT_TEST_PEER_CAN_RESTART must be set if and only if the peer can restart a sync. When set, the full set of restart tests is enabled and expected to restart. Otherwise, only testTwoWayRestart is tested and expected to not do a restart despite the request to do so. Furthermore, when acting as server no restart tests are done because that doesn't work in server mode. Older boost::lambda (as on Ubunty Hardy) has problems with binds which involve references to classes with pure virtual methods, like SyncSource. Later Boost releases fixed that: http://lists.boost.org/boost-users/2006/03/18053.php As a workaround for older Boost a pointer to SyncSource is used in boost::lambda::bind.
2012-02-13 10:56:25 +01:00
void allSourcesInsertMany(int startIndex, int numItems,
std::map<int, std::list<std::string> > &luids);
void allSourcesUpdateMany(int startIndex, int numItems,
int revision,
std::map<int, std::list<std::string> > &luids,
int offset);
void allSourcesRemoveMany(int numItems,
std::map<int, std::list<std::string> > &luids,
int offset);
};
/*
* A transport wraper wraps a real transport impl and gives user
* possibility to do additional work before/after transport operation.
* We use TransportFaultInjector to emulate a network failure;
* We use UserSuspendInjector to emulate a user suspend after receving
* a response.
*/
class TransportWrapper : public TransportAgent {
protected:
int m_interruptAtMessage, m_messageCount;
std::shared_ptr<TransportAgent> m_wrappedAgent;
Status m_status;
SyncOptions *m_options;
public:
TransportWrapper() {
m_messageCount = 0;
m_interruptAtMessage = -1;
m_status = INACTIVE;
m_options = nullptr;
}
~TransportWrapper() {
}
/**
* -1 for wrappers which are meant to be used without message resending,
* otherwise the number x for which "interrupt" <= x will lead to
* an aborted sync (0 for TransportResendInjector, 2 for TransportResendProxy)
*/
virtual int getResendFailureThreshold() { return -1; }
virtual int getMessageCount() { return m_messageCount; }
virtual void setURL(const std::string &url) { m_wrappedAgent->setURL(url); }
virtual void setContentType(const std::string &type) { m_wrappedAgent->setContentType(type); }
virtual void setAgent(std::shared_ptr<TransportAgent> agent) {m_wrappedAgent = agent;}
virtual void setSyncOptions(SyncOptions *options) {m_options = options;}
virtual void setInterruptAtMessage (int interrupt) {m_interruptAtMessage = interrupt;}
virtual void cancel() { m_wrappedAgent->cancel(); }
virtual void shutdown() { m_wrappedAgent->shutdown(); }
virtual void rewind() {
m_messageCount = 0;
m_interruptAtMessage = -1;
m_status = INACTIVE;
m_options = nullptr;
m_wrappedAgent.reset();
}
virtual Status wait(bool noReply = false) { return m_status; }
virtual void setTimeout(int seconds) { m_wrappedAgent->setTimeout(seconds); }
};
/** write log message into *.log file of a test */
#define CLIENT_TEST_LOG(_format, _args...) \
SE_LOG_DEBUG(NULL, "\n%s:%d *** " _format, \
getBasename(__FILE__).c_str(), __LINE__, \
##_args)
/** assert equality, include string in message if unequal */
#define CLIENT_TEST_EQUAL( _prefix, \
_expected, \
_actual ) \
CT_ASSERT_EQUAL_MESSAGE( std::string(_prefix) + ": " + #_expected + " == " + #_actual, \
_expected, \
_actual )
/** execute _x and then check the status of the _source pointer */
#define SOURCE_ASSERT_NO_FAILURE(_source, _x) \
{ \
CT_ASSERT_NO_THROW(_x); \
CT_ASSERT((_source)); \
}
/** check _x for true and then the status of the _source pointer */
#define SOURCE_ASSERT(_source, _x) \
{ \
CT_ASSERT(_x); \
CT_ASSERT((_source)); \
}
/** check that _x evaluates to a specific value and then the status of the _source pointer */
#define SOURCE_ASSERT_EQUAL(_source, _value, _x) \
{ \
CT_ASSERT_EQUAL(_value, _x); \
CT_ASSERT((_source)); \
}
/** same as SOURCE_ASSERT() with a specific failure message */
#define SOURCE_ASSERT_MESSAGE(_message, _source, _x) \
{ \
CT_ASSERT_MESSAGE((_message), (_x)); \
CT_ASSERT((_source)); \
}
/**
* convenience macro for adding a test name like a function,
* to be used inside addTests() of an instance of that class
*
* @param _class class which contains the function
* @param _function a function without parameters in that class
*/
#define ADD_TEST(_class, _function) \
ADD_TEST_TO_SUITE(this, _class, _function)
#define ADD_TEST_TO_SUITE(_suite, _class, _function) \
_suite->addTest(FilterTest(new CppUnit::TestCaller<_class>(_suite->getName() + "::" #_function, &_class::_function, *this)))
#define ADD_TEST_TO_SUITE_SUFFIX(_suite, _class, _function, _suffix) \
_suite->addTest(FilterTest(new CppUnit::TestCaller<_class>(_suite->getName() + "::" #_function + _suffix, &_class::_function, *this)))
SE_END_CXX
#endif // ENABLE_INTEGRATION_TESTS
#endif // INCL_TESTSYNCCLIENT