File indexing completed on 2024-06-16 04:50:16

0001 /* This file is based on qtest_kde.h from kdelibs
0002     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #pragma once
0009 
0010 #include "agentinstance.h"
0011 #include "agentmanager.h"
0012 #include "collectionfetchscope.h"
0013 #include "collectionpathresolver.h"
0014 #include "itemfetchscope.h"
0015 #include "monitor.h"
0016 #include "servermanager.h"
0017 
0018 #include <QDBusConnection>
0019 #include <QDBusInterface>
0020 #include <QDBusReply>
0021 #include <QSignalSpy>
0022 #include <QTest>
0023 #include <QTimer>
0024 
0025 /**
0026  * \short Akonadi Replacement for QTEST_MAIN from QTestLib
0027  *
0028  * This macro should be used for classes that run inside the Akonadi Testrunner.
0029  * So instead of writing QTEST_MAIN( TestClass ) you write
0030  * QTEST_AKONADIMAIN( TestClass ).
0031  *
0032  * Unlike QTEST_MAIN, this macro actually does call QApplication::exec() so
0033  * that the application is running during test execution. This is needed
0034  * for proper clean up of Sessions.
0035  *
0036  * \param TestObject The class you use for testing.
0037  *
0038  * \see QTestLib
0039  * \see QTEST_KDEMAIN
0040  */
0041 #define QTEST_AKONADIMAIN(TestObject)                                                                                                                          \
0042     int main(int argc, char *argv[])                                                                                                                           \
0043     {                                                                                                                                                          \
0044         qputenv("LC_ALL", "C");                                                                                                                                \
0045         qunsetenv("KDE_COLOR_DEBUG");                                                                                                                          \
0046         QApplication app(argc, argv);                                                                                                                          \
0047         app.setApplicationName(QStringLiteral("qttest"));                                                                                                      \
0048         app.setOrganizationDomain(QStringLiteral("kde.org"));                                                                                                  \
0049         app.setOrganizationName(QStringLiteral("KDE"));                                                                                                        \
0050         QGuiApplication::setQuitOnLastWindowClosed(false);                                                                                                     \
0051         QCoreApplication::setQuitLockEnabled(false);                                                                                                           \
0052         qRegisterMetaType<QList<QUrl>>();                                                                                                                      \
0053         int result = 0;                                                                                                                                        \
0054         QTimer::singleShot(0, &app, [argc, argv, &result]() {                                                                                                  \
0055             TestObject tc;                                                                                                                                     \
0056             result = QTest::qExec(&tc, argc, argv);                                                                                                            \
0057             qApp->quit();                                                                                                                                      \
0058         });                                                                                                                                                    \
0059         app.exec();                                                                                                                                            \
0060         return result;                                                                                                                                         \
0061     }
0062 
0063 namespace AkonadiTest
0064 {
0065 /**
0066  * Checks that the test is running in the proper test environment
0067  */
0068 void checkTestIsIsolated()
0069 {
0070     if (qEnvironmentVariableIsEmpty("TESTRUNNER_DB_ENVIRONMENT"))
0071         qFatal("This test must be run using ctest, in order to use the testrunner environment. Aborting, to avoid messing up your real akonadi");
0072     if (!qgetenv("XDG_DATA_HOME").contains("testrunner"))
0073         qFatal("Did you forget to run the test using QTEST_AKONADIMAIN?");
0074 }
0075 
0076 /**
0077  * Switch all resources offline to reduce interference from them
0078  */
0079 void setAllResourcesOffline()
0080 {
0081     // switch all resources offline to reduce interference from them
0082     const auto lst = Akonadi::AgentManager::self()->instances();
0083     for (Akonadi::AgentInstance agent : lst) {
0084         agent.setIsOnline(false);
0085     }
0086 }
0087 
0088 template<typename Object, typename Func>
0089 bool akWaitForSignal(Object sender, Func member, int timeout = 1000)
0090 {
0091     QSignalSpy spy(sender, member);
0092     bool ok = false;
0093     [&]() {
0094         QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, timeout);
0095         ok = true;
0096     }();
0097     return ok;
0098 }
0099 
0100 bool akWaitForSignal(const QObject *sender, const char *member, int timeout = 1000)
0101 {
0102     QSignalSpy spy(sender, member);
0103     bool ok = false;
0104     [&]() {
0105         QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, timeout);
0106         ok = true;
0107     }();
0108     return ok;
0109 }
0110 
0111 qint64 collectionIdFromPath(const QString &path)
0112 {
0113     auto resolver = new Akonadi::CollectionPathResolver(path);
0114     bool success = resolver->exec();
0115     if (!success) {
0116         qDebug() << "path resolution for " << path << " failed: " << resolver->errorText();
0117         return -1;
0118     }
0119     qint64 id = resolver->collection();
0120     return id;
0121 }
0122 
0123 QString testrunnerServiceName()
0124 {
0125     const QString pid = QString::fromLocal8Bit(qgetenv("AKONADI_TESTRUNNER_PID"));
0126     Q_ASSERT(!pid.isEmpty());
0127     return QStringLiteral("org.kde.Akonadi.Testrunner-") + pid;
0128 }
0129 
0130 bool restartAkonadiServer()
0131 {
0132     QDBusInterface testrunnerIface(testrunnerServiceName(), QStringLiteral("/"), QStringLiteral("org.kde.Akonadi.Testrunner"), QDBusConnection::sessionBus());
0133     if (!testrunnerIface.isValid()) {
0134         qWarning() << "Unable to get a dbus interface to the testrunner!";
0135     }
0136 
0137     QDBusReply<void> reply = testrunnerIface.call(QStringLiteral("restartAkonadiServer"));
0138     if (!reply.isValid()) {
0139         qWarning() << reply.error();
0140         return false;
0141     } else if (Akonadi::ServerManager::isRunning()) {
0142         return true;
0143     } else {
0144         bool ok = false;
0145         [&]() {
0146             QSignalSpy spy(Akonadi::ServerManager::self(), &Akonadi::ServerManager::started);
0147             QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 10000);
0148             ok = true;
0149         }();
0150         return ok;
0151     }
0152 }
0153 
0154 bool trackAkonadiProcess(bool track)
0155 {
0156     QDBusInterface testrunnerIface(testrunnerServiceName(), QStringLiteral("/"), QStringLiteral("org.kde.Akonadi.Testrunner"), QDBusConnection::sessionBus());
0157     if (!testrunnerIface.isValid()) {
0158         qWarning() << "Unable to get a dbus interface to the testrunner!";
0159     }
0160 
0161     QDBusReply<void> reply = testrunnerIface.call(QStringLiteral("trackAkonadiProcess"), track);
0162     if (!reply.isValid()) {
0163         qWarning() << reply.error();
0164         return false;
0165     } else {
0166         return true;
0167     }
0168 }
0169 
0170 std::unique_ptr<Akonadi::Monitor> getTestMonitor()
0171 {
0172     auto m = new Akonadi::Monitor();
0173     m->fetchCollection(true);
0174     m->setCollectionMonitored(Akonadi::Collection::root(), true);
0175     m->setAllMonitored(true);
0176     auto &itemFS = m->itemFetchScope();
0177     itemFS.setAncestorRetrieval(Akonadi::ItemFetchScope::All);
0178     auto &colFS = m->collectionFetchScope();
0179     colFS.setAncestorRetrieval(Akonadi::CollectionFetchScope::All);
0180 
0181     QSignalSpy readySpy(m, &Akonadi::Monitor::monitorReady);
0182     readySpy.wait();
0183 
0184     return std::unique_ptr<Akonadi::Monitor>(m);
0185 }
0186 
0187 } // namespace
0188 
0189 /**
0190  * Runs an Akonadi::Job synchronously and aborts if the job failed.
0191  * Similar to QVERIFY( job->exec() ) but includes the job error message
0192  * in the output in case of a failure.
0193  */
0194 #define AKVERIFYEXEC(job) QVERIFY2(job->exec(), job->errorString().toUtf8().constData())