00001 /* 00002 * Funambol is a mobile platform developed by Funambol, Inc. 00003 * Copyright (C) 2003 - 2007 Funambol, Inc. 00004 * 00005 * This program is free software; you can redistribute it and/or modify it under 00006 * the terms of the GNU Affero General Public License version 3 as published by 00007 * the Free Software Foundation with the addition of the following permission 00008 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED 00009 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 00010 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 00011 * 00012 * This program is distributed in the hope that it will be useful, but WITHOUT 00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00014 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 00015 * details. 00016 * 00017 * You should have received a copy of the GNU Affero General Public License 00018 * along with this program; if not, see http://www.gnu.org/licenses or write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00020 * MA 02110-1301 USA. 00021 * 00022 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 00023 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. 00024 * 00025 * The interactive user interfaces in modified source and object code versions 00026 * of this program must display Appropriate Legal Notices, as required under 00027 * Section 5 of the GNU Affero General Public License version 3. 00028 * 00029 * In accordance with Section 7(b) of the GNU Affero General Public License 00030 * version 3, these Appropriate Legal Notices must retain the display of the 00031 * "Powered by Funambol" logo. If the display of the logo is not reasonably 00032 * feasible for technical reasons, the Appropriate Legal Notices must display 00033 * the words "Powered by Funambol". 00034 */ 00035 00036 #ifndef INCL_TESTSYNCCLIENT 00037 #define INCL_TESTSYNCCLIENT 00038 /** @cond API */ 00039 /** @addtogroup Client */ 00040 /** @{ */ 00041 00042 #include <string> 00043 #include <vector> 00044 #include <list> 00045 #include "spds/SyncSource.h" 00046 #include "spds/SyncReport.h" 00047 00048 #ifdef ENABLE_INTEGRATION_TESTS 00049 00050 #include <cppunit/TestSuite.h> 00051 #include <cppunit/TestAssert.h> 00052 #include <cppunit/TestFixture.h> 00053 #include "base/globalsdef.h" 00054 00055 BEGIN_NAMESPACE 00056 00057 /** 00058 * This class encapsulates logging and checking of a SyncReport. 00059 * When constructed with default parameters, no checking will be done. 00060 * Otherwise the sync report has to contain exactly the expected result. 00061 * When multiple sync sources are active, @b all of them have to behave 00062 * alike (which is how the tests are constructed). 00063 * 00064 * No item is ever supposed to fail. 00065 */ 00066 class CheckSyncReport { 00067 public: 00068 CheckSyncReport(int clAdded = -1, int clUpdated = -1, int clDeleted = -1, 00069 int srAdded = -1, int srUpdated = -1, int srDeleted = -1) : 00070 clientAdded(clAdded), 00071 clientUpdated(clUpdated), 00072 clientDeleted(clDeleted), 00073 serverAdded(srAdded), 00074 serverUpdated(srUpdated), 00075 serverDeleted(srDeleted) 00076 {} 00077 00078 virtual ~CheckSyncReport() {} 00079 00080 const int clientAdded, clientUpdated, clientDeleted, 00081 serverAdded, serverUpdated, serverDeleted; 00082 00083 /** 00084 * checks that the sync completed as expected and throws 00085 * CPPUnit exceptions if something is wrong 00086 * 00087 * @param res return code from SyncClient::sync() 00088 * @param report the sync report stored in the SyncClient 00089 */ 00090 virtual void check(int res, SyncReport &report) const; 00091 }; 00092 00093 class LocalTests; 00094 class SyncTests; 00095 00096 /** 00097 * This is the interface expected by the testing framework for sync 00098 * clients. It defines several methods that a derived class must 00099 * implement if it wants to use that framework. Note that this class 00100 * itself is not derived from SyncClient. This gives a user of this 00101 * framework the freedom to implement it in two different ways: 00102 * - implement a class derived from both SyncClient and ClientTest 00103 * - add testing of an existing subclass of SyncClient by implementing 00104 * a ClientTest which uses that subclass 00105 * 00106 * The client is expected to support change tracking for multiple 00107 * servers. Although the framework always always tests against the 00108 * same server, for most tests it is necessary to access the database 00109 * without affecting the next synchronization with the server. This is 00110 * done by asking the client for two different sync sources via 00111 * Config::createSourceA and Config::createSourceB which have to 00112 * create them in a suitable way - pretty much as if the client was 00113 * synchronized against different server. A third, different change 00114 * tracking is needed for real synchronizations of the data. 00115 * 00116 * Furthermore the client is expected to support multiple data sources 00117 * of the same kind, f.i. two different address books. This is used to 00118 * test full client A <-> server <-> client B synchronizations in some 00119 * tests or to check server modifications done by client A with a 00120 * synchronization against client B. In those tests client A is mapped 00121 * to the first data source and client B to the second one. 00122 * 00123 * Finally the SyncSource API is used in slightly different ways which 00124 * go beyond what is normally expected from a SyncSource implementation: 00125 * - beginSync() may be called without setting a sync mode: 00126 * when SyncSource::getSyncMode() returns SYNC_NONE the source is 00127 * expected to make itself ready to iterate over all, new, updated and 00128 * deleted items 00129 * - items may be added via SyncSource::addItem() with a type of "raw": 00130 * this implies that the type is the one used for items in the 00131 * ClientTest::Config below 00132 * 00133 * Handling configuration and creating classes is entirely done by the 00134 * subclass of ClientTest, the frameworks makes no assumptions 00135 * about how this is done. Instead it queries the ClientTest for 00136 * properties (like available sync sources) and then creates several 00137 * tests. 00138 */ 00139 class ClientTest { 00140 public: 00141 ClientTest(int serverSleepSec = 0, const std::string &serverLog= ""); 00142 virtual ~ClientTest(); 00143 00144 /** 00145 * This function registers tests using this instance of ClientTest for 00146 * later use during a test run. 00147 * 00148 * The instance must remain valid until after the tests were 00149 * run. To run them use a separate test runner, like the one from 00150 * client-test-main.cpp. 00151 */ 00152 virtual void registerTests(); 00153 00154 struct Config; 00155 00156 /** 00157 * Creates an instance of LocalTests (default implementation) or a 00158 * class derived from it. LocalTests provides tests which cover 00159 * the SyncSource interface and can be executed without a SyncML 00160 * server. It also contains utility functions for working with 00161 * SyncSources. 00162 * 00163 * A ClientTest implementation can, but doesn't have to extend 00164 * these tests by instantiating a derived class here. 00165 */ 00166 virtual LocalTests *createLocalTests(const std::string &name, int sourceParam, ClientTest::Config &co); 00167 00168 /** 00169 * Creates an instance of SyncTests (default) or a class derived 00170 * from it. SyncTests provides tests which cover the actual 00171 * interaction with a SyncML server. 00172 * 00173 * A ClientTest implementation can, but doesn't have to extend 00174 * these tests by instantiating a derived class here. 00175 */ 00176 virtual SyncTests *createSyncTests(const std::string &name, std::vector<int> sourceIndices, bool isClientA = true); 00177 00178 /** 00179 * utility function for dumping items which are C strings with blank lines as separator 00180 */ 00181 static int dump(ClientTest &client, SyncSource &source, const char *file); 00182 00183 /** 00184 * utility function for importing items with blank lines as separator 00185 */ 00186 static int import(ClientTest &client, SyncSource &source, const char *file); 00187 00188 /** 00189 * utility function for comparing vCard and iCal files with the external 00190 * synccompare.pl Perl script 00191 */ 00192 static bool compare(ClientTest &client, const char *fileA, const char *fileB); 00193 00194 /** 00195 * A derived class can use this call to get default test 00196 * cases, but still has to add callbacks which create sources 00197 * and execute a sync session. 00198 * 00199 * Some of the test cases are compiled into the library, other 00200 * depend on the auxiliary files from the "test" directory. 00201 * Currently supported types: 00202 * - vcard30 = vCard 3.0 contacts 00203 * - vcard21 = vCard 2.1 contacts 00204 * - ical20 = iCal 2.0 events 00205 * - vcal10 = vCal 1.0 events 00206 * - itodo20 = iCal 2.0 tasks 00207 */ 00208 static void getTestData(const char *type, Config &config); 00209 00210 /** 00211 * Information about a data source. For the sake of simplicity all 00212 * items pointed to are owned by the ClientTest and must 00213 * remain valid throughout a test session. Not setting a pointer 00214 * is okay, but it will disable all tests that need the 00215 * information. 00216 */ 00217 struct Config { 00218 /** 00219 * The name is used in test names and has to be set. 00220 */ 00221 const char *sourceName; 00222 00223 /** 00224 * A default URI to be used when creating a client config. 00225 */ 00226 const char *uri; 00227 00228 /** 00229 * A member function of a subclass which is called to create a 00230 * sync source referencing the data. This is used in tests of 00231 * the SyncSource API itself as well as in tests which need to 00232 * modify or check the data sources used during synchronization. 00233 * 00234 * The test framework will call beginSync() and then some of 00235 * the functions it wants to test. After a successful test it 00236 * will call endSync() which is then expected to store all 00237 * changes persistently. Creating a sync source again 00238 * with the same call should not report any 00239 * new/updated/deleted items until such changes are made via 00240 * another sync source. 00241 * 00242 * The instance will be deleted by the caller. Because this 00243 * may be in the error case or in an exception handler, 00244 * the sync source's desctructor should not thow exceptions. 00245 * 00246 * @param client the same instance to which this config belongs 00247 * @param source index of the data source (from 0 to ClientTest::getNumSources() - 1) 00248 * @param isSourceA true if the requested SyncSource is the first one accessing that 00249 * data, otherwise the second 00250 */ 00251 typedef SyncSource *(*createsource_t)(ClientTest &client, int source, bool isSourceA); 00252 00253 /** 00254 * Creates a sync source which references the primary database; 00255 * it may report the same changes as the sync source used during 00256 * sync tests. 00257 */ 00258 createsource_t createSourceA; 00259 00260 /** 00261 * A second sync source also referencing the primary data 00262 * source, but configured so that it tracks changes 00263 * independently from the the primary sync source. 00264 * 00265 * In local tests the usage is like this: 00266 * - add item via first SyncSource 00267 * - iterate over new items in second SyncSource 00268 * - check that it lists the added item 00269 * 00270 * In tests with a server the usage is: 00271 * - do a synchronization with the server 00272 * - iterate over items in second SyncSource 00273 * - check that the total number and number of 00274 * added/updated/deleted items is as expected 00275 */ 00276 createsource_t createSourceB; 00277 00278 /** 00279 * The framework can generate vCard and vCalendar/iCalendar items 00280 * automatically by copying a template item and modifying certain 00281 * properties. 00282 * 00283 * This is the template for these automatically generated items. 00284 */ 00285 const char *templateItem; 00286 00287 /** 00288 * This is a colon (:) separated list of properties which need 00289 * to be modified in templateItem. 00290 */ 00291 const char *uniqueProperties; 00292 00293 /** 00294 * the number of items to create during stress tests 00295 */ 00296 int numItems; 00297 00298 /** 00299 * This is a single property in templateItem which can be extended 00300 * to increase the size of generated items. 00301 */ 00302 const char *sizeProperty; 00303 00304 /** 00305 * A very simple item that is inserted during basic tests. Ideally 00306 * it only contains properties supported by all servers. 00307 */ 00308 const char *insertItem; 00309 00310 /** 00311 * A slightly modified version of insertItem. If the source has UIDs 00312 * embedded into the item data, then both must have the same UID. 00313 * Again all servers should better support these modified properties. 00314 */ 00315 const char *updateItem; 00316 00317 /** 00318 * A more heavily modified version of insertItem. Same UID if necessary, 00319 * but can test changes to items only supported by more advanced 00320 * servers. 00321 */ 00322 const char *complexUpdateItem; 00323 00324 /** 00325 * To test merge conflicts two different updates of insertItem are 00326 * needed. This is the first such update. 00327 */ 00328 const char *mergeItem1; 00329 00330 /** 00331 * The second merge update item. To avoid true conflicts it should 00332 * update different properties than mergeItem1, but even then servers 00333 * usually have problems perfectly merging items. Therefore the 00334 * test is run without expecting a certain merge result. 00335 */ 00336 const char *mergeItem2; 00337 00338 /** 00339 * These two items are related: one is main one, the other is 00340 * a subordinate one. The semantic is that the main item is 00341 * complete on it its own, while the other normally should only 00342 * be used in combination with the main one. 00343 * 00344 * Because SyncML cannot express such dependencies between items, 00345 * a SyncSource has to be able to insert, updated and remove 00346 * both items independently. However, operations which violate 00347 * the semantic of the related items (like deleting the parent, but 00348 * not the child) may have unspecified results (like also deleting 00349 * the child). See LINKED_ITEMS_RELAXED_SEMANTIC. 00350 * 00351 * One example for main and subordinate items are a recurring 00352 * iCalendar 2.0 event and a detached recurrence. 00353 */ 00354 const char *parentItem, *childItem; 00355 00356 /** 00357 * define to 0 to disable tests which slightly violate the 00358 * semantic of linked items by inserting children 00359 * before/without their parent 00360 */ 00361 #ifndef LINKED_ITEMS_RELAXED_SEMANTIC 00362 # define LINKED_ITEMS_RELAXED_SEMANTIC 1 00363 #endif 00364 00365 /** 00366 * called to dump all items into a file, required by tests which need 00367 * to compare items 00368 * 00369 * ClientTest::dump can be used: it will simply dump all items of the source 00370 * with a blank line as separator. 00371 * 00372 * @param source sync source A already created and with beginSync() called 00373 * @param file a file name 00374 * @return error code, 0 for success 00375 */ 00376 int (*dump)(ClientTest &client, SyncSource &source, const char *file); 00377 00378 /** 00379 * import test items: which these are is determined entirely by 00380 * the implementor, but tests work best if several complex items are 00381 * imported 00382 * 00383 * ClientTest::import can be used if the file contains items separated by 00384 * empty lines. 00385 * 00386 * @param source sync source A already created and with beginSync() called 00387 * @param file the name of the file to import 00388 * @return error code, 0 for success 00389 */ 00390 int (*import)(ClientTest &client, SyncSource &source, const char *file); 00391 00392 /** 00393 * a function which compares two files with items in the format used by "dump" 00394 * 00395 * @param fileA first file name 00396 * @param fileB second file name 00397 * @return true if the content of the files is considered equal 00398 */ 00399 bool (*compare)(ClientTest &client, const char *fileA, const char *fileB); 00400 00401 /** 00402 * a file with test cases in the format expected by import and compare 00403 */ 00404 const char *testcases; 00405 00406 /** 00407 * the item type normally used by the source (not used by the tests 00408 * themselves; client-test.cpp uses it to initialize source configs) 00409 */ 00410 const char *type; 00411 }; 00412 00413 /** 00414 * Data sources are enumbered from 0 to n-1 for the purpose of 00415 * testing. This call returns n. 00416 */ 00417 virtual int getNumSources() = 0; 00418 00419 /** 00420 * Called to fill the given test source config with information 00421 * about a sync source identified by its index. It's okay to only 00422 * fill in the available pieces of information and set everything 00423 * else to zero. 00424 */ 00425 virtual void getSourceConfig(int source, Config &config) = 0; 00426 00427 /** 00428 * The instance to use as second client. Returning NULL disables 00429 * all checks which require a second client. The returned pointer 00430 * must remain valid throughout the life time of the tests. 00431 * 00432 * The second client must be configured to access the same server 00433 * and have data sources which match the ones from the primary 00434 * client. 00435 */ 00436 virtual ClientTest *getClientB() = 0; 00437 00438 /** 00439 * Returning true enables tests which only work if the server is 00440 * a Funambol server which supports the "b64" encoding of items 00441 * on the transport level. 00442 */ 00443 virtual bool isB64Enabled() = 0; 00444 00445 /** 00446 * Execute a synchronization with the selected sync sources 00447 * and the selected synchronization options. The log file 00448 * in LOG has been set up already for the synchronization run 00449 * and should not be changed by the client. 00450 * 00451 * @param activeSources a -1 terminated array of sync source indices 00452 * @param syncMode the synchronization mode to be used 00453 * @param checkReport has to be called after a successful or unsuccessful sync, 00454 * will dump the report and (optionally) check the result; 00455 * beware, the later may throw exceptions inside CPPUNIT macros 00456 * @param maxMsgSize >0: enable the maximum message size, else disable it 00457 * @param maxObjSize same as maxMsgSize for maximum object size 00458 * @param loSupport if true, then the sync is expected to enable Large Object support 00459 * @param encoding if non-empty, then let client library transform all items 00460 * into this format (guaranteed to be not NULL) 00461 * 00462 * @return return code of SyncClient::sync() 00463 */ 00464 virtual int sync( 00465 const int *activeSources, 00466 SyncMode syncMode, 00467 const CheckSyncReport &checkReport, 00468 long maxMsgSize = 0, 00469 long maxObjSize = 0, 00470 bool loSupport = false, 00471 const char *encoding = "") = 0; 00472 00473 /** 00474 * This is called after successful sync() calls (res == 0) as well 00475 * as after unsuccessful ones (res != 1). The default implementation 00476 * sleeps for the number of seconds specified when constructing this 00477 * instance and copies the server log if one was named. 00478 * 00479 * @param res result of sync() 00480 * @param logname base name of the current sync log (without ".client.[AB].log" suffix) 00481 */ 00482 virtual void postSync(int res, const std::string &logname); 00483 00484 protected: 00485 /** 00486 * time to sleep in postSync() 00487 */ 00488 int serverSleepSeconds; 00489 00490 /** 00491 * server log file which is copied by postSync() and then 00492 * truncated (Unix only, Windows does not allow such access 00493 * to an open file) 00494 */ 00495 std::string serverLogFileName; 00496 00497 private: 00498 /** 00499 * really a CppUnit::TestFactory, but declared as void * to avoid 00500 * dependencies on the CPPUnit header files: created by 00501 * registerTests() and remains valid until the client is deleted 00502 */ 00503 void *factory; 00504 }; 00505 00506 /** 00507 * helper class to encapsulate ClientTest::Config::createsource_t 00508 * pointer and the corresponding parameters 00509 */ 00510 class CreateSource { 00511 public: 00512 CreateSource(ClientTest::Config::createsource_t createSourceParam, ClientTest &clientParam, int sourceParam, bool isSourceAParam) : 00513 createSource(createSourceParam), 00514 client(clientParam), 00515 source(sourceParam), 00516 isSourceA(isSourceAParam) {} 00517 00518 SyncSource *operator() () { 00519 CPPUNIT_ASSERT(createSource); 00520 return createSource(client, source, isSourceA); 00521 } 00522 00523 const ClientTest::Config::createsource_t createSource; 00524 ClientTest &client; 00525 const int source; 00526 const bool isSourceA; 00527 }; 00528 00529 00530 /** 00531 * local test of one sync source and utility functions also used by 00532 * sync tests 00533 */ 00534 class LocalTests : public CppUnit::TestSuite, public CppUnit::TestFixture { 00535 public: 00536 /** the client we are testing */ 00537 ClientTest &client; 00538 00539 /** number of the source we are testing in that client */ 00540 const int source; 00541 00542 /** configuration that corresponds to source */ 00543 const ClientTest::Config config; 00544 00545 /** helper funclets to create sources */ 00546 CreateSource createSourceA, createSourceB; 00547 00548 LocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) : 00549 CppUnit::TestSuite(name), 00550 client(cl), 00551 source(sourceParam), 00552 config(co), 00553 createSourceA(co.createSourceA, cl, sourceParam, true), 00554 createSourceB(co.createSourceB, cl, sourceParam, false) 00555 {} 00556 00557 /** 00558 * adds the supported tests to the instance itself; 00559 * this is the function that a derived class can override 00560 * to add additional tests 00561 */ 00562 virtual void addTests(); 00563 00564 /** 00565 * opens source and inserts the given item; can be called 00566 * regardless whether the data source already contains items or not 00567 * 00568 * The type of the item is unset; it is assumed that the source 00569 * can handle that. 00570 * 00571 * @param relaxed if true, then disable some of the additional checks after adding the item 00572 * @return the UID of the inserted item 00573 */ 00574 virtual std::string insert(CreateSource createSource, const char *data, bool relaxed = false); 00575 00576 /** 00577 * assumes that exactly one element is currently inserted and updates it with the given item 00578 * 00579 * The type of the item is cleared, as in insert() above. 00580 * 00581 * @param check if true, then reopen the source and verify that the reported items are as expected 00582 */ 00583 virtual void update(CreateSource createSource, const char *data, bool check = true); 00584 00585 /** deletes all items locally via sync source */ 00586 virtual void deleteAll(CreateSource createSource); 00587 00588 /** 00589 * takes two databases, exports them, 00590 * then compares them using synccompare 00591 * 00592 * @param refFile existing file with source reference items, NULL uses a dump of sync source A instead 00593 * @param copy a sync source which contains the copied items, begin/endSync will be called 00594 * @param raiseAssert raise assertion if comparison yields differences (defaults to true) 00595 */ 00596 virtual void compareDatabases(const char *refFile, SyncSource ©, bool raiseAssert = true); 00597 00598 /** 00599 * insert artificial items, number of them determined by TEST_EVOLUTION_NUM_ITEMS 00600 * unless passed explicitly 00601 * 00602 * @param createSource a factory for the sync source that is to be used 00603 * @param startIndex IDs are generated starting with this value 00604 * @param numItems number of items to be inserted if non-null, otherwise TEST_EVOLUTION_NUM_ITEMS is used 00605 * @param size minimum size for new items 00606 * @return number of items inserted 00607 */ 00608 virtual int insertManyItems(CreateSource createSource, int startIndex = 1, int numItems = 0, int size = -1); 00609 00610 00611 /* for more information on the different tests see their implementation */ 00612 00613 virtual void testOpen(); 00614 virtual void testIterateTwice(); 00615 virtual void testSimpleInsert(); 00616 virtual void testLocalDeleteAll(); 00617 virtual void testComplexInsert(); 00618 virtual void testLocalUpdate(); 00619 virtual void testChanges(); 00620 virtual void testImport(); 00621 virtual void testImportDelete(); 00622 virtual void testManyChanges(); 00623 virtual void testLinkedItemsParent(); 00624 virtual void testLinkedItemsChild(); 00625 virtual void testLinkedItemsParentChild(); 00626 virtual void testLinkedItemsChildParent(); 00627 virtual void testLinkedItemsChildChangesParent(); 00628 virtual void testLinkedItemsRemoveParentFirst(); 00629 virtual void testLinkedItemsRemoveNormal(); 00630 virtual void testLinkedItemsInsertParentTwice(); 00631 virtual void testLinkedItemsInsertChildTwice(); 00632 virtual void testLinkedItemsParentUpdate(); 00633 virtual void testLinkedItemsUpdateChild(); 00634 virtual void testLinkedItemsInsertBothUpdateChild(); 00635 virtual void testLinkedItemsInsertBothUpdateParent(); 00636 00637 }; 00638 00639 enum itemType { 00640 NEW_ITEMS, 00641 UPDATED_ITEMS, 00642 DELETED_ITEMS, 00643 TOTAL_ITEMS 00644 }; 00645 00646 /** 00647 * utility function which counts items of a certain kind known to the sync source 00648 * @param source valid source ready to iterate; NULL triggers an assert 00649 * @param itemType determines which iterator functions are used 00650 * @return number of valid items iterated over 00651 */ 00652 int countItemsOfType(SyncSource *source, itemType type); 00653 00654 typedef std::list<std::string> UIDList; 00655 /** 00656 * generates list of UIDs in the specified kind of items 00657 */ 00658 UIDList listItemsOfType(SyncSource *source, itemType type); 00659 00660 /** 00661 * Tests synchronization with one or more sync sources enabled. 00662 * When testing multiple sources at once only the first config 00663 * is checked to see which tests can be executed. 00664 */ 00665 class SyncTests : public CppUnit::TestSuite, public CppUnit::TestFixture { 00666 public: 00667 /** the client we are testing */ 00668 ClientTest &client; 00669 00670 SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA = true); 00671 ~SyncTests(); 00672 00673 /** adds the supported tests to the instance itself */ 00674 virtual void addTests(); 00675 00676 protected: 00677 /** list with all local test classes for manipulating the sources and their index in the client */ 00678 std::vector< std::pair<int, LocalTests *> > sources; 00679 typedef std::vector< std::pair<int, LocalTests *> >::iterator source_it; 00680 00681 /** the indices from sources, terminated by -1 (for sync()) */ 00682 int *sourceArray; 00683 00684 /** utility functions for second client */ 00685 SyncTests *accessClientB; 00686 00687 enum DeleteAllMode { 00688 DELETE_ALL_SYNC, /**< make sure client and server are in sync, 00689 delete locally, 00690 sync again */ 00691 DELETE_ALL_REFRESH /**< delete locally, refresh server */ 00692 }; 00693 00694 /** compare databases of first and second client */ 00695 virtual void compareDatabases(); 00696 00697 /** deletes all items locally and on server */ 00698 virtual void deleteAll(DeleteAllMode mode = DELETE_ALL_SYNC); 00699 00700 /** get both clients in sync with empty server, then copy one item from client A to B */ 00701 virtual void doCopy(); 00702 00703 /** 00704 * replicate server database locally: same as SYNC_REFRESH_FROM_SERVER, 00705 * but done with explicit local delete and then a SYNC_SLOW because some 00706 * servers do no support SYNC_REFRESH_FROM_SERVER 00707 */ 00708 virtual void refreshClient(); 00709 00710 /* for more information on the different tests see their implementation */ 00711 00712 // do a two-way sync without additional checks 00713 virtual void testTwoWaySync() { 00714 sync(SYNC_TWO_WAY); 00715 } 00716 00717 // do a slow sync without additional checks 00718 virtual void testSlowSync() { 00719 sync(SYNC_SLOW); 00720 } 00721 // do a refresh from server sync without additional checks 00722 virtual void testRefreshFromServerSync() { 00723 sync(SYNC_REFRESH_FROM_SERVER); 00724 } 00725 00726 // do a refresh from client sync without additional checks 00727 virtual void testRefreshFromClientSync() { 00728 sync(SYNC_REFRESH_FROM_CLIENT); 00729 } 00730 00731 // delete all items, locally and on server using two-way sync 00732 virtual void testDeleteAllSync() { 00733 deleteAll(DELETE_ALL_SYNC); 00734 } 00735 00736 virtual void testDeleteAllRefresh(); 00737 virtual void testRefreshSemantic(); 00738 virtual void testRefreshStatus(); 00739 00740 // test that a two-way sync copies an item from one address book into the other 00741 void testCopy() { 00742 doCopy(); 00743 compareDatabases(); 00744 } 00745 00746 virtual void testUpdate(); 00747 virtual void testComplexUpdate(); 00748 virtual void testDelete(); 00749 virtual void testMerge(); 00750 virtual void testTwinning(); 00751 virtual void testOneWayFromServer(); 00752 virtual void testOneWayFromClient(); 00753 virtual void testItems(); 00754 virtual void testAddUpdate(); 00755 00756 // test copying with maxMsg and no large object support 00757 void testMaxMsg() { 00758 doVarSizes(true, false, NULL); 00759 } 00760 // test copying with maxMsg and large object support 00761 void testLargeObject() { 00762 doVarSizes(true, true, NULL); 00763 } 00764 // test copying with maxMsg and large object support using explicit "bin" encoding 00765 void testLargeObjectBin() { 00766 doVarSizes(true, true, "bin"); 00767 } 00768 // test copying with maxMsg and large object support using B64 encoding 00769 void testLargeObjectEncoded() { 00770 doVarSizes(true, true, "b64"); 00771 } 00772 00773 virtual void testManyItems(); 00774 00775 00776 /** 00777 * implements testMaxMsg(), testLargeObject(), testLargeObjectEncoded() 00778 * using a sequence of items with varying sizes 00779 */ 00780 virtual void doVarSizes(bool withMaxMsgSize, 00781 bool withLargeObject, 00782 const char *encoding); 00783 00784 /** 00785 * executes a sync with the given options, 00786 * checks the result and (optionally) the sync report 00787 */ 00788 virtual void sync(SyncMode syncMode, 00789 const std::string &logprefix = "", 00790 CheckSyncReport checkReport = CheckSyncReport(), 00791 long maxMsgSize = 0, 00792 long maxObjSize = 0, 00793 bool loSupport = false, 00794 const char *encoding = ""); 00795 }; 00796 00797 00798 /** assert equality, include string in message if unequal */ 00799 #define CLIENT_TEST_EQUAL( _prefix, \ 00800 _expected, \ 00801 _actual ) \ 00802 CPPUNIT_ASSERT_EQUAL_MESSAGE( std::string(_prefix) + ": " + #_expected + " == " + #_actual, \ 00803 _expected, \ 00804 _actual ) 00805 00806 /** execute _x and then check the status of the _source pointer */ 00807 #define SOURCE_ASSERT_NO_FAILURE(_source, _x) \ 00808 { \ 00809 CPPUNIT_ASSERT_NO_THROW(_x); \ 00810 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00811 } 00812 00813 /** check _x for true and then the status of the _source pointer */ 00814 #define SOURCE_ASSERT(_source, _x) \ 00815 { \ 00816 CPPUNIT_ASSERT(_x); \ 00817 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00818 } 00819 00820 /** check that _x evaluates to a specific value and then the status of the _source pointer */ 00821 #define SOURCE_ASSERT_EQUAL(_source, _value, _x) \ 00822 { \ 00823 CPPUNIT_ASSERT_EQUAL(_value, _x); \ 00824 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00825 } 00826 00827 /** same as SOURCE_ASSERT() with a specific failure message */ 00828 #define SOURCE_ASSERT_MESSAGE(_message, _source, _x) \ 00829 { \ 00830 CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \ 00831 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00832 } 00833 00834 00835 /** 00836 * convenience macro for adding a test name like a function, 00837 * to be used inside addTests() of an instance of that class 00838 * 00839 * @param _class class which contains the function 00840 * @param _function a function without parameters in that class 00841 */ 00842 #define ADD_TEST(_class, _function) \ 00843 addTest(new CppUnit::TestCaller<_class>(getName() + "::" #_function, &_class::_function, *this)) 00844 00845 00846 #endif // ENABLE_INTEGRATION_TESTS 00847 00848 00849 END_NAMESPACE 00850 00851 /** @} */ 00852 /** @endcond */ 00853 #endif // INCL_TESTSYNCCLIENT