Warning, file /plasma/kwin/autotests/integration/xwaylandserver_restart_test.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kwin_wayland_test.h"
0008 
0009 #include "composite.h"
0010 #include "core/outputbackend.h"
0011 #include "main.h"
0012 #include "scene/workspacescene.h"
0013 #include "wayland_server.h"
0014 #include "workspace.h"
0015 #include "x11window.h"
0016 #include "xwayland/xwayland.h"
0017 #include "xwayland/xwaylandlauncher.h"
0018 
0019 #include <xcb/xcb_icccm.h>
0020 
0021 namespace KWin
0022 {
0023 
0024 struct XcbConnectionDeleter
0025 {
0026     void operator()(xcb_connection_t *pointer)
0027     {
0028         xcb_disconnect(pointer);
0029     }
0030 };
0031 
0032 static const QString s_socketName = QStringLiteral("wayland_test_kwin_xwayland_server_restart-0");
0033 
0034 class XwaylandServerRestartTest : public QObject
0035 {
0036     Q_OBJECT
0037 
0038 private Q_SLOTS:
0039     void initTestCase();
0040     void testRestart();
0041 };
0042 
0043 void XwaylandServerRestartTest::initTestCase()
0044 {
0045     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0046     QVERIFY(waylandServer()->init(s_socketName));
0047     QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024)));
0048 
0049     KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0050     KConfigGroup xwaylandGroup = config->group("Xwayland");
0051     xwaylandGroup.writeEntry(QStringLiteral("XwaylandCrashPolicy"), QStringLiteral("Restart"));
0052     xwaylandGroup.sync();
0053     kwinApp()->setConfig(config);
0054 
0055     kwinApp()->start();
0056     QVERIFY(applicationStartedSpy.wait());
0057 }
0058 
0059 static void kwin_safe_kill(QProcess *process)
0060 {
0061     // The SIGKILL signal must be sent when the event loop is spinning.
0062     QTimer::singleShot(1, process, &QProcess::kill);
0063 }
0064 
0065 void XwaylandServerRestartTest::testRestart()
0066 {
0067     // This test verifies that the Xwayland server will be restarted after a crash.
0068 
0069     Xwl::Xwayland *xwayland = static_cast<Xwl::Xwayland *>(kwinApp()->xwayland());
0070 
0071     // Pretend that the Xwayland process has crashed by sending a SIGKILL to it.
0072     QSignalSpy startedSpy(xwayland, &Xwl::Xwayland::started);
0073     kwin_safe_kill(xwayland->xwaylandLauncher()->process());
0074     QVERIFY(startedSpy.wait());
0075     QCOMPARE(startedSpy.count(), 1);
0076 
0077     // Check that the compositor still accepts new X11 clients.
0078     std::unique_ptr<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
0079     QVERIFY(!xcb_connection_has_error(c.get()));
0080     const QRect rect(0, 0, 100, 200);
0081     xcb_window_t windowId = xcb_generate_id(c.get());
0082     xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
0083                       rect.x(), rect.y(), rect.width(), rect.height(), 0,
0084                       XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
0085     xcb_size_hints_t hints;
0086     memset(&hints, 0, sizeof(hints));
0087     xcb_icccm_size_hints_set_position(&hints, 1, rect.x(), rect.y());
0088     xcb_icccm_size_hints_set_size(&hints, 1, rect.width(), rect.height());
0089     xcb_icccm_size_hints_set_min_size(&hints, rect.width(), rect.height());
0090     xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
0091     xcb_map_window(c.get(), windowId);
0092     xcb_flush(c.get());
0093 
0094     QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
0095     QVERIFY(windowCreatedSpy.wait());
0096     X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
0097     QVERIFY(window);
0098     QCOMPARE(window->window(), windowId);
0099     QVERIFY(window->isDecorated());
0100 
0101     // Render a frame to ensure that the compositor doesn't crash.
0102     Compositor::self()->scene()->addRepaintFull();
0103     QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &WorkspaceScene::frameRendered);
0104     QVERIFY(frameRenderedSpy.wait());
0105 
0106     // Destroy the test window.
0107     xcb_destroy_window(c.get(), windowId);
0108     xcb_flush(c.get());
0109     QVERIFY(Test::waitForWindowDestroyed(window));
0110 }
0111 
0112 } // namespace KWin
0113 
0114 WAYLANDTEST_MAIN(KWin::XwaylandServerRestartTest)
0115 #include "xwaylandserver_restart_test.moc"