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 * The updated items are needed in same tests; they should differ 00355 * from the normal ones in some relevant properties. 00356 */ 00357 const char *parentItem, *childItem, *parentItemUpdate, *childItemUpdate; 00358 00359 /** 00360 * define to 0 to disable tests which slightly violate the 00361 * semantic of linked items by inserting children 00362 * before/without their parent 00363 */ 00364 #ifndef LINKED_ITEMS_RELAXED_SEMANTIC 00365 # define LINKED_ITEMS_RELAXED_SEMANTIC 1 00366 #endif 00367 00368 /** 00369 * Overwrite the default 'true' with 'false' to disable 00370 * tests which assume that the source being tested 00371 * follows certain conventions for the items being exchanged. 00372 * 00373 * For example, testLinkedItemsInsertParentTwice inserts a 00374 * calendar event twice and expects that the source only keeps 00375 * one event because the UID has to be kept unique. A dumb 00376 * file sync source doesn't know that and would keep two copies 00377 * of the same event. 00378 */ 00379 bool sourceKnowsItemSemantic; 00380 00381 /** 00382 * called to dump all items into a file, required by tests which need 00383 * to compare items 00384 * 00385 * ClientTest::dump can be used: it will simply dump all items of the source 00386 * with a blank line as separator. 00387 * 00388 * @param source sync source A already created and with beginSync() called 00389 * @param file a file name 00390 * @return error code, 0 for success 00391 */ 00392 int (*dump)(ClientTest &client, SyncSource &source, const char *file); 00393 00394 /** 00395 * import test items: which these are is determined entirely by 00396 * the implementor, but tests work best if several complex items are 00397 * imported 00398 * 00399 * ClientTest::import can be used if the file contains items separated by 00400 * empty lines. 00401 * 00402 * @param source sync source A already created and with beginSync() called 00403 * @param file the name of the file to import 00404 * @return error code, 0 for success 00405 */ 00406 int (*import)(ClientTest &client, SyncSource &source, const char *file); 00407 00408 /** 00409 * a function which compares two files with items in the format used by "dump" 00410 * 00411 * @param fileA first file name 00412 * @param fileB second file name 00413 * @return true if the content of the files is considered equal 00414 */ 00415 bool (*compare)(ClientTest &client, const char *fileA, const char *fileB); 00416 00417 /** 00418 * a file with test cases in the format expected by import and compare 00419 */ 00420 const char *testcases; 00421 00422 /** 00423 * the item type normally used by the source (not used by the tests 00424 * themselves; client-test.cpp uses it to initialize source configs) 00425 */ 00426 const char *type; 00427 }; 00428 00429 /** 00430 * Data sources are enumbered from 0 to n-1 for the purpose of 00431 * testing. This call returns n. 00432 */ 00433 virtual int getNumSources() = 0; 00434 00435 /** 00436 * Called to fill the given test source config with information 00437 * about a sync source identified by its index. It's okay to only 00438 * fill in the available pieces of information and set everything 00439 * else to zero. 00440 */ 00441 virtual void getSourceConfig(int source, Config &config) = 0; 00442 00443 /** 00444 * The instance to use as second client. Returning NULL disables 00445 * all checks which require a second client. The returned pointer 00446 * must remain valid throughout the life time of the tests. 00447 * 00448 * The second client must be configured to access the same server 00449 * and have data sources which match the ones from the primary 00450 * client. 00451 */ 00452 virtual ClientTest *getClientB() = 0; 00453 00454 /** 00455 * Returning true enables tests which only work if the server is 00456 * a Funambol server which supports the "b64" encoding of items 00457 * on the transport level. 00458 */ 00459 virtual bool isB64Enabled() = 0; 00460 00461 /** 00462 * Execute a synchronization with the selected sync sources 00463 * and the selected synchronization options. The log file 00464 * in LOG has been set up already for the synchronization run 00465 * and should not be changed by the client. 00466 * 00467 * @param activeSources a -1 terminated array of sync source indices 00468 * @param syncMode the synchronization mode to be used 00469 * @param checkReport has to be called after a successful or unsuccessful sync, 00470 * will dump the report and (optionally) check the result; 00471 * beware, the later may throw exceptions inside CPPUNIT macros 00472 * @param maxMsgSize >0: enable the maximum message size, else disable it 00473 * @param maxObjSize same as maxMsgSize for maximum object size 00474 * @param loSupport if true, then the sync is expected to enable Large Object support 00475 * @param encoding if non-empty, then let client library transform all items 00476 * into this format (guaranteed to be not NULL) 00477 * 00478 * @return return code of SyncClient::sync() 00479 */ 00480 virtual int sync( 00481 const int *activeSources, 00482 SyncMode syncMode, 00483 const CheckSyncReport &checkReport, 00484 long maxMsgSize = 0, 00485 long maxObjSize = 0, 00486 bool loSupport = false, 00487 const char *encoding = "") = 0; 00488 00489 /** 00490 * This is called after successful sync() calls (res == 0) as well 00491 * as after unsuccessful ones (res != 1). The default implementation 00492 * sleeps for the number of seconds specified when constructing this 00493 * instance and copies the server log if one was named. 00494 * 00495 * @param res result of sync() 00496 * @param logname base name of the current sync log (without ".client.[AB].log" suffix) 00497 */ 00498 virtual void postSync(int res, const std::string &logname); 00499 00500 protected: 00501 /** 00502 * time to sleep in postSync() 00503 */ 00504 int serverSleepSeconds; 00505 00506 /** 00507 * server log file which is copied by postSync() and then 00508 * truncated (Unix only, Windows does not allow such access 00509 * to an open file) 00510 */ 00511 std::string serverLogFileName; 00512 00513 private: 00514 /** 00515 * really a CppUnit::TestFactory, but declared as void * to avoid 00516 * dependencies on the CPPUnit header files: created by 00517 * registerTests() and remains valid until the client is deleted 00518 */ 00519 void *factory; 00520 }; 00521 00522 /** 00523 * helper class to encapsulate ClientTest::Config::createsource_t 00524 * pointer and the corresponding parameters 00525 */ 00526 class CreateSource { 00527 public: 00528 CreateSource(ClientTest::Config::createsource_t createSourceParam, ClientTest &clientParam, int sourceParam, bool isSourceAParam) : 00529 createSource(createSourceParam), 00530 client(clientParam), 00531 source(sourceParam), 00532 isSourceA(isSourceAParam) {} 00533 00534 SyncSource *operator() () { 00535 CPPUNIT_ASSERT(createSource); 00536 return createSource(client, source, isSourceA); 00537 } 00538 00539 const ClientTest::Config::createsource_t createSource; 00540 ClientTest &client; 00541 const int source; 00542 const bool isSourceA; 00543 }; 00544 00545 00546 /** 00547 * local test of one sync source and utility functions also used by 00548 * sync tests 00549 */ 00550 class LocalTests : public CppUnit::TestSuite, public CppUnit::TestFixture { 00551 public: 00552 /** the client we are testing */ 00553 ClientTest &client; 00554 00555 /** number of the source we are testing in that client */ 00556 const int source; 00557 00558 /** configuration that corresponds to source */ 00559 const ClientTest::Config config; 00560 00561 /** helper funclets to create sources */ 00562 CreateSource createSourceA, createSourceB; 00563 00564 LocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) : 00565 CppUnit::TestSuite(name), 00566 client(cl), 00567 source(sourceParam), 00568 config(co), 00569 createSourceA(co.createSourceA, cl, sourceParam, true), 00570 createSourceB(co.createSourceB, cl, sourceParam, false) 00571 {} 00572 00573 /** 00574 * adds the supported tests to the instance itself; 00575 * this is the function that a derived class can override 00576 * to add additional tests 00577 */ 00578 virtual void addTests(); 00579 00580 /** 00581 * opens source and inserts the given item; can be called 00582 * regardless whether the data source already contains items or not 00583 * 00584 * The type of the item is unset; it is assumed that the source 00585 * can handle that. 00586 * 00587 * @param relaxed if true, then disable some of the additional checks after adding the item 00588 * @return the UID of the inserted item 00589 */ 00590 virtual std::string insert(CreateSource createSource, const char *data, bool relaxed = false); 00591 00592 /** 00593 * assumes that exactly one element is currently inserted and updates it with the given item 00594 * 00595 * The type of the item is cleared, as in insert() above. 00596 * 00597 * @param check if true, then reopen the source and verify that the reported items are as expected 00598 */ 00599 virtual void update(CreateSource createSource, const char *data, bool check = true); 00600 00601 /** deletes all items locally via sync source */ 00602 virtual void deleteAll(CreateSource createSource); 00603 00604 /** 00605 * takes two databases, exports them, 00606 * then compares them using synccompare 00607 * 00608 * @param refFile existing file with source reference items, NULL uses a dump of sync source A instead 00609 * @param copy a sync source which contains the copied items, begin/endSync will be called 00610 * @param raiseAssert raise assertion if comparison yields differences (defaults to true) 00611 */ 00612 virtual void compareDatabases(const char *refFile, SyncSource ©, bool raiseAssert = true); 00613 00614 /** 00615 * insert artificial items, number of them determined by TEST_EVOLUTION_NUM_ITEMS 00616 * unless passed explicitly 00617 * 00618 * @param createSource a factory for the sync source that is to be used 00619 * @param startIndex IDs are generated starting with this value 00620 * @param numItems number of items to be inserted if non-null, otherwise TEST_EVOLUTION_NUM_ITEMS is used 00621 * @param size minimum size for new items 00622 * @return number of items inserted 00623 */ 00624 virtual int insertManyItems(CreateSource createSource, int startIndex = 1, int numItems = 0, int size = -1); 00625 00626 00627 /* for more information on the different tests see their implementation */ 00628 00629 virtual void testOpen(); 00630 virtual void testIterateTwice(); 00631 virtual void testSimpleInsert(); 00632 virtual void testLocalDeleteAll(); 00633 virtual void testComplexInsert(); 00634 virtual void testLocalUpdate(); 00635 virtual void testChanges(); 00636 virtual void testImport(); 00637 virtual void testImportDelete(); 00638 virtual void testManyChanges(); 00639 virtual void testLinkedItemsParent(); 00640 virtual void testLinkedItemsChild(); 00641 virtual void testLinkedItemsParentChild(); 00642 virtual void testLinkedItemsChildParent(); 00643 virtual void testLinkedItemsChildChangesParent(); 00644 virtual void testLinkedItemsRemoveParentFirst(); 00645 virtual void testLinkedItemsRemoveNormal(); 00646 virtual void testLinkedItemsInsertParentTwice(); 00647 virtual void testLinkedItemsInsertChildTwice(); 00648 virtual void testLinkedItemsParentUpdate(); 00649 virtual void testLinkedItemsUpdateChild(); 00650 virtual void testLinkedItemsInsertBothUpdateChild(); 00651 virtual void testLinkedItemsInsertBothUpdateParent(); 00652 00653 }; 00654 00655 enum itemType { 00656 NEW_ITEMS, 00657 UPDATED_ITEMS, 00658 DELETED_ITEMS, 00659 TOTAL_ITEMS 00660 }; 00661 00662 /** 00663 * utility function which counts items of a certain kind known to the sync source 00664 * @param source valid source ready to iterate; NULL triggers an assert 00665 * @param itemType determines which iterator functions are used 00666 * @return number of valid items iterated over 00667 */ 00668 int countItemsOfType(SyncSource *source, itemType type); 00669 00670 typedef std::list<std::string> UIDList; 00671 /** 00672 * generates list of UIDs in the specified kind of items 00673 */ 00674 UIDList listItemsOfType(SyncSource *source, itemType type); 00675 00676 /** 00677 * Tests synchronization with one or more sync sources enabled. 00678 * When testing multiple sources at once only the first config 00679 * is checked to see which tests can be executed. 00680 */ 00681 class SyncTests : public CppUnit::TestSuite, public CppUnit::TestFixture { 00682 public: 00683 /** the client we are testing */ 00684 ClientTest &client; 00685 00686 SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA = true); 00687 ~SyncTests(); 00688 00689 /** adds the supported tests to the instance itself */ 00690 virtual void addTests(); 00691 00692 protected: 00693 /** list with all local test classes for manipulating the sources and their index in the client */ 00694 std::vector< std::pair<int, LocalTests *> > sources; 00695 typedef std::vector< std::pair<int, LocalTests *> >::iterator source_it; 00696 00697 /** the indices from sources, terminated by -1 (for sync()) */ 00698 int *sourceArray; 00699 00700 /** utility functions for second client */ 00701 SyncTests *accessClientB; 00702 00703 enum DeleteAllMode { 00704 DELETE_ALL_SYNC, /**< make sure client and server are in sync, 00705 delete locally, 00706 sync again */ 00707 DELETE_ALL_REFRESH /**< delete locally, refresh server */ 00708 }; 00709 00710 /** compare databases of first and second client */ 00711 virtual void compareDatabases(); 00712 00713 /** deletes all items locally and on server */ 00714 virtual void deleteAll(DeleteAllMode mode = DELETE_ALL_SYNC); 00715 00716 /** get both clients in sync with empty server, then copy one item from client A to B */ 00717 virtual void doCopy(); 00718 00719 /** 00720 * replicate server database locally: same as SYNC_REFRESH_FROM_SERVER, 00721 * but done with explicit local delete and then a SYNC_SLOW because some 00722 * servers do no support SYNC_REFRESH_FROM_SERVER 00723 */ 00724 virtual void refreshClient(); 00725 00726 /* for more information on the different tests see their implementation */ 00727 00728 // do a two-way sync without additional checks 00729 virtual void testTwoWaySync() { 00730 sync(SYNC_TWO_WAY); 00731 } 00732 00733 // do a slow sync without additional checks 00734 virtual void testSlowSync() { 00735 sync(SYNC_SLOW); 00736 } 00737 // do a refresh from server sync without additional checks 00738 virtual void testRefreshFromServerSync() { 00739 sync(SYNC_REFRESH_FROM_SERVER); 00740 } 00741 00742 // do a refresh from client sync without additional checks 00743 virtual void testRefreshFromClientSync() { 00744 sync(SYNC_REFRESH_FROM_CLIENT); 00745 } 00746 00747 // delete all items, locally and on server using two-way sync 00748 virtual void testDeleteAllSync() { 00749 deleteAll(DELETE_ALL_SYNC); 00750 } 00751 00752 virtual void testDeleteAllRefresh(); 00753 virtual void testRefreshSemantic(); 00754 virtual void testRefreshStatus(); 00755 00756 // test that a two-way sync copies an item from one address book into the other 00757 void testCopy() { 00758 doCopy(); 00759 compareDatabases(); 00760 } 00761 00762 virtual void testUpdate(); 00763 virtual void testComplexUpdate(); 00764 virtual void testDelete(); 00765 virtual void testMerge(); 00766 virtual void testTwinning(); 00767 virtual void testOneWayFromServer(); 00768 virtual void testOneWayFromClient(); 00769 virtual void testItems(); 00770 virtual void testAddUpdate(); 00771 00772 // test copying with maxMsg and no large object support 00773 void testMaxMsg() { 00774 doVarSizes(true, false, NULL); 00775 } 00776 // test copying with maxMsg and large object support 00777 void testLargeObject() { 00778 doVarSizes(true, true, NULL); 00779 } 00780 // test copying with maxMsg and large object support using explicit "bin" encoding 00781 void testLargeObjectBin() { 00782 doVarSizes(true, true, "bin"); 00783 } 00784 // test copying with maxMsg and large object support using B64 encoding 00785 void testLargeObjectEncoded() { 00786 doVarSizes(true, true, "b64"); 00787 } 00788 00789 virtual void testManyItems(); 00790 00791 00792 /** 00793 * implements testMaxMsg(), testLargeObject(), testLargeObjectEncoded() 00794 * using a sequence of items with varying sizes 00795 */ 00796 virtual void doVarSizes(bool withMaxMsgSize, 00797 bool withLargeObject, 00798 const char *encoding); 00799 00800 /** 00801 * executes a sync with the given options, 00802 * checks the result and (optionally) the sync report 00803 */ 00804 virtual void sync(SyncMode syncMode, 00805 const std::string &logprefix = "", 00806 CheckSyncReport checkReport = CheckSyncReport(), 00807 long maxMsgSize = 0, 00808 long maxObjSize = 0, 00809 bool loSupport = false, 00810 const char *encoding = ""); 00811 }; 00812 00813 00814 /** assert equality, include string in message if unequal */ 00815 #define CLIENT_TEST_EQUAL( _prefix, \ 00816 _expected, \ 00817 _actual ) \ 00818 CPPUNIT_ASSERT_EQUAL_MESSAGE( std::string(_prefix) + ": " + #_expected + " == " + #_actual, \ 00819 _expected, \ 00820 _actual ) 00821 00822 /** execute _x and then check the status of the _source pointer */ 00823 #define SOURCE_ASSERT_NO_FAILURE(_source, _x) \ 00824 { \ 00825 CPPUNIT_ASSERT_NO_THROW(_x); \ 00826 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00827 } 00828 00829 /** check _x for true and then the status of the _source pointer */ 00830 #define SOURCE_ASSERT(_source, _x) \ 00831 { \ 00832 CPPUNIT_ASSERT(_x); \ 00833 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00834 } 00835 00836 /** check that _x evaluates to a specific value and then the status of the _source pointer */ 00837 #define SOURCE_ASSERT_EQUAL(_source, _value, _x) \ 00838 { \ 00839 CPPUNIT_ASSERT_EQUAL(_value, _x); \ 00840 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00841 } 00842 00843 /** same as SOURCE_ASSERT() with a specific failure message */ 00844 #define SOURCE_ASSERT_MESSAGE(_message, _source, _x) \ 00845 { \ 00846 CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \ 00847 CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ 00848 } 00849 00850 00851 /** 00852 * convenience macro for adding a test name like a function, 00853 * to be used inside addTests() of an instance of that class 00854 * 00855 * @param _class class which contains the function 00856 * @param _function a function without parameters in that class 00857 */ 00858 #define ADD_TEST(_class, _function) \ 00859 addTest(new CppUnit::TestCaller<_class>(getName() + "::" #_function, &_class::_function, *this)) 00860 00861 00862 #endif // ENABLE_INTEGRATION_TESTS 00863 00864 00865 END_NAMESPACE 00866 00867 /** @} */ 00868 /** @endcond */ 00869 #endif // INCL_TESTSYNCCLIENT