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"