GstHarness

#GstHarness is meant to make writing unit test for GStreamer much easier. It can be thought of as a way of treating a #GstElement as a black box, deterministically feeding it data, and controlling what data it outputs.

The basic structure of #GstHarness is two "floating" #GstPads that connect to the harnessed #GstElement src and sink #GstPads like so:

          __________________________
 _____   |  _____            _____  |   _____
|     |  | |     |          |     | |  |     |
| src |--+-| sink|  Element | src |-+--| sink|
|_____|  | |_____|          |_____| |  |_____|
         |__________________________|

With this, you can now simulate any environment the #GstElement might find itself in. By specifying the #GstCaps of the harness #GstPads, using functions like gstcheck.harness.Harness.setSrcCaps or gstcheck.harness.Harness.setSinkCapsStr, you can test how the #GstElement interacts with different caps sets.

Your harnessed #GstElement can of course also be a bin, and using gstcheck.harness.Harness.newParse supporting standard gst-launch syntax, you can easily test a whole pipeline instead of just one element.

You can then go on to push #GstBuffers and #GstEvents on to the srcpad, using functions like gstcheck.harness.Harness.push and gstcheck.harness.Harness.pushEvent, and then pull them out to examine them with gstcheck.harness.Harness.pull and gstcheck.harness.Harness.pullEvent.

A simple buffer-in buffer-out example

#include <gst/gst.h>
#include <gst/check/gstharness.h>
GstHarness *h;
GstBuffer *in_buf;
GstBuffer *out_buf;

// attach the harness to the src and sink pad of GstQueue
h = gst_harness_new ("queue");

// we must specify a caps before pushing buffers
gst_harness_set_src_caps_str (h, "mycaps");

// create a buffer of size 42
in_buf = gst_harness_create_buffer (h, 42);

// push the buffer into the queue
gst_harness_push (h, in_buf);

// pull the buffer from the queue
out_buf = gst_harness_pull (h);

// validate the buffer in is the same as buffer out
fail_unless (in_buf == out_buf);

// cleanup
gst_buffer_unref (out_buf);
gst_harness_teardown (h);

Another main feature of the #GstHarness is its integration with the #GstTestClock. Operating the #GstTestClock can be very challenging, but #GstHarness simplifies some of the most desired actions a lot, like wanting to manually advance the clock while at the same time releasing a #GstClockID that is waiting, with functions like gstcheck.harness.Harness.crankSingleClockWait.

#GstHarness also supports sub-harnesses, as a way of generating and validating data. A sub-harness is another #GstHarness that is managed by the "parent" harness, and can either be created by using the standard gst_harness_new type functions directly on the (GstHarness *)->src_harness, or using the much more convenient gstcheck.harness.Harness.addSrc or gstcheck.harness.Harness.addSinkParse. If you have a decoder-element you want to test, (like vp8dec) it can be very useful to add a src-harness with both a src-element (videotestsrc) and an encoder (vp8enc) to feed the decoder data with different configurations, by simply doing:

GstHarness * h = gst_harness_new ("vp8dec");
gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);

and then feeding it data with:

gst_harness_push_from_src (h);

Members

Variables

element
GstElement* element;

the element inside the harness

priv
GstHarnessPrivate* priv;
sinkHarness
GstHarness* sinkHarness;

the sink (output) harness (if any)

sinkpad
GstPad* sinkpad;

the internal harness sink pad

srcHarness
GstHarness* srcHarness;

the source (input) harness (if any)

srcpad
GstPad* srcpad;

the internal harness source pad