summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2013-01-18 15:53:56 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2013-10-17 13:35:04 +1000
commitde1042bb3ab33d6063536bee9f04b96a49dfef9c (patch)
tree5153ca9fb830d48f4458864a8461b698583667e4
parent35aa68143b39608bd2e7d75a68d37c3bff625792 (diff)
server/misc: add a bunch of idletime sync counter test
Definitely broken upstream. If a NegativeTransition counter is set on the idletimer, an AlarmNotify is sent when the idletimer goes below that. Once the alarm is sent, the server calls ComputeBracket. That should, but doesn't set the negative transition again because idletime < threshold for a negative transition (i.e. it's skipped). The idletimer can then go past the threshold, and back to 0 because nothing is ever set. Since the brackets are re-computed after each alarm, if there is one more alarm that fires the negative transition may be re-institutated after that alarm. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-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();