summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2013-10-18 09:12:03 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2013-10-18 09:12:03 +1000
commit40ce5943c5bf58c06742851b11b63c8d8e5b16dc (patch)
tree5153ca9fb830d48f4458864a8461b698583667e4
parent35aa68143b39608bd2e7d75a68d37c3bff625792 (diff)
parentde1042bb3ab33d6063536bee9f04b96a49dfef9c (diff)
Merge branch 'sync-idletimer-fix'
-rw-r--r--tests/server/misc.cpp322
1 files changed, 322 insertions, 0 deletions
diff --git a/tests/server/misc.cpp b/tests/server/misc.cpp
index 7e32afc..bae84b1 100644
--- a/tests/server/misc.cpp
+++ b/tests/server/misc.cpp
@@ -30,8 +30,10 @@
#include <xorg/gtest/xorg-gtest.h>
#include <X11/extensions/scrnsaver.h>
+#include <X11/extensions/sync.h>
#include "xit-server-input-test.h"
+#include "xit-event.h"
#include "device-interface.h"
#include "helpers.h"
@@ -222,6 +224,326 @@ TEST_F(ScreenSaverTest, ScreenSaverActivateDeactivate)
EXPECT_LT(info.idle, 1000U);
}
+
+class XSyncTest : public XITServerInputTest {
+ public:
+ virtual void SetUp() {
+ XITServerInputTest::SetUp();
+ QuerySyncExtension(Display());
+ }
+
+ virtual void QuerySyncExtension(::Display *dpy) {
+ ASSERT_TRUE(XSyncQueryExtension (dpy, &sync_event, &sync_error));
+ ASSERT_TRUE(XSyncInitialize (dpy, &sync_major, &sync_minor));
+ }
+
+ virtual XSyncAlarm SetAbsoluteAlarm(::Display *dpy, XSyncCounter counter,
+ int threshold, XSyncTestType direction,
+ bool need_events = true) {
+ XSyncAlarm alarm;
+ int flags;
+ XSyncAlarmAttributes attr;
+ XSyncValue delta, interval;
+
+ XSyncIntToValue(&delta, 0);
+ XSyncIntToValue(&interval, threshold);
+
+ attr.trigger.counter = counter;
+ attr.trigger.test_type = direction;;
+ attr.trigger.value_type = XSyncAbsolute;
+ attr.trigger.wait_value = interval;
+ attr.delta = delta;
+ attr.events = need_events;
+
+ flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
+ XSyncCAValue | XSyncCADelta| XSyncCAEvents;
+
+ alarm = XSyncCreateAlarm(dpy, flags, &attr);
+ XSync(dpy, False);
+ return alarm;
+ }
+
+ int sync_event;
+ int sync_error;
+ int sync_major;
+ int sync_minor;
+};
+
+class IdletimerTest : public XSyncTest,
+ public DeviceInterface {
+public:
+ virtual void SetUp() {
+ SetDevice("mice/PIXART-USB-OPTICAL-MOUSE-HWHEEL.desc");
+ XSyncTest::SetUp();
+ }
+
+ virtual void SetUpConfigAndLog() {
+ config.AddDefaultScreenWithDriver();
+ config.AddInputSection("evdev", "--device--",
+ "Option \"CorePointer\" \"on\"\n"
+ "Option \"GrabDevice\" \"on\"\n"
+ "Option \"Device\" \"" + dev->GetDeviceNode() + "\"");
+ /* add default keyboard device to avoid server adding our device again */
+ config.AddInputSection("kbd", "kbd-device",
+ "Option \"CoreKeyboard\" \"on\"\n");
+ config.WriteConfig();
+ }
+
+ virtual XSyncCounter GetIdletimeCounter(::Display *dpy) {
+ int ncounters;
+ XSyncSystemCounter *counters;
+ XSyncCounter counter = None;
+
+ counters = XSyncListSystemCounters (dpy, &ncounters);
+ for (int i = 0; i < ncounters; i++) {
+ if (!strcmp(counters[i].name, "IDLETIME")) {
+ counter = counters[i].counter;
+ }
+ }
+
+ XSyncFreeSystemCounterList(counters);
+
+ if (!counter)
+ ADD_FAILURE() << "IDLETIME counter not found.";
+ return counter;
+ }
+
+ /**
+ * This function is necessary because in this test setup the server may
+ * hang when we're only sending one event. Event gets processed, but
+ * ProcessInputEvent() is never called so we just hang waiting for
+ * something to happen and the test fails.
+ * This is a server bug, but won't be triggered on a normal desktop
+ * since there's always something to process (client request, timer,
+ * etc.).
+ */
+ virtual void WaitForEvent(::Display *dpy) {
+ XEvent ev;
+ XSelectInput(dpy, DefaultRootWindow(dpy), PointerMotionMask);
+ while (!XCheckMaskEvent(dpy, PointerMotionMask, &ev)) {
+ dev->PlayOne(EV_REL, REL_X, 10, true);
+ XSync(dpy, False);
+ usleep(10000);
+ }
+ }
+};
+
+TEST_F(IdletimerTest, NegativeTransitionHighThreshold)
+{
+ XORG_TESTCASE("Set up an alarm on negative transition for a high threshold\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect event\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect event\n"
+ "https://bugs.freedesktop.org/show_bug.cgi?id=59644");
+
+ ::Display *dpy = Display();
+
+ /* make sure server is ready to send events */
+ WaitForEvent(dpy);
+ XSync(dpy, True);
+
+ XSyncAlarm neg_alarm;
+ XSyncCounter idlecounter;
+
+ /* bug: if the negative transition threshold fires but the idletime is
+ below the threshold, it is never set up again */
+
+ const int threshold = 1000; /* ms */
+
+ idlecounter = GetIdletimeCounter(dpy);
+ ASSERT_GT(idlecounter, (XSyncCounter)None);
+ neg_alarm = SetAbsoluteAlarm(dpy, idlecounter, threshold, XSyncNegativeTransition);
+ ASSERT_GT(neg_alarm, (XSyncAlarm)None);
+
+ usleep(threshold * 1.5 * 1000);
+ WaitForEvent(dpy);
+
+ usleep(threshold * 1.5 * 1000);
+ WaitForEvent(dpy);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev1, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev1->alarm, neg_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev2, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev2->alarm, neg_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+}
+
+TEST_F(IdletimerTest, NegativeTransitionLowThreshold)
+{
+ XORG_TESTCASE("Set up an alarm on negative transition for a low threshold\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect alarm event\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect alarm event\n"
+ "------------------------------------------------\n"
+ "This alarm will generate false positives, the test \n"
+ "will only fail if the server is busy and the time to\n"
+ "idle timer query takes more than <threshold> ms\n"
+ "https://bugs.freedesktop.org/show_bug.cgi?id=70476");
+
+ ::Display *dpy = Display();
+
+ WaitForEvent(dpy);
+ XSync(dpy, True);
+
+ XSyncAlarm neg_alarm;
+ XSyncCounter idlecounter;
+
+ /* bug: if the negative transition threshold fires but the idletime may
+ move past the threshold before the handler queries it */
+
+ const int threshold = 1; /* ms */
+
+ usleep(threshold * 1000);
+
+ idlecounter = GetIdletimeCounter(dpy);
+ ASSERT_GT(idlecounter, (XSyncCounter)None);
+ neg_alarm = SetAbsoluteAlarm(dpy, idlecounter, threshold, XSyncNegativeTransition);
+ ASSERT_GT(neg_alarm, (XSyncAlarm)None);
+
+ usleep(threshold * 1.5 * 1000);
+ WaitForEvent(dpy);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev1, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev1->alarm, neg_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+}
+
+TEST_F(IdletimerTest, PositiveTransitionLowThreshold)
+{
+ XORG_TESTCASE("Set up an alarm on positive transition for a low threshold\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect event when idletime passes threshold\n"
+ "Wait past threshold, then move pointer\n"
+ "Expect event when idletime passes threshold\n"
+ "https://bugs.freedesktop.org/show_bug.cgi?id=70476");
+
+ ::Display *dpy = Display();
+
+ /* make sure server is ready to send events */
+ WaitForEvent(dpy);
+ XSync(dpy, True);
+
+ XSyncAlarm pos_alarm;
+ XSyncCounter idlecounter;
+
+ /* bug: if the postive transition threshold fires but the idletime is
+ already above the threshold, it is never set up again */
+
+ const int threshold = 1; /* ms */
+
+ usleep(threshold * 20000);
+
+ idlecounter = GetIdletimeCounter(dpy);
+ ASSERT_GT(idlecounter, (XSyncCounter)None);
+ pos_alarm = SetAbsoluteAlarm(dpy, idlecounter, threshold, XSyncPositiveTransition);
+ SetAbsoluteAlarm(dpy, idlecounter, threshold + 1, XSyncNegativeTransition, false);
+ ASSERT_GT(pos_alarm, (XSyncAlarm)None);
+
+ WaitForEvent(dpy);
+ usleep(threshold * 2000);
+
+ WaitForEvent(dpy);
+ usleep(threshold * 2000);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev1, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev1->alarm, pos_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev2, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev2->alarm, pos_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+}
+
+TEST_F(IdletimerTest, NegativeTransition)
+{
+ XORG_TESTCASE("Set up an alarm on negative transition\n"
+ "Move pointer\n"
+ "Expect event\n"
+ "Wait for timeout\n"
+ "Move pointer again\n"
+ "Expect event\n");
+
+ ::Display *dpy = Display();
+
+ /* make sure server is ready to send events */
+ WaitForEvent(dpy);
+ XSync(dpy, True);
+
+ XSyncAlarm neg_alarm;
+ XSyncCounter idlecounter;
+
+ /* bug: if the negative transition threshold fires but the idletime is
+ below the threshold, it is never set up again */
+ const int threshold = 1000;
+ usleep(threshold * 1001);
+
+ idlecounter = GetIdletimeCounter(dpy);
+ ASSERT_GT(idlecounter, (XSyncCounter)None);
+ neg_alarm = SetAbsoluteAlarm(dpy, idlecounter, threshold, XSyncNegativeTransition);
+ ASSERT_GT(neg_alarm, (XSyncAlarm)None);
+
+ dev->PlayOne(EV_REL, REL_X, 10, true);
+ WaitForEvent(dpy);
+ usleep(threshold * 1001);
+
+ dev->PlayOne(EV_REL, REL_X, 10, true);
+ WaitForEvent(dpy);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev1, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev1->alarm, neg_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev2, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EQ(ev2->alarm, neg_alarm);
+ ASSERT_EQ(ev1->state, XSyncAlarmActive);
+}
+
+TEST_F(IdletimerTest, NegativeTransitionMultipleAlarms)
+{
+ XORG_TESTCASE("Set up an multiple alarm on negative transitions\n"
+ "Move pointer\n"
+ "Expect event\n"
+ "Wait for timeout\n"
+ "Move pointer again\n"
+ "Expect event\n");
+
+ ::Display *dpy = Display();
+
+ /* make sure server is ready to send events */
+ XSelectInput(dpy, DefaultRootWindow(dpy), PointerMotionMask);
+ WaitForEvent(dpy);
+ XSync(dpy, True);
+
+ XSyncAlarm neg_alarm1, neg_alarm2;
+ XSyncCounter idlecounter;
+
+ /* bug: if the negative transition threshold fires but the idletime is
+ below the threshold, it is never set up again */
+ const int threshold = 200;
+ usleep(threshold * 2000);
+
+ idlecounter = GetIdletimeCounter(dpy);
+ ASSERT_GT(idlecounter, (XSyncCounter)None);
+ neg_alarm2 = SetAbsoluteAlarm(dpy, idlecounter, threshold/2, XSyncNegativeTransition);
+ neg_alarm1 = SetAbsoluteAlarm(dpy, idlecounter, threshold, XSyncNegativeTransition);
+ ASSERT_GT(neg_alarm1, (XSyncAlarm)None);
+ ASSERT_GT(neg_alarm2, (XSyncAlarm)None);
+
+ WaitForEvent(dpy);
+ usleep(threshold * 2000);
+
+ WaitForEvent(dpy);
+
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev1, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev2, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev3, dpy, sync_event + XSyncAlarmNotify);
+ ASSERT_EVENT(XSyncAlarmNotifyEvent, ev4, dpy, sync_event + XSyncAlarmNotify);
+}
+
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();