diff --git a/examples/caldavresource/tests/caldavtest.cpp b/examples/caldavresource/tests/caldavtest.cpp index daa890dd..d62616f0 100644 --- a/examples/caldavresource/tests/caldavtest.cpp +++ b/examples/caldavresource/tests/caldavtest.cpp @@ -1,370 +1,415 @@ #include #include +#include #include #include +#include #include #include #include #include #include "../caldavresource.h" #include "common/resourcecontrol.h" #include "common/secretstore.h" #include "common/store.h" #include "common/test.h" #include "tests/testutils.h" #include using Sink::ApplicationDomain::Calendar; using Sink::ApplicationDomain::DummyResource; using Sink::ApplicationDomain::Event; using Sink::ApplicationDomain::Todo; using Sink::ApplicationDomain::SinkResource; class CalDavTest : public QObject { Q_OBJECT // This test assumes a calendar "personal". const QString baseUrl = "http://localhost/dav/calendars/user/doe"; const QString username = "doe"; const QString password = "doe"; SinkResource createResource() { auto resource = Sink::ApplicationDomain::CalDavResource::create("account1"); resource.setProperty("server", baseUrl); resource.setProperty("username", username); Sink::SecretStore::instance().insert(resource.identifier(), password); - resource.setProperty("testmode", true); return resource; } QByteArray mResourceInstanceIdentifier; - QString addedEventUid; - QString addedTodoUid; + QByteArray createEvent(const QString &subject, const QString &collectionName) + { + QUrl mainUrl{"http://localhost/dav/calendars/user/doe"}; + mainUrl.setUserName(QStringLiteral("doe")); + mainUrl.setPassword(QStringLiteral("doe")); + + KDAV2::DavUrl davUrl(mainUrl, KDAV2::CalDav); + + auto *job = new KDAV2::DavCollectionsFetchJob(davUrl); + job->exec(); + + const auto collectionUrl = [&] { + for (const auto &col : job->collections()) { + // qWarning() << "Looking for " << collectionName << col.displayName(); + if (col.displayName() == collectionName) { + return col.url().url(); + } + } + return QUrl{}; + }(); + + QUrl url{collectionUrl.toString() + subject + ".ical"}; + url.setUserInfo(mainUrl.userInfo()); + + KDAV2::DavUrl testItemUrl(url, KDAV2::CardDav); + + auto event = QSharedPointer::create(); + event->setSummary(subject); + event->setDtStart(QDateTime::currentDateTime()); + event->setDtEnd(QDateTime::currentDateTime().addSecs(3600)); + event->setCreated(QDateTime::currentDateTime()); + event->setUid(subject); + + auto data = KCalCore::ICalFormat().toICalString(event).toUtf8(); + + KDAV2::DavItem item(testItemUrl, QStringLiteral("text/calendar"), data, QString()); + auto createJob = new KDAV2::DavItemCreateJob(item); + createJob->exec(); + if (createJob->error()) { + qWarning() << createJob->errorString(); + } + return event->uid().toUtf8(); + } + + void createCollection(const QString &name) + { + QUrl mainUrl(QStringLiteral("http://localhost/dav/calendars/user/doe/") + name); + mainUrl.setUserName(QStringLiteral("doe")); + mainUrl.setPassword(QStringLiteral("doe")); + + KDAV2::DavUrl davUrl(mainUrl, KDAV2::CalDav); + KDAV2::DavCollection collection{davUrl, name, KDAV2::DavCollection::Events}; + + auto createJob = new KDAV2::DavCollectionCreateJob(collection); + createJob->exec(); + if (createJob->error()) { + qWarning() << createJob->errorString(); + } + } + + void resetTestEnvironment() + { + system("resetmailbox.sh"); + } private slots: void initTestCase() { Sink::Test::initTest(); + resetTestEnvironment(); auto resource = createResource(); QVERIFY(!resource.identifier().isEmpty()); VERIFYEXEC(Sink::Store::create(resource)); mResourceInstanceIdentifier = resource.identifier(); } void cleanup() { VERIFYEXEC(Sink::Store::removeDataFromDisk(mResourceInstanceIdentifier)); } void init() { VERIFYEXEC(Sink::ResourceControl::start(mResourceInstanceIdentifier)); } void testSyncCalEmpty() { VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - auto eventJob = Sink::Store::fetchAll(Sink::Query().request()) - .then([](const QList &events) { QCOMPARE(events.size(), 0); }); - auto todoJob = Sink::Store::fetchAll(Sink::Query().request()) - .then([](const QList &todos) { QCOMPARE(todos.size(), 0); }); + QCOMPARE(Sink::Store::read({}).size(), 0); + QCOMPARE(Sink::Store::read({}).size(), 0); + + const auto calendars = Sink::Store::read(Sink::Query().request()); + QCOMPARE(calendars.size(), 1); + QCOMPARE(calendars.first().getName(), {"personal"}); + } + + void testSyncCalendars() + { + createCollection("calendar2"); + + Sink::SyncScope scope; + scope.setType(); + scope.resourceFilter(mResourceInstanceIdentifier); + + VERIFYEXEC(Sink::Store::synchronize(scope)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + const auto calendars = Sink::Store::read(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); + QCOMPARE(calendars.size(), 2); + } - VERIFYEXEC(eventJob); - VERIFYEXEC(todoJob); + void testSyncEvents() + { + createEvent("event1", "personal"); + createEvent("event2", "personal"); + createEvent("event3", "calendar2"); + Sink::SyncScope scope; + scope.setType(); + scope.resourceFilter(mResourceInstanceIdentifier); + + VERIFYEXEC(Sink::Store::synchronize(scope)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + const auto events = Sink::Store::read(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); + QCOMPARE(events.size(), 3); - auto calendarJob = Sink::Store::fetchAll(Sink::Query().request()) - .then([](const QList &calendars) { - QCOMPARE(calendars.size(), 1); - for (const auto &calendar : calendars) { - QVERIFY(calendar->getName() == "personal"); - } - }); - VERIFYEXEC(calendarJob); + //Ensure a resync works + { + VERIFYEXEC(Sink::Store::synchronize(scope)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + const auto events = Sink::Store::read(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); + QCOMPARE(events.size(), 3); + } - SinkLog() << "Finished"; + //Ensure a resync after another creation works + createEvent("event4", "calendar2"); + { + VERIFYEXEC(Sink::Store::synchronize(scope)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + const auto events = Sink::Store::read(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); + QCOMPARE(events.size(), 4); + } } - void testAddEvent() + void testCreateModifyDeleteEvent() { VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - auto future = Sink::Store::fetchOne({}).exec(); - future.waitForFinished(); - QVERIFY2(!future.errorCode(), "Fetching Calendar failed"); - auto calendar = future.value(); + auto calendar = Sink::Store::readOne(Sink::Query{}.filter("personal")); auto event = QSharedPointer::create(); event->setSummary("Hello"); event->setDtStart(QDateTime::currentDateTime()); event->setDtEnd(QDateTime::currentDateTime().addSecs(3600)); event->setCreated(QDateTime::currentDateTime()); - addedEventUid = QUuid::createUuid().toString(); + auto addedEventUid = QUuid::createUuid().toString(); event->setUid(addedEventUid); auto ical = KCalCore::ICalFormat().toICalString(event); Event sinkEvent(mResourceInstanceIdentifier); sinkEvent.setIcal(ical.toUtf8()); sinkEvent.setCalendar(calendar); - SinkLog() << "Adding event"; VERIFYEXEC(Sink::Store::create(sinkEvent)); VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); - auto verifyEventCountJob = - Sink::Store::fetchAll(Sink::Query().request()).then([](const QList &events) { - QCOMPARE(events.size(), 1); - }); - VERIFYEXEC(verifyEventCountJob); + auto events = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))); + QCOMPARE(events.size(), 1); + QCOMPARE(events.first().getSummary(), {"Hello"}); + + //Modify + { + auto event = events.first(); + auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal()); + auto calevent = incidence.dynamicCast(); + QVERIFY2(calevent, "Cannot convert to KCalCore event"); + + calevent->setSummary("Hello World!"); + auto dummy = QSharedPointer(calevent); + auto newical = KCalCore::ICalFormat().toICalString(dummy); + + event.setIcal(newical.toUtf8()); + + VERIFYEXEC(Sink::Store::modify(event)); + + VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - auto verifyEventJob = - Sink::Store::fetchOne(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) - .then([](const Event &event) { QCOMPARE(event.getSummary(), {"Hello"}); }); - VERIFYEXEC(verifyEventJob); + auto events = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))); + QCOMPARE(events.size(), 1); + QCOMPARE(events.first().getSummary(), {"Hello World!"}); + } + //Delete + { + auto event = events.first(); + + VERIFYEXEC(Sink::Store::remove(event)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); + + auto events = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))); + QCOMPARE(events.size(), 0); + } } - void testAddTodo() + void testCreateModifyDeleteTodo() { VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - auto job = Sink::Store::fetchOne({}).exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Calendar failed"); - auto calendar = job.value(); + auto calendar = Sink::Store::readOne(Sink::Query{}.filter("personal")); auto todo = QSharedPointer::create(); todo->setSummary("Hello"); todo->setDtStart(QDateTime::currentDateTime()); todo->setCreated(QDateTime::currentDateTime()); - addedTodoUid = QUuid::createUuid().toString(); + auto addedTodoUid = QUuid::createUuid().toString(); todo->setUid(addedTodoUid); auto ical = KCalCore::ICalFormat().toICalString(todo); Todo sinkTodo(mResourceInstanceIdentifier); sinkTodo.setIcal(ical.toUtf8()); sinkTodo.setCalendar(calendar); - SinkLog() << "Adding todo"; VERIFYEXEC(Sink::Store::create(sinkTodo)); VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); - auto verifyTodoCountJob = - Sink::Store::fetchAll(Sink::Query().request()).then([](const QList &todos) { - QCOMPARE(todos.size(), 1); - }); - VERIFYEXEC(verifyTodoCountJob); + auto todos = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))); + QCOMPARE(todos.size(), 1); + QCOMPARE(todos.first().getSummary(), {"Hello"}); - auto verifyTodoJob = - Sink::Store::fetchOne(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) - .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello"}); }); - VERIFYEXEC(verifyTodoJob); - } - - void testModifyEvent() - { - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - - auto job = Sink::Store::fetchOne( - Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) - .exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Event failed"); - auto event = job.value(); + //Modify + { + auto todo = todos.first(); + auto incidence = KCalCore::ICalFormat().readIncidence(todo.getIcal()); + auto caltodo = incidence.dynamicCast(); + QVERIFY2(caltodo, "Cannot convert to KCalCore todo"); - auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal()); - auto calevent = incidence.dynamicCast(); - QVERIFY2(calevent, "Cannot convert to KCalCore event"); + caltodo->setSummary("Hello World!"); + auto dummy = QSharedPointer(caltodo); + auto newical = KCalCore::ICalFormat().toICalString(dummy); - calevent->setSummary("Hello World!"); - auto dummy = QSharedPointer(calevent); - auto newical = KCalCore::ICalFormat().toICalString(dummy); + todo.setIcal(newical.toUtf8()); - event.setIcal(newical.toUtf8()); + VERIFYEXEC(Sink::Store::modify(todo)); - VERIFYEXEC(Sink::Store::modify(event)); + VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + auto todos = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))); + QCOMPARE(todos.size(), 1); + QCOMPARE(todos.first().getSummary(), {"Hello World!"}); + } + //Delete + { + auto todo = todos.first(); - auto verifyEventCountJob = Sink::Store::fetchAll({}).then( - [](const QList &events) { QCOMPARE(events.size(), 1); }); - VERIFYEXEC(verifyEventCountJob); + VERIFYEXEC(Sink::Store::remove(todo)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); - auto verifyEventJob = - Sink::Store::fetchOne(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) - .then([](const Event &event) { QCOMPARE(event.getSummary(), {"Hello World!"}); }); - VERIFYEXEC(verifyEventJob); + auto todos = Sink::Store::read(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))); + QCOMPARE(todos.size(), 0); + } } - void testModifyTodo() + void testModificationConflict() { VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - auto job = Sink::Store::fetchOne( - Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) - .exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Todo failed"); - auto todo = job.value(); - - auto incidence = KCalCore::ICalFormat().readIncidence(todo.getIcal()); - auto caltodo = incidence.dynamicCast(); - QVERIFY2(caltodo, "Cannot convert to KCalCore todo"); - - caltodo->setSummary("Hello World!"); - auto dummy = QSharedPointer(caltodo); - auto newical = KCalCore::ICalFormat().toICalString(dummy); - - todo.setIcal(newical.toUtf8()); - - VERIFYEXEC(Sink::Store::modify(todo)); + auto calendar = Sink::Store::readOne(Sink::Query{}.filter("personal")); - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - - auto verifyTodoCountJob = Sink::Store::fetchAll({}).then( - [](const QList &todos) { QCOMPARE(todos.size(), 1); }); - VERIFYEXEC(verifyTodoCountJob); + auto event = QSharedPointer::create(); + event->setSummary("Hello"); + event->setDtStart(QDateTime::currentDateTime()); + event->setDtEnd(QDateTime::currentDateTime().addSecs(3600)); + event->setCreated(QDateTime::currentDateTime()); + auto addedEventUid = QUuid::createUuid().toString(); + event->setUid(addedEventUid); - auto verifyTodoJob = - Sink::Store::fetchOne(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) - .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello World!"}); }); - VERIFYEXEC(verifyTodoJob); - } + auto ical = KCalCore::ICalFormat().toICalString(event); + Event sinkEvent(mResourceInstanceIdentifier); + sinkEvent.setIcal(ical.toUtf8()); + sinkEvent.setCalendar(calendar); - void testSneakyModifyEvent() - { - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + VERIFYEXEC(Sink::Store::create(sinkEvent)); + VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); // Change the item without sink's knowledge { - auto collection = ([this]() -> KDAV2::DavCollection { + auto collection = [&]() -> KDAV2::DavCollection { QUrl url(baseUrl); url.setUserName(username); url.setPassword(password); KDAV2::DavUrl davurl(url, KDAV2::CalDav); auto collectionsJob = new KDAV2::DavCollectionsFetchJob(davurl); collectionsJob->exec(); Q_ASSERT(collectionsJob->error() == 0); - return collectionsJob->collections()[0]; - })(); + for (const auto &col : collectionsJob->collections()) { + if (col.displayName() == "personal") { + return col; + } + } + return {}; + }(); auto itemList = ([&collection]() -> KDAV2::DavItem::List { auto cache = std::make_shared(); auto itemsListJob = new KDAV2::DavItemsListJob(collection.url(), cache); itemsListJob->exec(); Q_ASSERT(itemsListJob->error() == 0); return itemsListJob->items(); })(); auto hollowDavItemIt = - std::find_if(itemList.begin(), itemList.end(), [this](const KDAV2::DavItem &item) { + std::find_if(itemList.begin(), itemList.end(), [&](const KDAV2::DavItem &item) { return item.url().url().path().endsWith(addedEventUid); }); QVERIFY(hollowDavItemIt != itemList.end()); - auto davitem = ([this, &collection, &hollowDavItemIt]() -> KDAV2::DavItem { + auto davitem = ([&]() -> KDAV2::DavItem { QString itemUrl = collection.url().url().toEncoded() + addedEventUid; auto itemFetchJob = new KDAV2::DavItemFetchJob (*hollowDavItemIt); itemFetchJob->exec(); Q_ASSERT(itemFetchJob->error() == 0); return itemFetchJob->item(); })(); auto incidence = KCalCore::ICalFormat().readIncidence(davitem.data()); auto calevent = incidence.dynamicCast(); QVERIFY2(calevent, "Cannot convert to KCalCore event"); calevent->setSummary("Manual Hello World!"); auto newical = KCalCore::ICalFormat().toICalString(calevent); davitem.setData(newical.toUtf8()); auto itemModifyJob = new KDAV2::DavItemModifyJob(davitem); itemModifyJob->exec(); QVERIFY2(itemModifyJob->error() == 0, "Cannot modify item"); } - // Try to change the item with sink + //Change the item with sink as well { - auto job = Sink::Store::fetchOne( - Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) - .exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Event failed"); - auto event = job.value(); - - auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal()); - auto calevent = incidence.dynamicCast(); - QVERIFY2(calevent, "Cannot convert to KCalCore event"); + auto event = Sink::Store::readOne(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))); + auto calevent = KCalCore::ICalFormat().readIncidence(event.getIcal()).dynamicCast(); + QVERIFY(calevent); calevent->setSummary("Sink Hello World!"); - auto dummy = QSharedPointer(calevent); - auto newical = KCalCore::ICalFormat().toICalString(dummy); + event.setIcal(KCalCore::ICalFormat().toICalString(calevent).toUtf8()); - event.setIcal(newical.toUtf8()); - - // TODO: make that fail + // TODO: this produced a conflict, but we're not dealing with it in any way VERIFYEXEC(Sink::Store::modify(event)); VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); } } - void testRemoveEvent() - { - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - - auto job = Sink::Store::fetchOne( - Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) - .exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Event failed"); - auto event = job.value(); - - VERIFYEXEC(Sink::Store::remove(event)); - VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); - - auto verifyEventCountJob = Sink::Store::fetchAll({}).then( - [](const QList &events) { QCOMPARE(events.size(), 0); }); - VERIFYEXEC(verifyEventCountJob); - } - - void testRemoveTodo() - { - VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); - VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); - - auto job = Sink::Store::fetchOne( - Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) - .exec(); - job.waitForFinished(); - QVERIFY2(!job.errorCode(), "Fetching Todo failed"); - auto todo = job.value(); - VERIFYEXEC(Sink::Store::remove(todo)); - VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); - - auto verifyTodoCountJob = Sink::Store::fetchAll({}).then( - [](const QList &todos) { QCOMPARE(todos.size(), 0); }); - VERIFYEXEC(verifyTodoCountJob); - } }; QTEST_MAIN(CalDavTest) #include "caldavtest.moc"