[mutter] tests/clutter/timeline-interpolate: Rework test to be less flaky
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] tests/clutter/timeline-interpolate: Rework test to be less flaky
- Date: Mon, 8 Mar 2021 15:01:49 +0000 (UTC)
commit 6f30764320f6674814bae230e6965dc323437930
Author: Jonas Ã…dahl <jadahl gmail com>
Date: Mon Mar 1 14:38:32 2021 +0100
tests/clutter/timeline-interpolate: Rework test to be less flaky
This more or less rewrites this test so that it explicitly tests the
"interpolation" when a timeline loops, i.e. that if something occupies
the thread when a timeline was supposed to have looped, we end up in the
right place "in the middle" of the next timeline cycle.
The test more or less does this:
* Start a 3 second looping timeline
* Sleep so that we're in the middle of the first cycle
* Sleep again so that we end up in the middle of the next cycle
The semantics checked are that we see the following frames:
* The first frame with timestamp 0
* The second frame in the middle of the first cycle (timestamp ~= 1.5
sceonds)
* The third frame in the end of the first cycle (timestamp == 3.0
seconds)
* The fourth frame, first in the second cycle, with timestamp ~= 1.5
seconds)
This means we can increase the "grace period" to the double (from 0.5 s
to 1 s), while at the same time decrease the time spent running the test
(from 10 s to 4.5 s). This should hopefully make the test less flaky,
especially in slower runners, e.g. aarch64.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1751>
src/tests/clutter/conform/timeline-interpolate.c | 174 ++++++++++++++---------
1 file changed, 109 insertions(+), 65 deletions(-)
---
diff --git a/src/tests/clutter/conform/timeline-interpolate.c
b/src/tests/clutter/conform/timeline-interpolate.c
index 6167f1e9fe..4c9d058c5f 100644
--- a/src/tests/clutter/conform/timeline-interpolate.c
+++ b/src/tests/clutter/conform/timeline-interpolate.c
@@ -5,21 +5,13 @@
#include "tests/clutter-test-utils.h"
-/* We ask for 1 frame per millisecond.
- * Whenever this rate can't be achieved then the timeline
- * will interpolate the number frames that should have
- * passed between timeouts. */
-#define TEST_TIMELINE_FPS 1000
-#define TEST_TIMELINE_DURATION 5000
-
-/* We are at the mercy of the system scheduler so this
- * may not be a very reliable tolerance.
- *
- * It's set as very tolerable (1 ms shorter than the frame interval) as
- * otherwise CI, which are very prone to not get CPU time scheduled, tend to
- * often fail.
+#define TEST_TIMELINE_DURATION 3000
+
+/*
+ * Make the test tolarate being half a second off track in each direction,
+ * the thing we're testing for will still be tested for.
*/
-#define TEST_ERROR_TOLERANCE ((TEST_TIMELINE_FPS / 4) - 1)
+#define TEST_ERROR_TOLERANCE 500
typedef struct _TestState
{
@@ -28,7 +20,7 @@ typedef struct _TestState
int new_frame_counter;
int expected_frame;
int completion_count;
- gboolean passed;
+ int cycle_frame_counter;
} TestState;
@@ -41,7 +33,6 @@ new_frame_cb (ClutterTimeline *timeline,
int current_frame;
long msec_diff;
int loop_overflow = 0;
- static int step = 1;
current_time = g_get_real_time ();
@@ -61,57 +52,100 @@ new_frame_cb (ClutterTimeline *timeline,
state->expected_frame = TEST_TIMELINE_DURATION;
}
- if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE)
- && current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE))
- {
- g_test_message ("elapsed milliseconds=%-5li "
- "expected frame=%-4i actual frame=%-4i (OK)",
- msec_diff,
- state->expected_frame,
- current_frame);
- }
- else
+ switch (state->cycle_frame_counter)
{
- g_test_message ("elapsed milliseconds=%-5li "
- "expected frame=%-4i actual frame=%-4i (FAILED)",
- msec_diff,
- state->expected_frame,
- current_frame);
- state->passed = FALSE;
+ case 0:
+ case 1:
+ if (current_frame >= (state->expected_frame - TEST_ERROR_TOLERANCE) &&
+ current_frame <= (state->expected_frame + TEST_ERROR_TOLERANCE))
+ {
+ g_test_message ("elapsed milliseconds=%-5li "
+ "expected frame=%-4i actual frame=%-4i (OK)",
+ msec_diff,
+ state->expected_frame,
+ current_frame);
+ }
+ else
+ {
+ g_test_message ("elapsed milliseconds=%-5li "
+ "expected frame=%-4i actual frame=%-4i (FAILED)",
+ msec_diff,
+ state->expected_frame,
+ current_frame);
+ g_test_fail ();
+ }
+ break;
+ case 2:
+ g_assert_cmpint (current_frame, ==, TEST_TIMELINE_DURATION);
+ break;
+ default:
+ g_assert_not_reached ();
}
- if (step>0)
+ /* We already tested that we interpolated when looping, lets stop now. */
+ if (state->completion_count == 1 &&
+ state->cycle_frame_counter == 0)
{
- state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4);
- g_test_message ("Sleeping for 250ms "
- "so next frame should be (%i + %i) = %i",
- current_frame,
- (TEST_TIMELINE_FPS / 4),
- state->expected_frame);
- g_usleep (250000);
- }
- else
- {
- state->expected_frame = current_frame + TEST_TIMELINE_FPS;
- g_test_message ("Sleeping for 1sec "
- "so next frame should be (%i + %i) = %i",
- current_frame,
- TEST_TIMELINE_FPS,
- state->expected_frame);
- g_usleep (1000000);
+ clutter_timeline_stop (timeline);
+ return;
}
- if (current_frame >= TEST_TIMELINE_DURATION)
+ switch (state->cycle_frame_counter)
{
- state->expected_frame += loop_overflow;
- state->expected_frame -= TEST_TIMELINE_DURATION;
- g_test_message ("End of timeline reached: "
- "Wrapping expected frame too %i",
- state->expected_frame);
+ case 0:
+ {
+ /*
+ * First frame, sleep so we're about in the middle of the cycle,
+ * before the end of the timeline cycle.
+ */
+ int delay_ms = ms (1500);
+
+ state->expected_frame = current_frame + delay_ms;
+ g_test_message ("Sleeping for 1.5 seconds "
+ "so next frame should be (%d + %d) = %d",
+ current_frame,
+ delay_ms,
+ state->expected_frame);
+ g_usleep (ms2us (delay_ms));
+ break;
+ }
+ case 1:
+ {
+ /*
+ * Second frame, we're about in the middle of the cycle; sleep one cycle,
+ * and check that we end up in the middle again.
+ */
+ int delay_ms = TEST_TIMELINE_DURATION;
+
+ state->expected_frame = current_frame + delay_ms;
+ g_test_message ("Sleeping for %d seconds "
+ "so next frame should be (%d + %d) = %d, "
+ "which is %d into the next cycle",
+ TEST_TIMELINE_DURATION / 1000,
+ current_frame,
+ delay_ms,
+ state->expected_frame,
+ state->expected_frame - TEST_TIMELINE_DURATION);
+ g_usleep (ms2us (delay_ms));
+
+ g_assert_cmpint (state->expected_frame, >, TEST_TIMELINE_DURATION);
+
+ state->expected_frame += loop_overflow;
+ state->expected_frame -= TEST_TIMELINE_DURATION;
+ g_test_message ("End of timeline reached: "
+ "Wrapping expected frame too %d",
+ state->expected_frame);
+ break;
+ }
+ case 2:
+ case 3:
+ {
+ break;
+ }
}
state->new_frame_counter++;
- step = -step;
+ state->cycle_frame_counter++;
}
static void
@@ -119,14 +153,20 @@ completed_cb (ClutterTimeline *timeline,
TestState *state)
{
state->completion_count++;
+ state->cycle_frame_counter = 0;
- if (state->completion_count == 2)
- {
- if (state->passed)
- clutter_test_quit ();
- else
- g_assert_not_reached ();
- }
+ if (state->completion_count >= 2)
+ g_assert_not_reached ();
+}
+
+static void
+stopped_cb (ClutterTimeline *timeline,
+ gboolean is_finished,
+ TestState *state)
+{
+ g_assert_cmpint (state->completion_count, ==, 1);
+
+ clutter_test_quit ();
}
static void
@@ -148,10 +188,14 @@ timeline_interpolation (void)
"completed",
G_CALLBACK (completed_cb),
&state);
+ g_signal_connect (state.timeline,
+ "stopped",
+ G_CALLBACK (stopped_cb),
+ &state);
state.completion_count = 0;
state.new_frame_counter = 0;
- state.passed = TRUE;
+ state.cycle_frame_counter = 0;
state.expected_frame = 0;
clutter_actor_show (stage);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]