TestClock
Added in version 1.2.
Superclasses: Clock
, Object
, InitiallyUnowned
, Object
GstTestClock is an implementation of Clock
which has different
behaviour compared to GstSystemClock
. Time for GstSystemClock
advances
according to the system time, while time for TestClock
changes only
when set_time()
or advance_time()
are
called. TestClock
provides unit tests with the possibility to
precisely advance the time in a deterministic manner, independent of the
system time or any other external factors.
Advancing the time of a TestClock
``include`` <gst/gst.h>
``include`` <gst/check/gsttestclock.h>
GstClock *clock;
GstTestClock *test_clock;
clock = gst_test_clock_new ();
test_clock = GST_TEST_CLOCK (clock);
GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND);
GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
g_usleep (10 * G_USEC_PER_SEC);
GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
gst_test_clock_set_time (test_clock, 42 * GST_SECOND);
GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
...
Clock
allows for setting up single shot or periodic clock notifications
as well as waiting for these notifications synchronously (using
id_wait()
) or asynchronously (using id_wait_async()
or
id_wait_async()
). This is used by many GStreamer elements,
among them GstBaseSrc
and GstBaseSink
.
TestClock
keeps track of these clock notifications. By calling
wait_for_next_pending_id()
or
wait_for_multiple_pending_ids()
a unit tests may wait for the
next one or several clock notifications to be requested. Additionally unit
tests may release blocked waits in a controlled fashion by calling
process_next_clock_id()
. This way a unit test can control the
inaccuracy (jitter) of clock notifications, since the test can decide to
release blocked waits when the clock time has advanced exactly to, or past,
the requested clock notification time.
There are also interfaces for determining if a notification belongs to a
TestClock
or not, as well as getting the number of requested clock
notifications so far.
N.B.: When a unit test waits for a certain amount of clock notifications to
be requested in wait_for_next_pending_id()
or
wait_for_multiple_pending_ids()
then these functions may block
for a long time. If they block forever then the expected clock notifications
were never requested from TestClock
, and so the assumptions in the code
of the unit test are wrong. The unit test case runner in gstcheck is
expected to catch these cases either by the default test case timeout or the
one set for the unit test by calling tcase_set_timeout().
The sample code below assumes that the element under test will delay a
buffer pushed on the source pad by some latency until it arrives on the sink
pad. Moreover it is assumed that the element will at some point call
id_wait()
to synchronously wait for a specific time. The first
buffer sent will arrive exactly on time only delayed by the latency. The
second buffer will arrive a little late (7ms) due to simulated jitter in the
clock notification.
Demonstration of how to work with clock notifications and TestClock
``include`` <gst/gst.h>
``include`` <gst/check/gstcheck.h>
``include`` <gst/check/gsttestclock.h>
GstClockTime latency;
GstElement *element;
GstPad *srcpad;
GstClock *clock;
GstTestClock *test_clock;
GstBuffer buf;
GstClockID pending_id;
GstClockID processed_id;
latency = 42 * GST_MSECOND;
element = create_element (latency, ...);
srcpad = get_source_pad (element);
clock = gst_test_clock_new ();
test_clock = GST_TEST_CLOCK (clock);
gst_element_set_clock (element, clock);
GST_INFO ("Set time, create and push the first buffer\n");
gst_test_clock_set_time (test_clock, 0);
buf = create_test_buffer (gst_clock_get_time (clock), ...);
gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
GST_INFO ("Block until element is waiting for a clock notification\n");
gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
GST_INFO ("Advance to the requested time of the clock notification\n");
gst_test_clock_advance_time (test_clock, latency);
GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
processed_id = gst_test_clock_process_next_clock_id (test_clock);
g_assert (processed_id == pending_id);
g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
gst_clock_id_unref (pending_id);
gst_clock_id_unref (processed_id);
GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
buf = get_buffer_pushed_by_element (element, ...);
g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, latency);
gst_buffer_unref (buf);
GST_INFO ("Check that element does not wait for any clock notification\n");
g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
GST_INFO ("Set time, create and push the second buffer\n");
gst_test_clock_advance_time (test_clock, 10 * GST_SECOND);
buf = create_test_buffer (gst_clock_get_time (clock), ...);
gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
GST_INFO ("Block until element is waiting for a new clock notification\n");
(gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
GST_INFO ("Advance past 7ms beyond the requested time of the clock notification\n");
gst_test_clock_advance_time (test_clock, latency + 7 * GST_MSECOND);
GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
processed_id = gst_test_clock_process_next_clock_id (test_clock);
g_assert (processed_id == pending_id);
g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
gst_clock_id_unref (pending_id);
gst_clock_id_unref (processed_id);
GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
buf = get_buffer_pushed_by_element (element, ...);
g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==,
10 * GST_SECOND + latency + 7 * GST_MSECOND);
gst_buffer_unref (buf);
GST_INFO ("Check that element does not wait for any clock notification\n");
g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
...
Since TestClock
is only supposed to be used in unit tests it calls
assert()
, assert_cmpint()
or assert_cmpuint()
to validate all function
arguments. This will highlight any issues with the unit test code itself.
Constructors
Methods
- class TestClock
- advance_time(delta: int) None
Advances the time of the
test_clock
by the amount given bydelta
. The time oftest_clock
is monotonically increasing, therefore providing adelta
which is negative or zero is a programming error.MT safe.
Added in version 1.2.
- Parameters:
delta – a positive
ClockTimeDiff
to be added to the time of the clock
- crank() bool
A “crank” consists of three steps: 1: Wait for a
ClockID
to be registered with theTestClock
. 2: Advance theTestClock
to the time theClockID
is waiting, unlessthe clock time is already passed the clock id (Since: 1.18).
3: Release the
ClockID
wait. A “crank” can be though of as the notion of manually driving the clock forward to its next logical step.Added in version 1.8.
- get_next_entry_time() int
Retrieve the requested time for the next pending clock notification.
MT safe.
Added in version 1.2.
- has_id(id: None) bool
Checks whether
test_clock
was requested to provide the clock notification given byid
.MT safe.
Added in version 1.2.
- Parameters:
id – a
ClockID
clock notification
- id_list_get_latest_time(pending_list: list[None] | None = None) int
Finds the latest time inside the list.
MT safe.
Added in version 1.4.
- Parameters:
pending_list – List of of pending
ClockID
- peek_id_count() int
Determine the number of pending clock notifications that have been requested from the
test_clock
.MT safe.
Added in version 1.2.
- peek_next_pending_id() tuple[bool, None]
Determines if the
pending_id
is the next clock notification scheduled to be triggered given the current time of thetest_clock
.MT safe.
Added in version 1.2.
- process_id(pending_id: None) bool
Processes and releases the pending ID.
MT safe.
Added in version 1.18.
- Parameters:
pending_id –
ClockID
- process_id_list(pending_list: list[None] | None = None) int
Processes and releases the pending IDs in the list.
MT safe.
Added in version 1.4.
- Parameters:
pending_list – List of pending
ClockID
- set_time(new_time: int) None
Sets the time of
test_clock
to the time given bynew_time
. The time oftest_clock
is monotonically increasing, therefore providing anew_time
which is earlier or equal to the time of the clock as given byget_time()
is a programming error.MT safe.
Added in version 1.2.
- Parameters:
new_time – a
ClockTime
later than that returned byget_time()
- timed_wait_for_multiple_pending_ids(count: int, timeout_ms: int) tuple[bool, list[None]]
Blocks until at least
count
clock notifications have been requested fromtest_clock
, or the timeout expires.MT safe.
Added in version 1.16.
- Parameters:
count – the number of pending clock notifications to wait for
timeout_ms – the timeout in milliseconds
- wait_for_multiple_pending_ids(count: int) list[None]
Blocks until at least
count
clock notifications have been requested fromtest_clock
. There is no timeout for this wait, see the main description ofTestClock
.MT safe.
Added in version 1.4.
- Parameters:
count – the number of pending clock notifications to wait for
- wait_for_next_pending_id() None
Waits until a clock notification is requested from
test_clock
. There is no timeout for this wait, see the main description ofTestClock
. A reference to the pending clock notification is stored inpending_id
.MT safe.
Added in version 1.2.
- wait_for_pending_id_count(count: int) None
Blocks until at least
count
clock notifications have been requested fromtest_clock
. There is no timeout for this wait, see the main description ofTestClock
.Added in version 1.2.
Deprecated since version Unknown: use
wait_for_multiple_pending_ids()
instead.- Parameters:
count – the number of pending clock notifications to wait for
Properties
- class TestClock
-
- props.start_time: int
When a
TestClock
is constructed it will have a certain start time set. If the clock was created usingnew_with_start_time()
then this property contains the value of thestart_time
argument. Ifnew()
was called the clock started at time zero, and thus this property contains the value 0.