6308063e309446efac13e251641375e17517cf32
[platform/upstream/syncevolution.git] / test / ClientTest.h
1 /*
2  * Copyright (C) 2008 Funambol, Inc.
3  * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
4  * Copyright (C) 2009 Intel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) version 3.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301  USA
20  */
21
22 #ifndef INCL_TESTSYNCCLIENT
23 #define INCL_TESTSYNCCLIENT
24
25 #include <string>
26 #include <vector>
27 #include <list>
28
29 #include <boost/function.hpp>
30 #include <boost/shared_ptr.hpp>
31
32 #include <SyncML.h>
33 #include <TransportAgent.h>
34 #include <SyncSource.h>
35
36 #include "test.h"
37
38 #ifdef ENABLE_INTEGRATION_TESTS
39
40 #include <cppunit/TestSuite.h>
41 #include <cppunit/TestAssert.h>
42 #include <cppunit/TestFixture.h>
43
44 #include <syncevo/declarations.h>
45 SE_BEGIN_CXX
46
47 class SyncContext;
48 class EvolutionSyncSource;
49 class TransportWrapper;
50 class TestingSyncSource;
51
52 /**
53  * This class encapsulates logging and checking of a SyncReport.
54  * When constructed with default parameters, no checking will be done.
55  * Otherwise the sync report has to contain exactly the expected result.
56  * When multiple sync sources are active, @b all of them have to behave
57  * alike (which is how the tests are constructed).
58  *
59  * No item is ever supposed to fail.
60  */
61 class CheckSyncReport {
62   public:
63     CheckSyncReport(int clAdded = -1, int clUpdated = -1, int clDeleted = -1,
64                     int srAdded = -1, int srUpdated = -1, int srDeleted = -1,
65                     bool mstSucceed = true, SyncMode mode = SYNC_NONE) :
66         clientAdded(clAdded),
67         clientUpdated(clUpdated),
68         clientDeleted(clDeleted),
69         serverAdded(srAdded),
70         serverUpdated(srUpdated),
71         serverDeleted(srDeleted),
72         mustSucceed(mstSucceed),
73         syncMode(mode)
74         {}
75
76     virtual ~CheckSyncReport() {}
77
78     int clientAdded, clientUpdated, clientDeleted,
79         serverAdded, serverUpdated, serverDeleted;
80     bool mustSucceed;
81     SyncMode syncMode;
82
83     /**
84      * checks that the sync completed as expected and throws
85      * CPPUnit exceptions if something is wrong
86      *
87      * @param res     return code from SyncClient::sync()
88      * @param report  the sync report stored in the SyncClient
89      */
90     virtual void check(SyncMLStatus status, SyncReport &report) const;
91 };
92
93 /**
94  * parameters for running a sync
95  */
96 struct SyncOptions {
97     /** default maximum message size */
98     static const long DEFAULT_MAX_MSG_SIZE = 128 * 1024;
99     /** default maximum object size */
100     static const long DEFAULT_MAX_OBJ_SIZE = 1024 * 1024 * 1024;
101     /** sync mode chosen by client */
102     SyncMode m_syncMode;
103     /**
104      * has to be called after a successful or unsuccessful sync,
105      * will dump the report and (optionally) check the result;
106      * beware, the later may throw exceptions inside CPPUNIT macros
107      */
108     CheckSyncReport m_checkReport;
109
110     /** maximum message size supported by client */
111     long m_maxMsgSize;
112     /** maximum object size supported by client */
113     long m_maxObjSize;
114     /** enabled large object support */
115     bool m_loSupport;
116     /** enabled WBXML (default) */
117     bool m_isWBXML;
118
119     bool m_isSuspended; 
120     
121     bool m_isAborted;
122
123     typedef boost::function<bool (SyncContext &,
124                                   SyncOptions &)> Callback_t;
125     /**
126      * Callback to be invoked after setting up local sources, but
127      * before running the engine. May throw exception to indicate
128      * error and return true to stop sync without error.
129      */
130     Callback_t m_startCallback;
131
132     boost::shared_ptr<TransportAgent> m_transport;
133
134     SyncOptions(SyncMode syncMode = SYNC_NONE,
135                 const CheckSyncReport &checkReport = CheckSyncReport(),
136                 long maxMsgSize = DEFAULT_MAX_MSG_SIZE, // 128KB = large enough that normal tests should run with a minimal number of messages
137                 long maxObjSize = DEFAULT_MAX_OBJ_SIZE, // 1GB = basically unlimited...
138                 bool loSupport = false,
139                 bool isWBXML = defaultWBXML(),
140                 Callback_t startCallback = EmptyCallback,
141                 boost::shared_ptr<TransportAgent> transport =
142                 boost::shared_ptr<TransportAgent>()) :
143         m_syncMode(syncMode),
144         m_checkReport(checkReport),
145         m_maxMsgSize(maxMsgSize),
146         m_maxObjSize(maxObjSize),
147         m_loSupport(loSupport),
148         m_isWBXML(isWBXML),
149         m_isSuspended(false),
150         m_isAborted(false),
151         m_startCallback(startCallback),
152         m_transport (transport)
153     {}
154
155     SyncOptions &setSyncMode(SyncMode syncMode) { m_syncMode = syncMode; return *this; }
156     SyncOptions &setCheckReport(const CheckSyncReport &checkReport) { m_checkReport = checkReport; return *this; }
157     SyncOptions &setMaxMsgSize(long maxMsgSize) { m_maxMsgSize = maxMsgSize; return *this; }
158     SyncOptions &setMaxObjSize(long maxObjSize) { m_maxObjSize = maxObjSize; return *this; }
159     SyncOptions &setLOSupport(bool loSupport) { m_loSupport = loSupport; return *this; }
160     SyncOptions &setWBXML(bool isWBXML) { m_isWBXML = isWBXML; return *this; }
161     SyncOptions &setStartCallback(const Callback_t &callback) { m_startCallback = callback; return *this; }
162     SyncOptions &setTransportAgent(const boost::shared_ptr<TransportAgent> transport)
163                                   {m_transport = transport; return *this;}
164
165     static bool EmptyCallback(SyncContext &,
166                               SyncOptions &) { return false; }
167
168     /** if CLIENT_TEST_XML=1, then XML, otherwise WBXML */
169     static bool defaultWBXML();
170 };
171
172 class LocalTests;
173 class SyncTests;
174
175 /**
176  * This is the interface expected by the testing framework for sync
177  * clients.  It defines several methods that a derived class must
178  * implement if it wants to use that framework. Note that this class
179  * itself is not derived from SyncClient. This gives a user of this
180  * framework the freedom to implement it in two different ways:
181  * - implement a class derived from both SyncClient and ClientTest
182  * - add testing of an existing subclass of SyncClient by implementing
183  *   a ClientTest which uses that subclass
184  *
185  * The client is expected to support change tracking for multiple
186  * servers. Although the framework always always tests against the
187  * same server, for most tests it is necessary to access the database
188  * without affecting the next synchronization with the server. This is
189  * done by asking the client for two different sync sources via
190  * Config::createSourceA and Config::createSourceB which have to
191  * create them in a suitable way - pretty much as if the client was
192  * synchronized against different server. A third, different change
193  * tracking is needed for real synchronizations of the data.
194  *
195  * Furthermore the client is expected to support multiple data sources
196  * of the same kind, f.i. two different address books. This is used to
197  * test full client A <-> server <-> client B synchronizations in some
198  * tests or to check server modifications done by client A with a
199  * synchronization against client B. In those tests client A is mapped
200  * to the first data source and client B to the second one.
201  *
202  * Handling configuration and creating classes is entirely done by the
203  * subclass of ClientTest, the frameworks makes no assumptions
204  * about how this is done. Instead it queries the ClientTest for
205  * properties (like available sync sources) and then creates several
206  * tests.
207  */
208 class ClientTest {
209   public:
210     ClientTest(int serverSleepSec = 0, const std::string &serverLog= "");
211     virtual ~ClientTest();
212
213     /**
214      * This function registers tests using this instance of ClientTest for
215      * later use during a test run.
216      *
217      * The instance must remain valid until after the tests were
218      * run. To run them use a separate test runner, like the one from
219      * client-test-main.cpp.
220      */
221     virtual void registerTests();
222
223     typedef ClientTestConfig Config;
224
225     /**
226      * Creates an instance of LocalTests (default implementation) or a
227      * class derived from it.  LocalTests provides tests which cover
228      * the SyncSource interface and can be executed without a SyncML
229      * server. It also contains utility functions for working with
230      * SyncSources.
231      *
232      * A ClientTest implementation can, but doesn't have to extend
233      * these tests by instantiating a derived class here.
234      */
235     virtual LocalTests *createLocalTests(const std::string &name, int sourceParam, ClientTest::Config &co);
236
237     /**
238      * Creates an instance of SyncTests (default) or a class derived
239      * from it.  SyncTests provides tests which cover the actual
240      * interaction with a SyncML server.
241      *
242      * A ClientTest implementation can, but doesn't have to extend
243      * these tests by instantiating a derived class here.
244      */
245     virtual SyncTests *createSyncTests(const std::string &name, std::vector<int> sourceIndices, bool isClientA = true);
246
247     /**
248      * utility function for dumping items which are C strings with blank lines as separator
249      */
250     static int dump(ClientTest &client, TestingSyncSource &source, const char *file);
251
252     /**
253      * utility function for splitting file into items with blank lines as separator
254      *
255      * @retval realfile       If <file>.<server>.tem exists, then it is used instead
256      *                        of the generic version. The caller gets the name of the
257      *                        file that was opened here.
258      */
259     static void getItems(const char *file, std::list<std::string> &items, std::string &realfile);
260
261     /**
262      * utility function for importing items with blank lines as separator
263      */
264     static int import(ClientTest &client, TestingSyncSource &source, const char *file, std::string &realfile);
265
266     /**
267      * utility function for comparing vCard and iCal files with the external
268      * synccompare.pl Perl script
269      */
270     static bool compare(ClientTest &client, const char *fileA, const char *fileB);
271
272     struct ClientTestConfig config;
273
274     /**
275      * A derived class can use this call to get default test
276      * cases, but still has to add callbacks which create sources
277      * and execute a sync session.
278      *
279      * Some of the test cases are compiled into the library, other
280      * depend on the auxiliary files from the "test" directory.
281      * Currently supported types:
282      * - vcard30 = vCard 3.0 contacts
283      * - vcard21 = vCard 2.1 contacts
284      * - ical20 = iCal 2.0 events
285      * - vcal10 = vCal 1.0 events
286      * - itodo20 = iCal 2.0 tasks
287      */
288     static void getTestData(const char *type, Config &config);
289
290     /**
291      * Data sources are enumbered from 0 to n-1 for the purpose of
292      * testing. This call returns n.
293      */
294     virtual int getNumLocalSources() = 0;
295     virtual int getNumSyncSources() = 0;
296
297     /**
298      * Called to fill the given test source config with information
299      * about a sync source identified by its index. It's okay to only
300      * fill in the available pieces of information and set everything
301      * else to zero.
302      * Two kinds of source config indexs are maintained, used for localSources
303      * and SyncSources, this is because virtual datasoures should be visible as
304      * a whole to the synccontext while should be viewed as a list of sub
305      * datasoures for Localtests.
306      */
307     virtual void getLocalSourceConfig(int source, Config &config) = 0;
308     virtual void getSyncSourceConfig(int source, Config &config) = 0;
309
310     /**
311      * Find the correspoding test source config via config name.
312      */
313     virtual void getSourceConfig(const string &configName, Config &config) =0;
314     /*
315      * Give me a test source config name, return the index in localSyncSources.
316      * */
317     virtual int getLocalSourcePosition (const string &configName) =0;
318
319     /**
320      * The instance to use as second client. Returning NULL disables
321      * all checks which require a second client. The returned pointer
322      * must remain valid throughout the life time of the tests.
323      *
324      * The second client must be configured to access the same server
325      * and have data sources which match the ones from the primary
326      * client.
327      */
328     virtual ClientTest *getClientB() = 0;
329
330     /**
331      * Execute a synchronization with the selected sync sources
332      * and the selected synchronization options. The log file
333      * in LOG has been set up already for the synchronization run
334      * and should not be changed by the client.
335      *
336      * @param activeSources a -1 terminated array of sync source indices
337      * @param logbase      basename for logging: can be used for directory or as file (by adding .log suffix)
338      * @param options      sync options to be used
339      * @return return code of SyncClient::sync()
340      */
341     virtual SyncMLStatus doSync(
342         const int *activeSources,
343         const std::string &logbase,
344         const SyncOptions &options) = 0;
345
346
347     /**
348      * This is called after successful sync() calls (res == 0) as well
349      * as after unsuccessful ones (res != 1). The default implementation
350      * sleeps for the number of seconds specified when constructing this
351      * instance and copies the server log if one was named.
352      *
353      * @param res       result of sync()
354      * @param logname   base name of the current sync log (without ".client.[AB].log" suffix)
355      */
356     virtual void postSync(int res, const std::string &logname);
357
358   protected:
359     /**
360      * time to sleep in postSync()
361      */
362     int serverSleepSeconds;
363
364     /**
365      * server log file which is copied by postSync() and then
366      * truncated (Unix only, Windows does not allow such access
367      * to an open file)
368      */
369     std::string serverLogFileName;
370
371   private:
372     /**
373      * really a CppUnit::TestFactory, but declared as void * to avoid
374      * dependencies on the CPPUnit header files: created by
375      * registerTests() and remains valid until the client is deleted
376      */
377     void *factory;
378 };
379
380 /**
381  * helper class to encapsulate ClientTest::Config::createsource_t
382  * pointer and the corresponding parameters
383  */
384 class CreateSource {
385 public:
386     CreateSource(ClientTest::Config::createsource_t createSourceParam, ClientTest &clientParam, int sourceParam, bool isSourceAParam) :
387         createSource(createSourceParam),
388         client(clientParam),
389         source(sourceParam),
390         isSourceA(isSourceAParam) {}
391
392     TestingSyncSource *operator() () {
393         CPPUNIT_ASSERT(createSource);
394         return createSource(client, source, isSourceA);
395     }
396
397     const ClientTest::Config::createsource_t createSource;
398     ClientTest &client;
399     const int source;
400     const bool isSourceA;
401 };
402
403
404 /**
405  * local test of one sync source and utility functions also used by
406  * sync tests
407  */
408 class LocalTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
409 public:
410     /** the client we are testing */
411     ClientTest &client;
412
413     /** number of the source we are testing in that client */
414     const int source;
415
416     /** configuration that corresponds to source */
417     const ClientTest::Config config;
418
419     /** helper funclets to create sources */
420     CreateSource createSourceA, createSourceB;
421
422     LocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) :
423         CppUnit::TestSuite(name),
424         client(cl),
425         source(sourceParam),
426         config(co),
427         createSourceA(co.createSourceA, cl, sourceParam, true),
428         createSourceB(co.createSourceB, cl, sourceParam, false)
429         {}
430
431     /**
432      * adds the supported tests to the instance itself;
433      * this is the function that a derived class can override
434      * to add additional tests
435      */
436     virtual void addTests();
437
438     /**
439      * opens source and inserts the given item; can be called
440      * regardless whether the data source already contains items or not
441      *
442      * @param relaxed   if true, then disable some of the additional checks after adding the item
443      * @return the LUID of the inserted item
444      */
445     virtual std::string insert(CreateSource createSource, const char *data, bool relaxed = false);
446
447     /**
448      * assumes that exactly one element is currently inserted and updates it with the given item
449      *
450      * @param check     if true, then reopen the source and verify that the reported items are as expected
451      */
452     virtual void update(CreateSource createSource, const char *data, bool check = true);
453
454     /**
455      * updates one item identified by its LUID with the given item
456      *
457      * The type of the item is cleared, as in insert() above.
458      */
459     virtual void update(CreateSource createSource, const char *data, const std::string &luid);
460
461     /** deletes all items locally via sync source */
462     virtual void deleteAll(CreateSource createSource);
463
464     /**
465      * takes two databases, exports them,
466      * then compares them using synccompare
467      *
468      * @param refFile      existing file with source reference items, NULL uses a dump of sync source A instead
469      * @param copy         a sync source which contains the copied items, begin/endSync will be called
470      * @param raiseAssert  raise assertion if comparison yields differences (defaults to true)
471      * @return true if the two databases are equal
472      */
473     virtual bool compareDatabases(const char *refFile, TestingSyncSource &copy, bool raiseAssert = true);
474
475     /**
476      * insert artificial items, number of them determined by TEST_EVOLUTION_NUM_ITEMS
477      * unless passed explicitly
478      *
479      * @param createSource    a factory for the sync source that is to be used
480      * @param startIndex      IDs are generated starting with this value
481      * @param numItems        number of items to be inserted if non-null, otherwise TEST_EVOLUTION_NUM_ITEMS is used
482      * @param size            minimum size for new items
483      * @return number of items inserted
484      */
485     virtual std::list<std::string> insertManyItems(CreateSource createSource, int startIndex = 1, int numItems = 0, int size = -1);
486
487     /**
488      * create an artificial item for the current database
489      *
490      * @param item      item number: items with different number should be
491      *                  recognized as different by SyncML servers
492      * @param revision  differentiates items with the same item number (= updates of an older item)
493      * @param size      if > 0, then create items at least that large (in bytes)
494      * @return created item
495      */
496     std::string createItem(int item, const std::string &revision, int size);
497     std::string createItem(int item, int revision, int size) {
498         char buffer[32];
499         sprintf(buffer, "%d", revision);
500         return createItem(item, std::string(buffer), size);
501     }
502
503     /* for more information on the different tests see their implementation */
504
505     virtual void testOpen();
506     virtual void testIterateTwice();
507     virtual void testSimpleInsert();
508     virtual void testLocalDeleteAll();
509     virtual void testComplexInsert();
510     virtual void testLocalUpdate();
511     virtual void testChanges();
512     virtual void testImport();
513     virtual void testImportDelete();
514     virtual void testManyChanges();
515     virtual void testLinkedItemsParent();
516     virtual void testLinkedItemsChild();
517     virtual void testLinkedItemsParentChild();
518     virtual void testLinkedItemsChildParent();
519     virtual void testLinkedItemsChildChangesParent();
520     virtual void testLinkedItemsRemoveParentFirst();
521     virtual void testLinkedItemsRemoveNormal();
522     virtual void testLinkedItemsInsertParentTwice();
523     virtual void testLinkedItemsInsertChildTwice();
524     virtual void testLinkedItemsParentUpdate();
525     virtual void testLinkedItemsUpdateChild();
526     virtual void testLinkedItemsInsertBothUpdateChild();
527     virtual void testLinkedItemsInsertBothUpdateParent();
528
529 };
530
531 int countItemsOfType(TestingSyncSource *source, int state);
532 std::list<std::string> listItemsOfType(TestingSyncSource *source, int state);
533
534 /**
535  * Tests synchronization with one or more sync sources enabled.
536  * When testing multiple sources at once only the first config
537  * is checked to see which tests can be executed.
538  */
539 class SyncTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
540 public:
541     /** the client we are testing */
542     ClientTest &client;
543
544     SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA = true);
545     ~SyncTests();
546
547     /** adds the supported tests to the instance itself */
548     virtual void addTests();
549
550 protected:
551     /** list with all local test classes for manipulating the sources and their index in the client */
552     typedef std::vector< std::pair<int, LocalTests *> > source_array_t;
553     source_array_t sources;
554     typedef source_array_t::iterator source_it;
555
556     /**
557      * Stack of log file prefixes which are to be appended to the base name,
558      * which already contains the current test name. Add a new prefix by
559      * instantiating SyncPrefix. Its destructor takes care of popping
560      * the prefix.
561      */
562     std::list<std::string> logPrefixes;
563
564     class SyncPrefix {
565         SyncTests &m_tests;
566     public:
567         SyncPrefix(const std::string &prefix, SyncTests &tests) :
568         m_tests(tests) {
569             tests.logPrefixes.push_back(prefix);
570         }
571         ~SyncPrefix() {
572             m_tests.logPrefixes.pop_back();
573         }
574     };
575     friend class SyncPrefix;
576
577     /** the indices from sources, terminated by -1 (for sync()) */
578     int *sourceArray;
579
580     /** utility functions for second client */
581     SyncTests *accessClientB;
582
583     enum DeleteAllMode {
584         DELETE_ALL_SYNC,   /**< make sure client and server are in sync,
585                               delete locally,
586                               sync again */
587         DELETE_ALL_REFRESH /**< delete locally, refresh server */
588     };
589
590     /**
591      * Compare databases second client with either reference file(s)
592      * or first client.  The reference file(s) must follow the naming
593      * scheme <reFileBase><source name>.dat
594      */
595     virtual bool compareDatabases(const char *refFileBase = NULL,
596                                   bool raiseAssert = true);
597
598     /** deletes all items locally and on server */
599     virtual void deleteAll(DeleteAllMode mode = DELETE_ALL_SYNC);
600
601     /** get both clients in sync with empty server, then copy one item from client A to B */
602     virtual void doCopy();
603
604     /**
605      * replicate server database locally: same as SYNC_REFRESH_FROM_SERVER,
606      * but done with explicit local delete and then a SYNC_SLOW because some
607      * servers do no support SYNC_REFRESH_FROM_SERVER
608      */
609     virtual void refreshClient(SyncOptions options = SyncOptions());
610
611     /* for more information on the different tests see their implementation */
612
613     // do a two-way sync without additional checks,
614     // may or may not actually be done in two-way mode
615     virtual void testTwoWaySync() {
616         doSync(SyncOptions(SYNC_TWO_WAY));
617     }
618
619     // do a slow sync without additional checks
620     virtual void testSlowSync() {
621         doSync(SyncOptions(SYNC_SLOW,
622                            CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_SLOW)));
623     }
624     // do a refresh from server sync without additional checks
625     virtual void testRefreshFromServerSync() {
626         doSync(SyncOptions(SYNC_REFRESH_FROM_SERVER,
627                            CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_SERVER)));
628     }
629
630     // do a refresh from client sync without additional checks
631     virtual void testRefreshFromClientSync() {
632         doSync(SyncOptions(SYNC_REFRESH_FROM_CLIENT,
633                            CheckSyncReport(-1,-1,-1, -1,-1,-1, true, SYNC_REFRESH_FROM_CLIENT)));
634     }
635
636     // delete all items, locally and on server using two-way sync
637     virtual void testDeleteAllSync() {
638         deleteAll(DELETE_ALL_SYNC);
639     }
640
641     virtual void testDeleteAllRefresh();
642     virtual void testRefreshFromClientSemantic();
643     virtual void testRefreshFromServerSemantic();
644     virtual void testRefreshStatus();
645
646     // test that a two-way sync copies an item from one address book into the other
647     void testCopy() {
648         doCopy();
649         compareDatabases();
650     }
651
652     virtual void testUpdate();
653     virtual void testComplexUpdate();
654     virtual void testDelete();
655     virtual void testMerge();
656     virtual void testTwinning();
657     virtual void testOneWayFromServer();
658     virtual void testOneWayFromClient();
659     bool doConversionCallback(bool *success,
660                               SyncContext &client,
661                               SyncOptions &options);
662     virtual void testConversion();
663     virtual void testItems();
664     virtual void testItemsXML();
665     virtual void testAddUpdate();
666
667     // test copying with maxMsg and no large object support
668     void testMaxMsg() {
669         doVarSizes(true, false);
670     }
671     // test copying with maxMsg and large object support
672     void testLargeObject() {
673         doVarSizes(true, true);
674     }
675
676     virtual void testManyItems();
677     virtual void testManyDeletes();
678     virtual void testSlowSyncSemantic();
679     virtual void testComplexRefreshFromServerSemantic();
680
681     virtual void doInterruptResume(int changes,
682                   boost::shared_ptr<TransportWrapper> wrapper); 
683     enum {
684         CLIENT_ADD = (1<<0),
685         CLIENT_REMOVE = (1<<1),
686         CLIENT_UPDATE = (1<<2),
687         SERVER_ADD = (1<<3),
688         SERVER_REMOVE = (1<<4),
689         SERVER_UPDATE = (1<<5)
690     };
691     virtual void testInterruptResumeClientAdd();
692     virtual void testInterruptResumeClientRemove();
693     virtual void testInterruptResumeClientUpdate();
694     virtual void testInterruptResumeServerAdd();
695     virtual void testInterruptResumeServerRemove();
696     virtual void testInterruptResumeServerUpdate();
697     virtual void testInterruptResumeFull();
698
699     virtual void testUserSuspendClientAdd();
700     virtual void testUserSuspendClientRemove();
701     virtual void testUserSuspendClientUpdate();
702     virtual void testUserSuspendServerAdd();
703     virtual void testUserSuspendServerRemove();
704     virtual void testUserSuspendServerUpdate();
705     virtual void testUserSuspendFull();
706
707     virtual void testResendClientAdd();
708     virtual void testResendClientRemove();
709     virtual void testResendClientUpdate();
710     virtual void testResendServerAdd();
711     virtual void testResendServerRemove();
712     virtual void testResendServerUpdate();
713     virtual void testResendFull();
714
715     /**
716      * implements testMaxMsg(), testLargeObject(), testLargeObjectEncoded()
717      * using a sequence of items with varying sizes
718      */
719     virtual void doVarSizes(bool withMaxMsgSize,
720                             bool withLargeObject);
721
722     /**
723      * executes a sync with the given options,
724      * checks the result and (optionally) the sync report
725      */
726     virtual void doSync(const SyncOptions &options);
727     virtual void doSync(const char *logPrefix,
728                         const SyncOptions &options) {
729         SyncPrefix prefix(logPrefix, *this);
730         doSync(options);
731     }
732 };
733
734 /*
735  * A transport wraper wraps a real transport impl and gives user 
736  * possibility to do additional work before/after transport operation.
737  * We use TransportFaultInjector to emulate a network failure;
738  * We use UserSuspendInjector to emulate a user suspend after receving
739  * a response.
740  */
741 class TransportWrapper : public TransportAgent {
742 protected:
743     int m_interruptAtMessage, m_messageCount;
744     boost::shared_ptr<TransportAgent> m_wrappedAgent;
745     Status m_status;
746     SyncOptions *m_options;
747 public:
748     TransportWrapper() {
749         m_messageCount = 0;
750         m_interruptAtMessage = -1;
751         m_wrappedAgent = boost::shared_ptr<TransportAgent>();
752         m_status = INACTIVE;
753         m_options = NULL;
754     }
755     ~TransportWrapper() {
756     }
757
758     virtual int getMessageCount() { return m_messageCount; }
759
760     virtual void setURL(const std::string &url) { m_wrappedAgent->setURL(url); }
761     virtual void setContentType(const std::string &type) { m_wrappedAgent->setContentType(type); }
762     virtual void setAgent(boost::shared_ptr<TransportAgent> agent) {m_wrappedAgent = agent;}
763     virtual void setSyncOptions(SyncOptions *options) {m_options = options;}
764     virtual void setInterruptAtMessage (int interrupt) {m_interruptAtMessage = interrupt;}
765     virtual void cancel() { m_wrappedAgent->cancel(); }
766     virtual void shutdown() { m_wrappedAgent->shutdown(); }
767
768     virtual void rewind() {
769         m_messageCount = 0;
770         m_interruptAtMessage = -1;
771         m_status = INACTIVE;
772         m_options = NULL;
773         m_wrappedAgent.reset();
774     }
775     virtual Status wait(bool noReply = false) { return m_status; }
776     virtual void setCallback (TransportCallback cb, void *udata, int interval) 
777     { return m_wrappedAgent->setCallback(cb, udata, interval);}
778 };
779
780 /** assert equality, include string in message if unequal */
781 #define CLIENT_TEST_EQUAL( _prefix, \
782                            _expected, \
783                            _actual ) \
784     CPPUNIT_ASSERT_EQUAL_MESSAGE( std::string(_prefix) + ": " + #_expected + " == " + #_actual, \
785                                   _expected, \
786                                   _actual )
787
788 /** execute _x and then check the status of the _source pointer */
789 #define SOURCE_ASSERT_NO_FAILURE(_source, _x) \
790 { \
791     CPPUNIT_ASSERT_NO_THROW(_x); \
792     CPPUNIT_ASSERT((_source)); \
793 }
794
795 /** check _x for true and then the status of the _source pointer */
796 #define SOURCE_ASSERT(_source, _x) \
797 { \
798     CPPUNIT_ASSERT(_x); \
799     CPPUNIT_ASSERT((_source)); \
800 }
801
802 /** check that _x evaluates to a specific value and then the status of the _source pointer */
803 #define SOURCE_ASSERT_EQUAL(_source, _value, _x) \
804 { \
805     CPPUNIT_ASSERT_EQUAL(_value, _x); \
806     CPPUNIT_ASSERT((_source)); \
807 }
808
809 /** same as SOURCE_ASSERT() with a specific failure message */
810 #define SOURCE_ASSERT_MESSAGE(_message, _source, _x)     \
811 { \
812     CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \
813     CPPUNIT_ASSERT((_source)); \
814 }
815
816 /**
817  * convenience macro for adding a test name like a function,
818  * to be used inside addTests() of an instance of that class
819  *
820  * @param _class      class which contains the function
821  * @param _function   a function without parameters in that class
822  */
823 #define ADD_TEST(_class, _function) \
824     ADD_TEST_TO_SUITE(this, _class, _function)
825
826 #define ADD_TEST_TO_SUITE(_suite, _class, _function) \
827     _suite->addTest(FilterTest(new CppUnit::TestCaller<_class>(_suite->getName() + "::" #_function, &_class::_function, *this)))
828
829 SE_END_CXX
830
831 #endif // ENABLE_INTEGRATION_TESTS
832 #endif // INCL_TESTSYNCCLIENT