File indexing completed on 2024-05-12 05:19:11

0001 /* This file is part of Kleopatra
0002 
0003    SPDX-FileCopyrightText: 2016 Intevation GmbH
0004 
0005    It is based on libkdbus kdbusservicetest which is:
0006 
0007    SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
0008    SPDX-FileCopyrightText: 2011 David Faure <faure@kde.org>
0009    SPDX-FileCopyrightText: 2011 Kevin Ottens <ervin@kde.org>
0010 
0011    SPDX-License-Identifier: LGPL-2.0-only
0012 */
0013 
0014 /* The main modification in this test is that every activateRequested
0015  * call needs to set the exit code to signal the application it's done. */
0016 
0017 #include <QCoreApplication>
0018 #include <QDebug>
0019 #include <QDir>
0020 #include <QFile>
0021 #include <QMetaObject>
0022 #include <QProcess>
0023 #include <QTimer>
0024 
0025 #include "utils/kuniqueservice.h"
0026 
0027 #include <chrono>
0028 #include <stdio.h>
0029 using namespace std::chrono_literals;
0030 
0031 class TestObject : public QObject
0032 {
0033     Q_OBJECT
0034 public:
0035     TestObject(KUniqueService *service)
0036         : m_proc(nullptr)
0037         , m_callCount(0)
0038         , m_service(service)
0039     {
0040     }
0041 
0042     ~TestObject() override
0043     {
0044         if (m_proc) {
0045             m_proc->waitForFinished();
0046         }
0047     }
0048 
0049     int callCount() const
0050     {
0051         return m_callCount;
0052     }
0053 
0054 private Q_SLOTS:
0055     void slotActivateRequested(const QStringList &args, const QString &workingDirectory)
0056     {
0057         Q_UNUSED(workingDirectory)
0058         qDebug() << "Application executed with args" << args;
0059 
0060         ++m_callCount;
0061 
0062         if (m_callCount == 1) {
0063             Q_ASSERT(args.count() == 1);
0064             Q_ASSERT(args.at(0) == QLatin1StringView("dummy call"));
0065             m_service->setExitValue(0);
0066         } else if (m_callCount == 2) {
0067             Q_ASSERT(args.count() == 2);
0068             Q_ASSERT(args.at(1) == QLatin1StringView("bad call"));
0069             m_service->setExitValue(4);
0070         } else if (m_callCount == 3) {
0071             Q_ASSERT(args.count() == 3);
0072             Q_ASSERT(args.at(1) == QLatin1StringView("real call"));
0073             Q_ASSERT(args.at(2) == QLatin1StringView("second arg"));
0074             m_service->setExitValue(0);
0075             // OK, all done, quit
0076             QCoreApplication::instance()->quit();
0077         }
0078     }
0079 
0080     void slotProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
0081     {
0082         Q_UNUSED(exitStatus)
0083         qDebug() << "Process exited with code" << exitCode;
0084         m_proc = nullptr;
0085         if (m_callCount == 2) {
0086             Q_ASSERT(exitCode == 4);
0087             secondCall();
0088         }
0089     }
0090 
0091     void firstCall()
0092     {
0093         QStringList args;
0094         args << QStringLiteral("bad call");
0095         executeNewChild(args);
0096     }
0097 
0098     void secondCall()
0099     {
0100         QStringList args;
0101         args << QStringLiteral("real call") << QStringLiteral("second arg");
0102         executeNewChild(args);
0103     }
0104 
0105 private:
0106     void executeNewChild(const QStringList &args)
0107     {
0108         // Duplicated from kglobalsettingstest.cpp - make a shared helper method?
0109         m_proc = new QProcess(this);
0110         connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotProcessFinished(int, QProcess::ExitStatus)));
0111         QString appName = QStringLiteral("kuniqueservicetest");
0112 #ifdef Q_OS_WIN
0113         appName += QStringLiteral(".exe");
0114 #else
0115         if (QFile::exists(appName + QStringLiteral(".shell"))) {
0116             appName = QStringLiteral("./") + appName + QStringLiteral(".shell");
0117         } else if (QFile::exists(QCoreApplication::applicationFilePath())) {
0118             appName = QCoreApplication::applicationFilePath();
0119         } else {
0120             Q_ASSERT(QFile::exists(appName));
0121             appName = QStringLiteral("./") + appName;
0122         }
0123 #endif
0124         qDebug() << "about to run" << appName << args;
0125         m_proc->start(appName, args);
0126     }
0127 
0128     QProcess *m_proc;
0129     int m_callCount;
0130     KUniqueService *m_service;
0131 };
0132 
0133 int main(int argc, char *argv[])
0134 {
0135     QCoreApplication a(argc, argv);
0136 
0137     QCoreApplication::setApplicationName(QStringLiteral("kuniqueservicetest"));
0138     QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
0139 
0140     KUniqueService service;
0141     TestObject testObject(&service);
0142     QObject::connect(&service, SIGNAL(activateRequested(QStringList, QString)), &testObject, SLOT(slotActivateRequested(QStringList, QString)));
0143 
0144     // Testcase for the problem coming from the old fork-on-startup solution:
0145     // the "Activate" D-Bus call would time out if the app took too much time
0146     // to be ready.
0147     // printf("Sleeping.\n");
0148     // sleep(200);
0149     QStringList args;
0150     args << QStringLiteral("dummy call");
0151 
0152     QMetaObject::invokeMethod(&service, "activateRequested", Qt::QueuedConnection, Q_ARG(QStringList, args), Q_ARG(QString, QDir::currentPath()));
0153     QTimer::singleShot(400ms, &testObject, SLOT(firstCall()));
0154 
0155     qDebug() << "Running.";
0156     a.exec();
0157     qDebug() << "Terminating.";
0158 
0159     Q_ASSERT(testObject.callCount() == 3);
0160     const bool ok = testObject.callCount() == 3;
0161 
0162     return ok ? 0 : 1;
0163 }
0164 
0165 #include "kuniqueservicetest.moc"