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"