summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2022-01-06 14:51:42 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2022-01-19 14:22:52 +0100
commitd292f0143f05439e70d0af6152befa0e32487226 (patch)
tree585da0cae77fa36e0e29d21fa43381a3c76a9f41 /tests/auto
parentb07e5fcd1ba701df0d5e88661f385e7c3d5e22ef (diff)
Add more tests for event dispatcher waking up
Add two tests for some problematic scenarios where the behavior is not consistent across platforms and depending on which event dispatcher is used: 1) reliably waking up the dispatcher when posting events from a worker thread. That test fails 100% of the time on Windows no matter what type of application is created. It passes reliably on Linux and macOS for both core and gui applications. 2) waking up the dispatcher when we post an event from within an event handler. That test fails 100% of the time on Windows, both with core and GUI event dispatchers. On macOS, the test fails 100% of the time with the core dispatcher, and passes 100% of the time with the GUI dispatcher. On Linux, it passes only if a Glib based event dispatcher is used; the default Unix event dispatcher (which is also the one used on macOS for core applications) fails. Task-number: QTBUG-99323 Pick-to: 6.2 6.3 5.15 Change-Id: I2489533b9f0032488707777be0512bb933669a7d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alex Trotsenko <alex1973tr@gmail.com>
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp112
1 files changed, 111 insertions, 1 deletions
diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
index 9ef6c79bba..aea1c7ec9b 100644
--- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
+++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
@@ -35,6 +35,7 @@
#include <QTest>
#include <QAbstractEventDispatcher>
#include <QTimer>
+#include <QThreadPool>
enum {
PreciseTimerInterval = 10,
@@ -58,20 +59,29 @@ protected:
public:
inline tst_QEventDispatcher()
: QObject(),
- eventDispatcher(QAbstractEventDispatcher::instance(thread()))
+ eventDispatcher(QAbstractEventDispatcher::instance(thread())),
+ isGuiEventDispatcher(QCoreApplication::instance()->inherits("QGuiApplication"))
{ }
private slots:
void initTestCase();
void registerTimer();
+
/* void registerSocketNotifier(); */ // Not implemented here, see tst_QSocketNotifier instead
/* void registerEventNotifiier(); */ // Not implemented here, see tst_QWinEventNotifier instead
void sendPostedEvents_data();
void sendPostedEvents();
void processEventsOnlySendsQueuedEvents();
+ // these two tests need to run before postedEventsPingPong
+ void postEventFromThread();
+ void postEventFromEventHandler();
+ // these tests don't leave the event dispatcher in a reliable state
void postedEventsPingPong();
void eventLoopExit();
void interruptTrampling();
+
+private:
+ const bool isGuiEventDispatcher;
};
bool tst_QEventDispatcher::event(QEvent *e)
@@ -353,6 +363,106 @@ void tst_QEventDispatcher::processEventsOnlySendsQueuedEvents()
QCOMPARE(object.eventsReceived, 4);
}
+void tst_QEventDispatcher::postEventFromThread()
+{
+ QThreadPool *threadPool = QThreadPool::globalInstance();
+ QAtomicInt hadToQuit = false;
+ QAtomicInt done = false;
+
+ threadPool->start([&]{
+ int loop = 1000 / 10; // give it a second
+ while (!done && --loop)
+ QThread::msleep(10);
+ if (done)
+ return;
+ hadToQuit = true;
+ QCoreApplication::eventDispatcher()->wakeUp();
+ });
+
+ struct EventReceiver : public QObject {
+ bool event(QEvent* event) override {
+ if (event->type() == QEvent::User)
+ return true;
+ return QObject::event(event);
+ }
+ } receiver;
+
+ int count = 500;
+ while (!hadToQuit && --count) {
+ threadPool->start([&receiver]{
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::User));
+ });
+
+ QAbstractEventDispatcher::instance()->processEvents(QEventLoop::WaitForMoreEvents);
+ }
+ done = true;
+
+ if (QAbstractEventDispatcher::instance()->inherits("QEventDispatcherWin32"))
+ QEXPECT_FAIL("", QAbstractEventDispatcher::instance()->metaObject()->className(), Continue);
+
+ QVERIFY(!hadToQuit);
+ QVERIFY(threadPool->waitForDone());
+}
+
+void tst_QEventDispatcher::postEventFromEventHandler()
+{
+ QThreadPool *threadPool = QThreadPool::globalInstance();
+ QAtomicInt hadToQuit = false;
+ QAtomicInt done = false;
+
+ threadPool->start([&]{
+ int loop = 250 / 10; // give it 250ms
+ while (!done && --loop)
+ QThread::msleep(10);
+ if (done)
+ return;
+ hadToQuit = true;
+ QCoreApplication::eventDispatcher()->wakeUp();
+ });
+
+ struct EventReceiver : public QObject {
+ int i = 0;
+ bool event(QEvent* event) override
+ {
+ if (event->type() == QEvent::User) {
+ ++i;
+ if (i < 2)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ return true;
+ }
+ return QObject::event(event);
+ }
+ } receiver;
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::User));
+ while (receiver.i < 2)
+ QAbstractEventDispatcher::instance()->processEvents(QEventLoop::WaitForMoreEvents);
+ done = true;
+
+ bool coreFails = false;
+ bool guiFails = false;
+ const QByteArrayView eventDispatcherName(QAbstractEventDispatcher::instance()->metaObject()->className());
+#if defined(Q_OS_DARWIN)
+ coreFails = true;
+#elif defined(Q_OS_WINDOWS)
+ coreFails = true;
+ guiFails = true;
+#elif defined(Q_OS_LINUX)
+ // QXcbUnixEventDispatcher and QEventDispatcherUNIX do not do this correctly
+ // QXcbGlibEventDispatcher and QEventDispatcherGlib do
+ coreFails = !eventDispatcherName.contains("Glib");
+ guiFails = !eventDispatcherName.contains("Glib");
+#endif
+
+ if (coreFails && !isGuiEventDispatcher)
+ QEXPECT_FAIL("", eventDispatcherName.constData(), Continue);
+ if (guiFails && isGuiEventDispatcher)
+ QEXPECT_FAIL("", eventDispatcherName.constData(), Continue);
+
+ QVERIFY(!hadToQuit);
+ QVERIFY(threadPool->waitForDone());
+}
+
+
void tst_QEventDispatcher::postedEventsPingPong()
{
QEventLoop mainLoop;