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>
This commit is contained in:
parent
0d3840b056
commit
6f30764320
@ -5,21 +5,13 @@
|
|||||||
|
|
||||||
#include "tests/clutter-test-utils.h"
|
#include "tests/clutter-test-utils.h"
|
||||||
|
|
||||||
/* We ask for 1 frame per millisecond.
|
#define TEST_TIMELINE_DURATION 3000
|
||||||
* 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.
|
* Make the test tolarate being half a second off track in each direction,
|
||||||
*
|
* the thing we're testing for will still be tested for.
|
||||||
* 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_ERROR_TOLERANCE ((TEST_TIMELINE_FPS / 4) - 1)
|
#define TEST_ERROR_TOLERANCE 500
|
||||||
|
|
||||||
typedef struct _TestState
|
typedef struct _TestState
|
||||||
{
|
{
|
||||||
@ -28,7 +20,7 @@ typedef struct _TestState
|
|||||||
int new_frame_counter;
|
int new_frame_counter;
|
||||||
int expected_frame;
|
int expected_frame;
|
||||||
int completion_count;
|
int completion_count;
|
||||||
gboolean passed;
|
int cycle_frame_counter;
|
||||||
} TestState;
|
} TestState;
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +33,6 @@ new_frame_cb (ClutterTimeline *timeline,
|
|||||||
int current_frame;
|
int current_frame;
|
||||||
long msec_diff;
|
long msec_diff;
|
||||||
int loop_overflow = 0;
|
int loop_overflow = 0;
|
||||||
static int step = 1;
|
|
||||||
|
|
||||||
current_time = g_get_real_time ();
|
current_time = g_get_real_time ();
|
||||||
|
|
||||||
@ -61,57 +52,100 @@ new_frame_cb (ClutterTimeline *timeline,
|
|||||||
state->expected_frame = TEST_TIMELINE_DURATION;
|
state->expected_frame = TEST_TIMELINE_DURATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE)
|
switch (state->cycle_frame_counter)
|
||||||
&& current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE))
|
|
||||||
{
|
{
|
||||||
g_test_message ("elapsed milliseconds=%-5li "
|
case 0:
|
||||||
"expected frame=%-4i actual frame=%-4i (OK)",
|
case 1:
|
||||||
msec_diff,
|
if (current_frame >= (state->expected_frame - TEST_ERROR_TOLERANCE) &&
|
||||||
state->expected_frame,
|
current_frame <= (state->expected_frame + TEST_ERROR_TOLERANCE))
|
||||||
current_frame);
|
{
|
||||||
}
|
g_test_message ("elapsed milliseconds=%-5li "
|
||||||
else
|
"expected frame=%-4i actual frame=%-4i (OK)",
|
||||||
{
|
msec_diff,
|
||||||
g_test_message ("elapsed milliseconds=%-5li "
|
state->expected_frame,
|
||||||
"expected frame=%-4i actual frame=%-4i (FAILED)",
|
current_frame);
|
||||||
msec_diff,
|
}
|
||||||
state->expected_frame,
|
else
|
||||||
current_frame);
|
{
|
||||||
state->passed = FALSE;
|
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);
|
clutter_timeline_stop (timeline);
|
||||||
g_test_message ("Sleeping for 250ms "
|
return;
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_frame >= TEST_TIMELINE_DURATION)
|
switch (state->cycle_frame_counter)
|
||||||
{
|
{
|
||||||
state->expected_frame += loop_overflow;
|
case 0:
|
||||||
state->expected_frame -= TEST_TIMELINE_DURATION;
|
{
|
||||||
g_test_message ("End of timeline reached: "
|
/*
|
||||||
"Wrapping expected frame too %i",
|
* First frame, sleep so we're about in the middle of the cycle,
|
||||||
state->expected_frame);
|
* 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++;
|
state->new_frame_counter++;
|
||||||
step = -step;
|
state->cycle_frame_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -119,14 +153,20 @@ completed_cb (ClutterTimeline *timeline,
|
|||||||
TestState *state)
|
TestState *state)
|
||||||
{
|
{
|
||||||
state->completion_count++;
|
state->completion_count++;
|
||||||
|
state->cycle_frame_counter = 0;
|
||||||
|
|
||||||
if (state->completion_count == 2)
|
if (state->completion_count >= 2)
|
||||||
{
|
g_assert_not_reached ();
|
||||||
if (state->passed)
|
}
|
||||||
clutter_test_quit ();
|
|
||||||
else
|
static void
|
||||||
g_assert_not_reached ();
|
stopped_cb (ClutterTimeline *timeline,
|
||||||
}
|
gboolean is_finished,
|
||||||
|
TestState *state)
|
||||||
|
{
|
||||||
|
g_assert_cmpint (state->completion_count, ==, 1);
|
||||||
|
|
||||||
|
clutter_test_quit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -148,10 +188,14 @@ timeline_interpolation (void)
|
|||||||
"completed",
|
"completed",
|
||||||
G_CALLBACK (completed_cb),
|
G_CALLBACK (completed_cb),
|
||||||
&state);
|
&state);
|
||||||
|
g_signal_connect (state.timeline,
|
||||||
|
"stopped",
|
||||||
|
G_CALLBACK (stopped_cb),
|
||||||
|
&state);
|
||||||
|
|
||||||
state.completion_count = 0;
|
state.completion_count = 0;
|
||||||
state.new_frame_counter = 0;
|
state.new_frame_counter = 0;
|
||||||
state.passed = TRUE;
|
state.cycle_frame_counter = 0;
|
||||||
state.expected_frame = 0;
|
state.expected_frame = 0;
|
||||||
|
|
||||||
clutter_actor_show (stage);
|
clutter_actor_show (stage);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user