00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include <base/test.h>
00022 #include <ClientTest.h>
00023
00024 #include <cppunit/extensions/HelperMacros.h>
00025 #include <exception>
00026 #include <fstream>
00027 #include <fcntl.h>
00028 #include <unistd.h>
00029 #include <errno.h>
00030 #include <signal.h>
00031 #ifdef HAVE_VALGRIND_VALGRIND_H
00032 # include <valgrind/valgrind.h>
00033 #endif
00034 #ifdef HAVE_EXECINFO_H
00035 # include <execinfo.h>
00036 #endif
00037
00038 #include "EvolutionSyncClient.h"
00039 #include "EvolutionSyncSource.h"
00040 #include "SyncEvolutionUtil.h"
00041
00042
00043
00044
00045
00046
00047 CPPUNIT_REGISTRY_ADD_TO_DEFAULT("SyncEvolution");
00048
00049
00050
00051
00052
00053 class TestEvolutionSyncSource : public EvolutionSyncSource {
00054 public:
00055 TestEvolutionSyncSource(const string &type,
00056 const EvolutionSyncSourceParams ¶ms) :
00057 EvolutionSyncSource(params)
00058 {
00059 PersistentEvolutionSyncSourceConfig config(params.m_name, params.m_nodes);
00060 config.setSourceType(type);
00061 m_source.reset(EvolutionSyncSource::createSource(params));
00062 CPPUNIT_ASSERT(m_source.get());
00063 m_source->setSyncMode(SYNC_NONE);
00064 }
00065
00066 virtual int beginSync() throw () {
00067 CPPUNIT_ASSERT_NO_THROW(m_source->open());
00068 CPPUNIT_ASSERT(!m_source->hasFailed());
00069 return m_source->beginSync();
00070 }
00071
00072 virtual int endSync() throw () {
00073 int res = m_source->endSync();
00074 CPPUNIT_ASSERT_NO_THROW(m_source->close());
00075 CPPUNIT_ASSERT(!m_source->hasFailed());
00076 return res;
00077 }
00078
00079 virtual SyncItem* getFirstItem() throw () { return m_source->getFirstItem(); }
00080 virtual SyncItem* getNextItem() throw () { return m_source->getNextItem(); }
00081 virtual SyncItem* getFirstNewItem() throw () { return m_source->getFirstNewItem(); }
00082 virtual SyncItem* getNextNewItem() throw () { return m_source->getNextNewItem(); }
00083 virtual SyncItem* getFirstUpdatedItem() throw () { return m_source->getFirstUpdatedItem(); }
00084 virtual SyncItem* getNextUpdatedItem() throw () { return m_source->getNextUpdatedItem(); }
00085 virtual SyncItem* getFirstDeletedItem() throw () { return m_source->getFirstDeletedItem(); }
00086 virtual SyncItem* getNextDeletedItem() throw () { return m_source->getNextDeletedItem(); }
00087 virtual SyncItem* getFirstItemKey() throw () { return m_source->getFirstItemKey(); }
00088 virtual SyncItem* getNextItemKey() throw () { return m_source->getNextItemKey(); }
00089 virtual void setItemStatus(const char *key, int status) throw () { m_source->setItemStatus(key, status); }
00090 virtual int addItem(SyncItem& item) throw () { return m_source->addItem(item); }
00091 virtual int updateItem(SyncItem& item) throw () { return m_source->updateItem(item); }
00092 virtual int deleteItem(SyncItem& item) throw () { return m_source->deleteItem(item); }
00093 virtual int removeAllItems() throw () { return m_source->removeAllItems(); }
00094 const char *getName() throw () { return m_source->getName(); }
00095
00096 virtual Databases getDatabases() { return m_source->getDatabases(); }
00097 virtual void open() { m_source->open(); }
00098 virtual SyncItem *createItem(const string &uid) { return m_source->createItem(uid); }
00099 virtual void close() { m_source->close(); }
00100 virtual void exportData(ostream &out) { m_source->exportData(out); }
00101 virtual string fileSuffix() const { return m_source->fileSuffix(); }
00102 virtual const char *getMimeType() const { return m_source->getMimeType(); }
00103 virtual const char *getMimeVersion() const { return m_source->getMimeVersion(); }
00104 virtual const char* getSupportedTypes() const { return m_source->getSupportedTypes(); }
00105 virtual void beginSyncThrow(bool needAll,
00106 bool needPartial,
00107 bool deleteLocal) { m_source->beginSyncThrow(needAll, needPartial, deleteLocal); }
00108 virtual void endSyncThrow() { m_source->endSyncThrow(); }
00109 virtual int addItemThrow(SyncItem& item) { return m_source->addItemThrow(item); }
00110 virtual int updateItemThrow(SyncItem& item) { return m_source->updateItemThrow(item); }
00111 virtual int deleteItemThrow(SyncItem& item) { return m_source->deleteItemThrow(item); }
00112 virtual void logItem(const string &uid, const string &info, bool debug = false) { m_source->logItem(uid, info, debug); }
00113 virtual void logItem(const SyncItem &item, const string &info, bool debug = false) { m_source->logItem(item, info, debug); }
00114
00115 auto_ptr<EvolutionSyncSource> m_source;
00116 };
00117
00118 class EvolutionLocalTests : public LocalTests {
00119 public:
00120 EvolutionLocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) :
00121 LocalTests(name, cl, sourceParam, co)
00122 {}
00123
00124 virtual void addTests() {
00125 LocalTests::addTests();
00126
00127 #ifdef ENABLE_MAEMO
00128 if (config.createSourceA &&
00129 config.createSourceB &&
00130 config.templateItem &&
00131 strstr(config.templateItem, "BEGIN:VCARD") &&
00132 config.uniqueProperties) {
00133 ADD_TEST(EvolutionLocalTests, testOssoDelete);
00134 }
00135 #endif
00136 }
00137
00138 private:
00139
00140
00141
00142
00143 void testOssoDelete() {
00144
00145 deleteAll(createSourceA);
00146 insert(createSourceA, config.templateItem);
00147
00148
00149 string item = config.templateItem;
00150 const char *comma = strchr(config.uniqueProperties, ':');
00151 size_t offset = item.find(config.uniqueProperties, 0,
00152 comma ? comma - config.uniqueProperties : strlen(config.uniqueProperties));
00153 CPPUNIT_ASSERT(offset != item.npos);
00154 item.insert(offset, "X-OSSO-CONTACT-STATE:DELETED\n");
00155 update(createSourceA, item.c_str(), false);
00156
00157
00158 std::auto_ptr<SyncSource> source;
00159 SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceA()));
00160 SOURCE_ASSERT(source.get(), source->beginSync() == 0 );
00161 CPPUNIT_ASSERT_EQUAL(0, countItemsOfType(source.get(), TOTAL_ITEMS));
00162 CPPUNIT_ASSERT_EQUAL(0, countItemsOfType(source.get(), NEW_ITEMS));
00163 CPPUNIT_ASSERT_EQUAL(0, countItemsOfType(source.get(), UPDATED_ITEMS));
00164 CPPUNIT_ASSERT_EQUAL(1, countItemsOfType(source.get(), DELETED_ITEMS));
00165 }
00166 };
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 class TestEvolution : public ClientTest {
00205 public:
00206
00207
00208
00209 TestEvolution(const string &id) :
00210 ClientTest(getenv("CLIENT_TEST_DELAY") ? atoi(getenv("CLIENT_TEST_DELAY")) : 0,
00211 getenv("CLIENT_TEST_LOG") ? getenv("CLIENT_TEST_LOG") : ""),
00212 m_clientID(id),
00213 m_configs(EvolutionSyncSource::getTestRegistry())
00214 {
00215 const char *server = getenv("CLIENT_TEST_SERVER");
00216
00217 if (id == "1") {
00218 m_clientB.reset(new TestEvolution("2"));
00219 }
00220
00221
00222 if (!server) {
00223 server = "funambol";
00224 setenv("CLIENT_TEST_SERVER", "funambol", 1);
00225 }
00226
00227
00228 const char *evoprefix = getenv("CLIENT_TEST_EVOLUTION_PREFIX");
00229 m_evoPrefix = evoprefix ? evoprefix : "SyncEvolution_Test_";
00230 const char *evouser = getenv("CLIENT_TEST_EVOLUTION_USER");
00231 if (evouser) {
00232 m_evoUser = evouser;
00233 }
00234 const char *evopasswd = getenv("CLIENT_TEST_EVOLUTION_PASSWORD");
00235 if (evopasswd) {
00236 m_evoPassword = evopasswd;
00237 }
00238
00239
00240 const char *sourcelist = getenv("CLIENT_TEST_SOURCES");
00241 set<string> sources;
00242 if (sourcelist) {
00243 boost::split(sources, sourcelist, boost::is_any_of(","));
00244 } else {
00245 BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
00246 sources.insert(test->m_configName);
00247 }
00248 }
00249
00250 BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
00251 if (sources.find(test->m_configName) != sources.end()) {
00252 m_source2Config.push_back(test->m_configName);
00253 }
00254 }
00255
00256
00257 LOG.setLevel(LOG_LEVEL_DEBUG);
00258 std::string root = std::string("evolution/") + server + "_" + id;
00259 EvolutionSyncConfig config(string(server) + "_" + id);
00260 if (!config.exists()) {
00261
00262 config.setDefaults();
00263 config.setDevID(id == "1" ? "sc-api-nat" : "sc-pim-ppc");
00264 }
00265 BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
00266 ClientTest::Config testconfig;
00267 getSourceConfig(test, testconfig);
00268 CPPUNIT_ASSERT(testconfig.type);
00269
00270 boost::shared_ptr<EvolutionSyncSourceConfig> sc = config.getSyncSourceConfig(testconfig.sourceName);
00271 if (!sc || !sc->exists()) {
00272
00273 config.setSourceDefaults(testconfig.sourceName);
00274 sc = config.getSyncSourceConfig(testconfig.sourceName);
00275 CPPUNIT_ASSERT(sc);
00276 sc->setURI(testconfig.uri);
00277 sc->setSourceType(testconfig.type);
00278 }
00279
00280
00281 string database = getDatabaseName(test->m_configName);
00282 sc->setDatabaseID(database);
00283 sc->setUser(m_evoUser);
00284 sc->setPassword(m_evoPassword);
00285 }
00286 config.flush();
00287 }
00288
00289 virtual LocalTests *createLocalTests(const std::string &name, int sourceParam, ClientTest::Config &co) {
00290 return new EvolutionLocalTests(name, *this, sourceParam, co);
00291 }
00292
00293 virtual int getNumSources() {
00294 return m_source2Config.size();
00295 }
00296
00297 virtual void getSourceConfig(int source, Config &config) {
00298 getSourceConfig(m_configs[m_source2Config[source]], config);
00299 }
00300
00301 static void getSourceConfig(const RegisterSyncSourceTest *test, Config &config) {
00302 memset(&config, 0, sizeof(config));
00303 ClientTest::getTestData(test->m_testCaseName.c_str(), config);
00304 config.createSourceA = createSource;
00305 config.createSourceB = createSource;
00306 config.compare = compare;
00307 config.sourceName = test->m_configName.c_str();
00308
00309 test->updateConfig(config);
00310 }
00311
00312 virtual ClientTest *getClientB() {
00313 return m_clientB.get();
00314 }
00315
00316 virtual bool isB64Enabled() {
00317 return false;
00318 }
00319
00320 virtual int sync(
00321 const int *sources,
00322 SyncMode syncMode,
00323 const CheckSyncReport &checkReport,
00324 long maxMsgSize = 0,
00325 long maxObjSize = 0,
00326 bool loSupport = false,
00327 const char *encoding = NULL) {
00328 set<string> activeSources;
00329 for(int i = 0; sources[i] >= 0; i++) {
00330 activeSources.insert(m_source2Config[sources[i]]);
00331 }
00332
00333 string server = getenv("CLIENT_TEST_SERVER") ? getenv("CLIENT_TEST_SERVER") : "funambol";
00334 server += "_";
00335 server += m_clientID;
00336
00337 class ClientTest : public EvolutionSyncClient {
00338 public:
00339 ClientTest(const string &server,
00340 const set<string> &activeSources,
00341 SyncMode syncMode,
00342 long maxMsgSize,
00343 long maxObjSize,
00344 bool loSupport,
00345 const char *encoding) :
00346 EvolutionSyncClient(server, false, activeSources),
00347 m_syncMode(syncMode),
00348 m_maxMsgSize(maxMsgSize),
00349 m_maxObjSize(maxObjSize),
00350 m_loSupport(loSupport),
00351 m_encoding(encoding)
00352 {}
00353
00354 protected:
00355 virtual void prepare(SyncSource **sources) {
00356 for (SyncSource **source = sources;
00357 *source;
00358 source++) {
00359 ((EvolutionSyncSource *)*source)->setEncoding(m_encoding ? m_encoding : "", true);
00360 (*source)->setPreferredSyncMode(m_syncMode);
00361 }
00362 setLoSupport(m_loSupport, true);
00363 setMaxObjSize(m_maxObjSize, true);
00364 setMaxMsgSize(m_maxMsgSize, true);
00365 EvolutionSyncClient::prepare(sources);
00366 }
00367
00368 private:
00369 const SyncMode m_syncMode;
00370 const long m_maxMsgSize;
00371 const long m_maxObjSize;
00372 const bool m_loSupport;
00373 const char *m_encoding;
00374 } client(server, activeSources, syncMode, maxMsgSize, maxObjSize, loSupport, encoding);
00375
00376 int res = client.sync();
00377 CPPUNIT_ASSERT(client.getSyncReport());
00378 checkReport.check(res, *client.getSyncReport());
00379 return res;
00380 }
00381
00382 static bool compare(ClientTest &client, const char *fileA, const char *fileB) {
00383 std::string cmdstr = std::string("./synccompare ") + fileA + " " + fileB;
00384 return system(cmdstr.c_str()) == 0;
00385 }
00386
00387 private:
00388 string m_clientID;
00389 std::auto_ptr<TestEvolution> m_clientB;
00390 const TestRegistry &m_configs;
00391
00392
00393 string m_evoPrefix, m_evoUser, m_evoPassword;
00394
00395
00396
00397
00398
00399
00400 vector<string> m_source2Config;
00401
00402
00403 string getDatabaseName(const string &configName) {
00404 return m_evoPrefix + configName + "_" + m_clientID;
00405 }
00406
00407 static SyncSource *createSource(ClientTest &client, int source, bool isSourceA) {
00408 TestEvolution &evClient((TestEvolution &)client);
00409 string changeID = "SyncEvolution Change ID #";
00410 string name = evClient.m_source2Config[source];
00411 changeID += isSourceA ? "1" : "2";
00412 string database = evClient.getDatabaseName(name);
00413
00414 EvolutionSyncConfig config("client-test-changes");
00415 SyncSourceNodes nodes = config.getSyncSourceNodes(name,
00416 string("_") + ((TestEvolution &)client).m_clientID +
00417 "_" + (isSourceA ? "A" : "B"));
00418
00419
00420 nodes.m_configNode->setProperty("evolutionsource", database.c_str());
00421 nodes.m_configNode->setProperty("evolutionuser", evClient.m_evoUser.c_str());
00422 nodes.m_configNode->setProperty("evolutionpassword", evClient.m_evoPassword.c_str());
00423
00424 EvolutionSyncSourceParams params(name,
00425 nodes,
00426 changeID);
00427
00428 const RegisterSyncSourceTest *test = evClient.m_configs[name];
00429 ClientTestConfig testConfig;
00430 getSourceConfig(test, testConfig);
00431
00432 SyncSource *ss = new TestEvolutionSyncSource(testConfig.type, params);
00433 return ss;
00434 }
00435 };
00436
00437 static void handler(int sig)
00438 {
00439 void *buffer[100];
00440 int size;
00441
00442 fprintf(stderr, "\ncaught signal %d\n", sig);
00443 fflush(stderr);
00444 #ifdef HAVE_EXECINFO_H
00445 size = backtrace(buffer, sizeof(buffer)/sizeof(buffer[0]));
00446 backtrace_symbols_fd(buffer, size, 2);
00447 #endif
00448 #ifdef HAVE_VALGRIND_VALGRIND_H
00449 VALGRIND_PRINTF_BACKTRACE("\ncaught signal %d\n", sig);
00450 #endif
00451
00452 struct sigaction act;
00453 memset(&act, 0, sizeof(act));
00454 act.sa_handler = SIG_DFL;
00455 sigaction(SIGABRT, &act, NULL);
00456 abort();
00457 }
00458
00459 static class RegisterTestEvolution {
00460 public:
00461 RegisterTestEvolution() :
00462 testClient("1") {
00463 struct sigaction act;
00464
00465 memset(&act, 0, sizeof(act));
00466 act.sa_handler = handler;
00467 sigaction(SIGABRT, &act, NULL);
00468 sigaction(SIGSEGV, &act, NULL);
00469 sigaction(SIGILL, &act, NULL);
00470
00471 #if defined(HAVE_GLIB) && defined(HAVE_EDS)
00472
00473
00474 g_type_init();
00475 #endif
00476 EDSAbiWrapperInit();
00477 testClient.registerTests();
00478 }
00479
00480 private:
00481 TestEvolution testClient;
00482
00483 } testEvolution;
00484
00485 int RegisterSyncSourceTest::dump(ClientTest &client, SyncSource &source, const char *file)
00486 {
00487 std::ofstream out(file);
00488
00489 ((EvolutionSyncSource &)source).exportData(out);
00490
00491 out.close();
00492 return out.bad();
00493 }