File indexing completed on 2024-05-05 14:06:24
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include <QCoreApplication> 0008 #include <QDBusConnectionInterface> 0009 #include <QObject> 0010 #include <QSignalSpy> 0011 #include <QtTest> 0012 0013 #include "../src/backendmanager_p.h" 0014 #include "../src/config.h" 0015 #include "../src/configmonitor.h" 0016 #include "../src/getconfigoperation.h" 0017 #include "../src/mode.h" 0018 #include "../src/output.h" 0019 #include "../src/setconfigoperation.h" 0020 0021 Q_LOGGING_CATEGORY(KSCREEN, "kscreen") 0022 0023 using namespace KScreen; 0024 0025 class TestInProcess : public QObject 0026 { 0027 Q_OBJECT 0028 0029 public: 0030 explicit TestInProcess(QObject *parent = nullptr); 0031 0032 private Q_SLOTS: 0033 void initTestCase(); 0034 0035 void init(); 0036 void cleanup(); 0037 0038 void loadConfig(); 0039 0040 void testCreateJob(); 0041 void testModeSwitching(); 0042 void testBackendCaching(); 0043 0044 void testConfigApply(); 0045 void testConfigMonitor(); 0046 0047 private: 0048 ConfigPtr m_config; 0049 bool m_backendServiceInstalled = false; 0050 }; 0051 0052 TestInProcess::TestInProcess(QObject *parent) 0053 : QObject(parent) 0054 , m_config(nullptr) 0055 { 0056 } 0057 0058 void TestInProcess::initTestCase() 0059 { 0060 m_backendServiceInstalled = true; 0061 0062 const QString kscreenServiceName = QStringLiteral("org.kde.KScreen"); 0063 QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); 0064 if (!bus->isServiceRegistered(kscreenServiceName)) { 0065 auto reply = bus->startService(kscreenServiceName); 0066 if (!reply.isValid()) { 0067 qDebug() << "D-Bus service org.kde.KScreen could not be started, skipping out-of-process tests"; 0068 m_backendServiceInstalled = false; 0069 } 0070 } 0071 } 0072 0073 void TestInProcess::init() 0074 { 0075 qputenv("KSCREEN_LOGGING", "false"); 0076 // Make sure we do everything in-process 0077 qputenv("KSCREEN_BACKEND_INPROCESS", "1"); 0078 // Use Fake backend with one of the json configs 0079 qputenv("KSCREEN_BACKEND", "Fake"); 0080 0081 KScreen::BackendManager::instance()->shutdownBackend(); 0082 KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "multipleoutput.json"}}); 0083 } 0084 0085 void TestInProcess::cleanup() 0086 { 0087 KScreen::BackendManager::instance()->shutdownBackend(); 0088 } 0089 0090 void TestInProcess::loadConfig() 0091 { 0092 qputenv("KSCREEN_BACKEND_INPROCESS", "1"); 0093 BackendManager::instance()->setMethod(BackendManager::InProcess); 0094 0095 auto *op = new GetConfigOperation(); 0096 QVERIFY(op->exec()); 0097 m_config = op->config(); 0098 QVERIFY(m_config); 0099 QVERIFY(m_config->isValid()); 0100 } 0101 0102 void TestInProcess::testModeSwitching() 0103 { 0104 KScreen::BackendManager::instance()->shutdownBackend(); 0105 BackendManager::instance()->setMethod(BackendManager::InProcess); 0106 // Load QScreen backend in-process 0107 qDebug() << "TT qscreen in-process"; 0108 qputenv("KSCREEN_BACKEND", "QScreen"); 0109 auto op = new GetConfigOperation(); 0110 QVERIFY(op->exec()); 0111 auto oc = op->config(); 0112 QVERIFY(oc != nullptr); 0113 QVERIFY(oc->isValid()); 0114 0115 qDebug() << "TT fake in-process"; 0116 // Load the Fake backend in-process 0117 qputenv("KSCREEN_BACKEND", "Fake"); 0118 auto ip = new GetConfigOperation(); 0119 QVERIFY(ip->exec()); 0120 auto ic = ip->config(); 0121 QVERIFY(ic != nullptr); 0122 QVERIFY(ic->isValid()); 0123 QVERIFY(ic->outputs().count()); 0124 0125 KScreen::ConfigPtr xc(nullptr); 0126 if (m_backendServiceInstalled) { 0127 qDebug() << "TT xrandr out-of-process"; 0128 // Load the xrandr backend out-of-process 0129 qputenv("KSCREEN_BACKEND", "QScreen"); 0130 qputenv("KSCREEN_BACKEND_INPROCESS", "0"); 0131 BackendManager::instance()->setMethod(BackendManager::OutOfProcess); 0132 auto xp = new GetConfigOperation(); 0133 QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); 0134 QVERIFY(xp->exec()); 0135 xc = xp->config(); 0136 QVERIFY(xc != nullptr); 0137 QVERIFY(xc->isValid()); 0138 QVERIFY(xc->outputs().count()); 0139 } 0140 0141 qDebug() << "TT fake in-process"; 0142 0143 qputenv("KSCREEN_BACKEND_INPROCESS", "1"); 0144 BackendManager::instance()->setMethod(BackendManager::InProcess); 0145 // Load the Fake backend in-process 0146 qputenv("KSCREEN_BACKEND", "Fake"); 0147 auto fp = new GetConfigOperation(); 0148 QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); 0149 QVERIFY(fp->exec()); 0150 auto fc = fp->config(); 0151 QVERIFY(fc != nullptr); 0152 QVERIFY(fc->isValid()); 0153 QVERIFY(fc->outputs().count()); 0154 0155 QVERIFY(oc->isValid()); 0156 QVERIFY(ic->isValid()); 0157 if (xc) { 0158 QVERIFY(xc->isValid()); 0159 } 0160 QVERIFY(fc->isValid()); 0161 } 0162 0163 void TestInProcess::testBackendCaching() 0164 { 0165 KScreen::BackendManager::instance()->shutdownBackend(); 0166 qputenv("KSCREEN_BACKEND", "Fake"); 0167 QElapsedTimer t; 0168 BackendManager::instance()->setMethod(BackendManager::InProcess); 0169 QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); 0170 int t_cold; 0171 int t_warm; 0172 0173 { 0174 t.start(); 0175 auto cp = new GetConfigOperation(); 0176 cp->exec(); 0177 auto cc = cp->config(); 0178 t_cold = t.nsecsElapsed(); 0179 QVERIFY(cc != nullptr); 0180 QVERIFY(cc->isValid()); 0181 QVERIFY(cc->outputs().count()); 0182 } 0183 { 0184 // KScreen::BackendManager::instance()->shutdownBackend(); 0185 QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); 0186 t.start(); 0187 auto cp = new GetConfigOperation(); 0188 cp->exec(); 0189 auto cc = cp->config(); 0190 t_warm = t.nsecsElapsed(); 0191 QVERIFY(cc != nullptr); 0192 QVERIFY(cc->isValid()); 0193 QVERIFY(cc->outputs().count()); 0194 } 0195 { 0196 auto cp = new GetConfigOperation(); 0197 QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); 0198 cp->exec(); 0199 auto cc = cp->config(); 0200 QVERIFY(cc != nullptr); 0201 QVERIFY(cc->isValid()); 0202 QVERIFY(cc->outputs().count()); 0203 } 0204 // Check if all our configs are still valid after the backend is gone 0205 KScreen::BackendManager::instance()->shutdownBackend(); 0206 0207 if (m_backendServiceInstalled) { 0208 // qputenv("KSCREEN_BACKEND", "QScreen"); 0209 qputenv("KSCREEN_BACKEND_INPROCESS", "0"); 0210 BackendManager::instance()->setMethod(BackendManager::OutOfProcess); 0211 QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); 0212 int t_x_cold; 0213 0214 { 0215 t.start(); 0216 auto xp = new GetConfigOperation(); 0217 xp->exec(); 0218 t_x_cold = t.nsecsElapsed(); 0219 auto xc = xp->config(); 0220 QVERIFY(xc != nullptr); 0221 } 0222 t.start(); 0223 auto xp = new GetConfigOperation(); 0224 xp->exec(); 0225 int t_x_warm = t.nsecsElapsed(); 0226 auto xc = xp->config(); 0227 QVERIFY(xc != nullptr); 0228 0229 // Make sure in-process is faster 0230 QVERIFY(t_cold > t_warm); 0231 QVERIFY(t_x_cold > t_x_warm); 0232 QVERIFY(t_x_cold > t_cold); 0233 return; 0234 qDebug() << "ip speedup for cached access:" << (qreal)((qreal)t_cold / (qreal)t_warm); 0235 qDebug() << "oop speedup for cached access:" << (qreal)((qreal)t_x_cold / (qreal)t_x_warm); 0236 qDebug() << "out-of vs. in-process speedup:" << (qreal)((qreal)t_x_warm / (qreal)t_warm); 0237 qDebug() << "cold oop: " << ((qreal)t_x_cold / 1000000); 0238 qDebug() << "cached oop: " << ((qreal)t_x_warm / 1000000); 0239 qDebug() << "cold in process: " << ((qreal)t_cold / 1000000); 0240 qDebug() << "cached in process: " << ((qreal)t_warm / 1000000); 0241 } 0242 } 0243 0244 void TestInProcess::testCreateJob() 0245 { 0246 KScreen::BackendManager::instance()->shutdownBackend(); 0247 { 0248 BackendManager::instance()->setMethod(BackendManager::InProcess); 0249 auto op = new GetConfigOperation(); 0250 auto _op = qobject_cast<GetConfigOperation *>(op); 0251 QVERIFY(_op != nullptr); 0252 QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); 0253 QVERIFY(op->exec()); 0254 auto cc = op->config(); 0255 QVERIFY(cc != nullptr); 0256 QVERIFY(cc->isValid()); 0257 } 0258 if (m_backendServiceInstalled) { 0259 BackendManager::instance()->setMethod(BackendManager::OutOfProcess); 0260 auto op = new GetConfigOperation(); 0261 auto _op = qobject_cast<GetConfigOperation *>(op); 0262 QVERIFY(_op != nullptr); 0263 QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); 0264 QVERIFY(op->exec()); 0265 auto cc = op->config(); 0266 QVERIFY(cc != nullptr); 0267 QVERIFY(cc->isValid()); 0268 } 0269 KScreen::BackendManager::instance()->shutdownBackend(); 0270 BackendManager::instance()->setMethod(BackendManager::InProcess); 0271 } 0272 0273 void TestInProcess::testConfigApply() 0274 { 0275 qputenv("KSCREEN_BACKEND", "Fake"); 0276 KScreen::BackendManager::instance()->shutdownBackend(); 0277 BackendManager::instance()->setMethod(BackendManager::InProcess); 0278 auto op = new GetConfigOperation(); 0279 op->exec(); 0280 auto config = op->config(); 0281 // qDebug() << "op:" << config->outputs().count(); 0282 auto output = config->outputs().first(); 0283 // qDebug() << "res:" << output->geometry(); 0284 // qDebug() << "modes:" << output->modes(); 0285 auto m0 = output->modes().first(); 0286 // qDebug() << "m0:" << m0->id() << m0; 0287 output->setCurrentModeId(m0->id()); 0288 QVERIFY(Config::canBeApplied(config)); 0289 0290 // expected to fail, SetConfigOperation is out-of-process only 0291 auto setop = new SetConfigOperation(config); 0292 QVERIFY(!setop->hasError()); 0293 QVERIFY(setop->exec()); 0294 0295 QVERIFY(!setop->hasError()); 0296 } 0297 0298 void TestInProcess::testConfigMonitor() 0299 { 0300 qputenv("KSCREEN_BACKEND", "Fake"); 0301 0302 KScreen::BackendManager::instance()->shutdownBackend(); 0303 BackendManager::instance()->setMethod(BackendManager::InProcess); 0304 auto op = new GetConfigOperation(); 0305 op->exec(); 0306 auto config = op->config(); 0307 // qDebug() << "op:" << config->outputs().count(); 0308 auto output = config->outputs().first(); 0309 // qDebug() << "res:" << output->geometry(); 0310 // qDebug() << "modes:" << output->modes(); 0311 auto m0 = output->modes().first(); 0312 // qDebug() << "m0:" << m0->id() << m0; 0313 output->setCurrentModeId(m0->id()); 0314 QVERIFY(Config::canBeApplied(config)); 0315 0316 QSignalSpy monitorSpy(ConfigMonitor::instance(), &ConfigMonitor::configurationChanged); 0317 qDebug() << "MOnitorspy connencted."; 0318 ConfigMonitor::instance()->addConfig(config); 0319 0320 auto setop = new SetConfigOperation(config); 0321 QVERIFY(!setop->hasError()); 0322 // do not cal setop->exec(), this must not block as the signalspy already blocks 0323 QVERIFY(monitorSpy.wait(500)); 0324 } 0325 0326 QTEST_GUILESS_MAIN(TestInProcess) 0327 0328 #include "testinprocess.moc"