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