#include #include #include #include "clientapi.h" #include "facade.h" #include "synclistresult.h" class RevisionNotifier : public QObject { Q_OBJECT public: RevisionNotifier() : QObject() {}; void notify(qint64 revision) { emit revisionChanged(revision); } Q_SIGNALS: void revisionChanged(qint64); }; class DummyResourceFacade : public Akonadi2::StoreFacade { public: ~DummyResourceFacade(){}; Async::Job create(const Akonadi2::ApplicationDomain::Event &domainObject) Q_DECL_OVERRIDE { return Async::null(); }; Async::Job modify(const Akonadi2::ApplicationDomain::Event &domainObject) Q_DECL_OVERRIDE { return Async::null(); }; Async::Job remove(const Akonadi2::ApplicationDomain::Event &domainObject) Q_DECL_OVERRIDE { return Async::null(); }; Async::Job load(const Akonadi2::Query &query, const std::function &resultCallback) { return Async::start([this, resultCallback](Async::Future &future) { qDebug() << "load called"; for(const auto &result : results) { resultCallback(result); } future.setValue(0); future.setFinished(); }); } Async::Job load(const Akonadi2::Query &query, const QSharedPointer > &resultProvider) Q_DECL_OVERRIDE { auto runner = QSharedPointer::create(query); //The runner only lives as long as the resultProvider resultProvider->setQueryRunner(runner); QWeakPointer > weakResultProvider = resultProvider; capturedResultProvider = resultProvider; runner->setQuery([this, weakResultProvider, query](qint64 oldRevision, qint64 newRevision) -> Async::Job { qDebug() << "Creating query for revisions: " << oldRevision << newRevision; return Async::start([this, weakResultProvider, query](Async::Future &future) { auto resultProvider = weakResultProvider.toStrongRef(); if (!resultProvider) { Warning() << "Tried executing query after result provider is already gone"; future.setError(0, QString()); future.setFinished(); return; } //TODO only emit changes and don't replace everything resultProvider->clear(); //rerun query std::function addCallback = std::bind(&Akonadi2::ResultProvider::add, resultProvider, std::placeholders::_1); load(query, addCallback).then([resultProvider, &future, query](qint64 queriedRevision) { future.setValue(queriedRevision); future.setFinished(); }).exec(); }); }); //Ensure the notification is emitted in the right thread //Otherwise we get crashes as we call revisionChanged from the test. if (!notifier) { notifier.reset(new RevisionNotifier); } //TODO somehow disconnect as resultNotifier is destroyed. Otherwise we keep the runner alive forever. if (query.liveQuery) { QObject::connect(notifier.data(), &RevisionNotifier::revisionChanged, [runner](qint64 newRevision) { runner->revisionChanged(newRevision); }); } return Async::start([runner](Async::Future &future) { runner->run().then([&future]() { //TODO if not live query, destroy runner. future.setFinished(); }).exec(); }); } QList results; QSharedPointer notifier; QWeakPointer > capturedResultProvider; }; class ClientAPITest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { Akonadi2::FacadeFactory::instance().resetFactory(); } void testLoad() { DummyResourceFacade facade; facade.results << QSharedPointer::create("resource", "id", 0, QSharedPointer()); Akonadi2::FacadeFactory::instance().registerFacade("dummyresource", [&facade](bool &externallyManaged) { externallyManaged = true; return &facade; } ); Akonadi2::Query query; query.resources << "dummyresource"; query.liveQuery = false; async::SyncListResult result(Akonadi2::Store::load(query)); result.exec(); QCOMPARE(result.size(), 1); } void testLiveQuery() { DummyResourceFacade facade; facade.results << QSharedPointer::create("resource", "id", 0, QSharedPointer()); Akonadi2::FacadeFactory::instance().registerFacade("dummyresource", [&facade](bool &externallyManaged){ externallyManaged = true; return &facade; } ); Akonadi2::Query query; query.resources << "dummyresource"; query.liveQuery = true; async::SyncListResult result(Akonadi2::Store::load(query)); result.exec(); QCOMPARE(result.size(), 1); //Enter a second result facade.results << QSharedPointer::create("resource", "id2", 0, QSharedPointer()); qWarning() << &facade; QVERIFY(facade.notifier); facade.notifier->revisionChanged(2); QTRY_COMPARE(result.size(), 2); } void testQueryLifetime() { DummyResourceFacade facade; facade.results << QSharedPointer::create("resource", "id", 0, QSharedPointer()); Akonadi2::FacadeFactory::instance().registerFacade("dummyresource", [&facade](bool &externallyManaged){ externallyManaged = true; return &facade; } ); Akonadi2::Query query; query.resources << "dummyresource"; query.liveQuery = true; { async::SyncListResult result(Akonadi2::Store::load(query)); result.exec(); QCOMPARE(result.size(), 1); } //It's running in a separate thread, so we have to wait for a moment. QTRY_VERIFY(!facade.capturedResultProvider); } }; QTEST_MAIN(ClientAPITest) #include "clientapitest.moc"