File indexing completed on 2024-04-28 05:50:34
0001 /* 0002 SPDX-FileCopyrightText: 2010 Kurt Hindenburg <kurt.hindenburg@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own 0008 #include "DBusTest.h" 0009 #include "../profile/Profile.h" 0010 #include "../profile/ProfileWriter.h" 0011 #include "../session/Session.h" 0012 0013 // Qt 0014 #include <QProcess> 0015 #include <QRandomGenerator> 0016 #include <QSignalSpy> 0017 #include <QStandardPaths> 0018 0019 using namespace Konsole; 0020 0021 /* Exec a new Konsole and grab its dbus */ 0022 void DBusTest::initTestCase() 0023 { 0024 qRegisterMetaType<QProcess::ExitStatus>(); 0025 0026 const QString interfaceName = QStringLiteral("org.kde.konsole"); 0027 QDBusConnectionInterface *bus = nullptr; 0028 QStringList konsoleServices; 0029 0030 if (!QDBusConnection::sessionBus().isConnected() || ((bus = QDBusConnection::sessionBus().interface()) == nullptr)) { 0031 QFAIL("Session bus not found"); 0032 } 0033 0034 QDBusReply<QStringList> serviceReply = bus->registeredServiceNames(); 0035 QVERIFY2(serviceReply.isValid(), "SessionBus interfaces not available"); 0036 0037 // Find all current Konsoles' services running 0038 QStringList allServices = serviceReply; 0039 for (QStringList::const_iterator it = allServices.constBegin(), end = allServices.constEnd(); it != end; ++it) { 0040 const QString service = *it; 0041 if (service.startsWith(interfaceName)) { 0042 konsoleServices << service; 0043 } 0044 } 0045 0046 // Create test profile 0047 auto profile = Profile::Ptr(new Profile()); 0048 ProfileWriter profileWriter; 0049 0050 do { 0051 _testProfileName = QStringLiteral("konsole-dbus-test-profile-%1").arg(QRandomGenerator::global()->generate()); 0052 profile->setProperty(Profile::UntranslatedName, _testProfileName); 0053 profile->setProperty(Profile::Name, _testProfileName); 0054 _testProfilePath = profileWriter.getPath(profile); 0055 } while (QFile::exists(_testProfilePath)); 0056 _testProfileEnv = QStringLiteral("TEST_PROFILE=%1").arg(_testProfileName); 0057 profile->setProperty(Profile::Environment, QStringList(_testProfileEnv)); 0058 // %D = Current Directory (Long) - hacky way to check current directory 0059 profile->setProperty(Profile::LocalTabTitleFormat, QStringLiteral("%D")); 0060 profileWriter.writeProfile(_testProfilePath, profile); 0061 0062 // Create a new Konsole with a separate process id 0063 _process = new QProcess; 0064 _process->setProcessChannelMode(QProcess::ForwardedChannels); 0065 _process->start(QStringLiteral("konsole"), QStringList(QStringLiteral("--separate"))); 0066 0067 if (!_process->waitForStarted()) { 0068 QFAIL(QStringLiteral("Unable to exec a new Konsole").toLatin1().data()); 0069 } 0070 0071 // Wait for above Konsole to finish starting 0072 QThread::sleep(5); 0073 0074 serviceReply = bus->registeredServiceNames(); 0075 QVERIFY2(serviceReply.isValid(), "SessionBus interfaces not available"); 0076 0077 // Find dbus service of above Konsole 0078 allServices = serviceReply; 0079 for (QStringList::const_iterator it = allServices.constBegin(), end = allServices.constEnd(); it != end; ++it) { 0080 const QString service = *it; 0081 if (service.startsWith(interfaceName)) { 0082 if (!konsoleServices.contains(service)) { 0083 _interfaceName = service; 0084 } 0085 } 0086 } 0087 0088 QVERIFY2(!_interfaceName.isEmpty(), "This test will only work in a Konsole window with a new PID. A new Konsole PID can't be found."); 0089 0090 QDBusInterface iface(_interfaceName, QStringLiteral("/Windows/1"), QStringLiteral("org.kde.konsole.Konsole")); 0091 QVERIFY(iface.isValid()); 0092 } 0093 0094 /* Close the Konsole window that was opened to test the DBus interface 0095 */ 0096 void DBusTest::cleanupTestCase() 0097 { 0098 // Remove test profile 0099 QFile::remove(_testProfilePath); 0100 0101 // Need to take care of when user has CloseAllTabs=False otherwise 0102 // they will get a popup dialog when we try to close this. 0103 QSignalSpy quitSpy(_process, SIGNAL(finished(int, QProcess::ExitStatus))); 0104 0105 // Do not use QWidget::close(), as it shows question popup when 0106 // CloseAllTabs is set to false (default). 0107 QDBusInterface iface(_interfaceName, QStringLiteral("/MainApplication"), QStringLiteral("org.qtproject.Qt.QCoreApplication")); 0108 QVERIFY2(iface.isValid(), "Unable to get a dbus interface to Konsole!"); 0109 0110 QDBusReply<void> instanceReply = iface.call(QStringLiteral("quit")); 0111 if (!instanceReply.isValid()) { 0112 QFAIL(QStringLiteral("Unable to close Konsole: %1").arg(instanceReply.error().message()).toLatin1().data()); 0113 } 0114 quitSpy.wait(); 0115 _process->kill(); 0116 _process->deleteLater(); 0117 } 0118 0119 void DBusTest::testSessions() 0120 { 0121 QDBusReply<void> voidReply; 0122 QDBusReply<bool> boolReply; 0123 QDBusReply<QByteArray> arrayReply; 0124 QDBusReply<QString> stringReply; 0125 QDBusReply<QStringList> listReply; 0126 0127 QDBusInterface iface(_interfaceName, QStringLiteral("/Sessions/1"), QStringLiteral("org.kde.konsole.Session")); 0128 QVERIFY(iface.isValid()); 0129 0130 //****************** Test is/set MonitorActivity 0131 voidReply = iface.call(QStringLiteral("setMonitorActivity"), false); 0132 QVERIFY(voidReply.isValid()); 0133 0134 boolReply = iface.call(QStringLiteral("isMonitorActivity")); 0135 QVERIFY(boolReply.isValid()); 0136 QCOMPARE(boolReply.value(), false); 0137 0138 voidReply = iface.call(QStringLiteral("setMonitorActivity"), true); 0139 QVERIFY(voidReply.isValid()); 0140 0141 boolReply = iface.call(QStringLiteral("isMonitorActivity")); 0142 QVERIFY(boolReply.isValid()); 0143 QCOMPARE(boolReply.value(), true); 0144 0145 //****************** Test is/set MonitorSilence 0146 voidReply = iface.call(QStringLiteral("setMonitorSilence"), false); 0147 QVERIFY(voidReply.isValid()); 0148 0149 boolReply = iface.call(QStringLiteral("isMonitorSilence")); 0150 QVERIFY(boolReply.isValid()); 0151 QCOMPARE(boolReply.value(), false); 0152 0153 voidReply = iface.call(QStringLiteral("setMonitorSilence"), true); 0154 QVERIFY(voidReply.isValid()); 0155 0156 boolReply = iface.call(QStringLiteral("isMonitorSilence")); 0157 QVERIFY(boolReply.isValid()); 0158 QCOMPARE(boolReply.value(), true); 0159 0160 //****************** Test codec and setCodec 0161 arrayReply = iface.call(QStringLiteral("codec")); 0162 QVERIFY(arrayReply.isValid()); 0163 0164 // Obtain a list of system's Codecs 0165 QList<QByteArray> availableCodecs = QTextCodec::availableCodecs(); 0166 for (int i = 0; i < availableCodecs.count(); ++i) { 0167 boolReply = iface.call(QStringLiteral("setCodec"), availableCodecs[i]); 0168 QVERIFY(boolReply.isValid()); 0169 QCOMPARE(boolReply.value(), true); 0170 0171 arrayReply = iface.call(QStringLiteral("codec")); 0172 QVERIFY(arrayReply.isValid()); 0173 // Compare result with name due to aliases issue 0174 // Better way to do this? 0175 QCOMPARE((QTextCodec::codecForName(arrayReply.value()))->name(), (QTextCodec::codecForName(availableCodecs[i]))->name()); 0176 } 0177 0178 //****************** Test is/set flowControlEnabled 0179 voidReply = iface.call(QStringLiteral("setFlowControlEnabled"), true); 0180 QVERIFY(voidReply.isValid()); 0181 0182 boolReply = iface.call(QStringLiteral("flowControlEnabled")); 0183 QVERIFY(boolReply.isValid()); 0184 QCOMPARE(boolReply.value(), true); 0185 0186 voidReply = iface.call(QStringLiteral("setFlowControlEnabled"), false); 0187 QVERIFY(voidReply.isValid()); 0188 0189 boolReply = iface.call(QStringLiteral("flowControlEnabled")); 0190 QVERIFY(boolReply.isValid()); 0191 QCOMPARE(boolReply.value(), false); 0192 0193 //****************** Test is/set environment 0194 listReply = iface.call(QStringLiteral("environment")); 0195 QVERIFY(listReply.isValid()); 0196 0197 QStringList prevEnv = listReply.value(); 0198 // for (int i = 0; i < prevEnv.size(); ++i) 0199 // qDebug()<< prevEnv.at(i).toLocal8Bit().constData() << endl; 0200 0201 voidReply = iface.call(QStringLiteral("setEnvironment"), QStringList()); 0202 QVERIFY(voidReply.isValid()); 0203 0204 listReply = iface.call(QStringLiteral("environment")); 0205 QVERIFY(listReply.isValid()); 0206 QCOMPARE(listReply.value(), QStringList()); 0207 0208 voidReply = iface.call(QStringLiteral("setEnvironment"), prevEnv); 0209 QVERIFY(voidReply.isValid()); 0210 0211 listReply = iface.call(QStringLiteral("environment")); 0212 QVERIFY(listReply.isValid()); 0213 QCOMPARE(listReply.value(), prevEnv); 0214 0215 //****************** Test is/set title 0216 // TODO: Consider checking what is in Profile 0217 stringReply = iface.call(QStringLiteral("title"), Session::NameRole); 0218 QVERIFY(stringReply.isValid()); 0219 0220 // set title to, what title should be 0221 QMap<QString, QString> titleMap; 0222 titleMap[QStringLiteral("Shell")] = QStringLiteral("Shell"); 0223 0224 // BUG: It appears that Session::LocalTabTitle is set to Shell and 0225 // doesn't change. While RemoteTabTitle is actually the LocalTabTitle 0226 // TODO: Figure out what's going on... 0227 QMapIterator<QString, QString> i(titleMap); 0228 while (i.hasNext()) { 0229 i.next(); 0230 voidReply = iface.call(QStringLiteral("setTitle"), Session::NameRole, i.key()); 0231 QVERIFY(voidReply.isValid()); 0232 0233 stringReply = iface.call(QStringLiteral("title"), Session::NameRole); 0234 QVERIFY(stringReply.isValid()); 0235 0236 QCOMPARE(stringReply.value(), i.value()); 0237 } 0238 } 0239 0240 void DBusTest::testWindows() 0241 { 0242 // Tested functions: 0243 // [+] int sessionCount(); 0244 // [+] QStringList sessionList(); 0245 // [+] int currentSession(); 0246 // [+] void setCurrentSession(int sessionId); 0247 // [+] int newSession(); 0248 // [+] int newSession(const QString &profile); 0249 // [+] int newSession(const QString &profile, const QString &directory); 0250 // [ ] QString defaultProfile(); 0251 // [ ] QStringList profileList(); 0252 // [ ] void nextSession(); 0253 // [ ] void prevSession(); 0254 // [ ] void moveSessionLeft(); 0255 // [ ] void moveSessionRight(); 0256 // [ ] void setTabWidthToText(bool); 0257 0258 QDBusReply<int> intReply; 0259 QDBusReply<QStringList> listReply; 0260 QDBusReply<void> voidReply; 0261 QDBusReply<QString> stringReply; 0262 0263 int sessionCount = -1; 0264 int initialSessionId = -1; 0265 0266 QDBusInterface iface(_interfaceName, QStringLiteral("/Windows/1"), QStringLiteral("org.kde.konsole.Window")); 0267 QVERIFY(iface.isValid()); 0268 0269 intReply = iface.call(QStringLiteral("sessionCount")); 0270 QVERIFY(intReply.isValid()); 0271 sessionCount = intReply.value(); 0272 QVERIFY(sessionCount > 0); 0273 0274 intReply = iface.call(QStringLiteral("currentSession")); 0275 QVERIFY(intReply.isValid()); 0276 initialSessionId = intReply.value(); 0277 0278 intReply = iface.call(QStringLiteral("newSession")); 0279 QVERIFY(intReply.isValid()); 0280 ++sessionCount; 0281 int newSessionId = intReply.value(); 0282 QVERIFY(newSessionId != initialSessionId); 0283 0284 listReply = iface.call(QStringLiteral("sessionList")); 0285 QVERIFY(listReply.isValid()); 0286 0287 QStringList sessions = listReply.value(); 0288 QVERIFY(sessions.contains(QString::number(initialSessionId))); 0289 QVERIFY(sessions.contains(QString::number(newSessionId))); 0290 QVERIFY(sessions.size() == sessionCount); 0291 0292 intReply = iface.call(QStringLiteral("newSession"), _testProfileName); 0293 QVERIFY(intReply.isValid()); 0294 ++sessionCount; 0295 newSessionId = intReply.value(); 0296 QVERIFY(newSessionId != initialSessionId); 0297 { 0298 QDBusInterface sessionIface(_interfaceName, QStringLiteral("/Sessions/%1").arg(newSessionId), QStringLiteral("org.kde.konsole.Session")); 0299 QVERIFY(iface.isValid()); 0300 0301 listReply = sessionIface.call(QStringLiteral("environment")); 0302 QVERIFY(listReply.isValid()); 0303 QStringList env = listReply.value(); 0304 QVERIFY(env.contains(_testProfileEnv)); 0305 } 0306 0307 const auto tempDirectories = QStandardPaths::standardLocations(QStandardPaths::TempLocation); 0308 const QString sessionDirectory = tempDirectories.empty() ? QStringLiteral("/") : tempDirectories.constFirst(); 0309 intReply = iface.call(QStringLiteral("newSession"), _testProfileName, sessionDirectory); 0310 QVERIFY(intReply.isValid()); 0311 ++sessionCount; 0312 newSessionId = intReply.value(); 0313 QVERIFY(newSessionId != initialSessionId); 0314 { 0315 QDBusInterface sessionIface(_interfaceName, QStringLiteral("/Sessions/%1").arg(newSessionId), QStringLiteral("org.kde.konsole.Session")); 0316 QVERIFY(iface.isValid()); 0317 0318 listReply = sessionIface.call(QStringLiteral("environment")); 0319 QVERIFY(listReply.isValid()); 0320 QStringList env = listReply.value(); 0321 QVERIFY(env.contains(_testProfileEnv)); 0322 0323 // Apparently there's no function for checking CWD. 0324 // The profile uses "%D" as title format, so check the title 0325 stringReply = sessionIface.call(QStringLiteral("title"), Session::DisplayedTitleRole); 0326 QVERIFY(stringReply.isValid()); 0327 QVERIFY(QDir(stringReply.value()) == QDir(sessionDirectory)); 0328 } 0329 0330 voidReply = iface.call(QStringLiteral("setCurrentSession"), initialSessionId); 0331 QVERIFY(voidReply.isValid()); 0332 0333 intReply = iface.call(QStringLiteral("currentSession")); 0334 QVERIFY(intReply.isValid()); 0335 QVERIFY(intReply.value() == initialSessionId); 0336 0337 intReply = iface.call(QStringLiteral("sessionCount")); 0338 QVERIFY(intReply.isValid()); 0339 QVERIFY(intReply.value() == sessionCount); 0340 } 0341 0342 QTEST_MAIN(DBusTest) 0343 0344 #include "moc_DBusTest.cpp"