kwin/autotests/integration/xwaylandserver_restart_test.cpp
2023-11-28 10:02:03 +00:00

116 lines
3.8 KiB
C++

/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "compositor.h"
#include "main.h"
#include "scene/workspacescene.h"
#include "wayland_server.h"
#include "workspace.h"
#include "x11window.h"
#include "xwayland/xwayland.h"
#include "xwayland/xwaylandlauncher.h"
#include <xcb/xcb_icccm.h>
namespace KWin
{
static const QString s_socketName = QStringLiteral("wayland_test_kwin_xwayland_server_restart-0");
class XwaylandServerRestartTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testRestart();
};
void XwaylandServerRestartTest::initTestCase()
{
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
KConfigGroup xwaylandGroup = config->group(QStringLiteral("Xwayland"));
xwaylandGroup.writeEntry(QStringLiteral("XwaylandCrashPolicy"), QStringLiteral("Restart"));
xwaylandGroup.sync();
kwinApp()->setConfig(config);
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
}
static void kwin_safe_kill(QProcess *process)
{
// The SIGKILL signal must be sent when the event loop is spinning.
QTimer::singleShot(1, process, &QProcess::kill);
}
void XwaylandServerRestartTest::testRestart()
{
// This test verifies that the Xwayland server will be restarted after a crash.
Xwl::Xwayland *xwayland = static_cast<Xwl::Xwayland *>(kwinApp()->xwayland());
QSignalSpy startedSpy(xwayland, &Xwl::Xwayland::started);
QSignalSpy stoppedSpy(xwayland, &Xwl::Xwayland::errorOccurred);
Test::createX11Connection(); // trigger an X11 start
QTRY_COMPARE(startedSpy.count(), 1);
// Pretend that the Xwayland process has crashed by sending a SIGKILL to it.
kwin_safe_kill(xwayland->xwaylandLauncher()->process());
QTRY_COMPARE(stoppedSpy.count(), 1);
// Check that the compositor still accepts new X11 clients.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
QTRY_COMPARE(startedSpy.count(), 2);
const QRect rect(0, 0, 100, 200);
xcb_window_t windowId = xcb_generate_id(c.get());
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
rect.x(), rect.y(), rect.width(), rect.height(), 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, rect.x(), rect.y());
xcb_icccm_size_hints_set_size(&hints, 1, rect.width(), rect.height());
xcb_icccm_size_hints_set_min_size(&hints, rect.width(), rect.height());
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
xcb_map_window(c.get(), windowId);
xcb_flush(c.get());
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
QVERIFY(windowCreatedSpy.wait());
X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(window->isDecorated());
// Render a frame to ensure that the compositor doesn't crash.
Compositor::self()->scene()->addRepaintFull();
QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &WorkspaceScene::frameRendered);
QVERIFY(frameRenderedSpy.wait());
// Destroy the test window.
xcb_destroy_window(c.get(), windowId);
xcb_flush(c.get());
QVERIFY(Test::waitForWindowClosed(window));
}
} // namespace KWin
WAYLANDTEST_MAIN(KWin::XwaylandServerRestartTest)
#include "xwaylandserver_restart_test.moc"