validate: Add a way to run a TestClock in scenarios
authorThibault Saunier <tsaunier@igalia.com>
Mon, 13 Apr 2020 20:23:32 +0000 (16:23 -0400)
committerThibault Saunier <tsaunier@igalia.com>
Mon, 27 Apr 2020 21:00:12 +0000 (17:00 -0400)
A TestClock will be used automatically when a scenario has a
`crank-clock` action.

And make `validate` and `debug-viewer` options features in meson,
no reason they weren't and now we require gst-check to build validate

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/merge_requests/182>

docs/gst-validate-test-file.md
meson.build
meson_options.txt
validate/gst/validate/gst-validate-scenario.c
validate/gst/validate/meson.build

index 4494db0..6328aa0 100644 (file)
@@ -28,8 +28,8 @@ The `meta` format:
 
 ## Tool arguments
 
-In the case of [`gst-validate`](gst-validate.md) it **has to** contain a
-`gst-validate-args` field with `gst-validate` argv arguments like:
+In the case of [`gst-validate`](gst-validate.md) it **has to** contain an
+`args` field with `gst-validate` argv arguments like:
 
 ``` yaml
 # This is the default tool so it is not mandatory for the `gst-validate` tool
@@ -49,7 +49,7 @@ usual [config](gst-validate-config.md) files contain.
 
 For example:
 
-``` json
+``` yaml
 configs = {
     # Set videotestsrc0 pattern value to `blue`
     "core, action=set-property, target-element-name=videotestsrc0, property-name=pattern, property-value=blue",
index 199cb72..842d296 100644 (file)
@@ -67,11 +67,9 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re
     fallback : ['gst-plugins-base', 'pbutils_dep'])
 gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req,
     fallback : ['gst-plugins-base', 'video_dep'])
-if host_machine.system() != 'windows'
-  gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req,
-    required : get_option('tests'),
-    fallback : ['gstreamer', 'gst_check_dep'])
-endif
+gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req,
+  required : get_option('validate'),
+  fallback : ['gstreamer', 'gst_check_dep'])
 
 glib_dep = dependency('glib-2.0', version : '>=2.32.0',
   fallback: ['glib', 'libglib_dep'])
@@ -146,7 +144,7 @@ i18n = import('i18n')
 python_mod = import('python')
 python3 = python_mod.find_installation()
 
-if get_option('validate')
+if not get_option('validate').disabled()
   subdir('validate')
 endif
 
index 10a1419..6d06623 100644 (file)
@@ -1,4 +1,4 @@
-option('validate', type : 'boolean', value : true,
+option('validate', type : 'feature', value : 'auto',
        description : 'Build GstValidate')
 option('debug_viewer', type : 'boolean', value : true,
         description : 'Build GstDebugViewer')
index b2a5ce8..e095ff3 100644 (file)
@@ -47,6 +47,7 @@
 #include <string.h>
 #include <errno.h>
 
+#include <gst/check/gsttestclock.h>
 #include "gst-validate-internal.h"
 #include "gst-validate-scenario.h"
 #include "gst-validate-reporter.h"
@@ -178,6 +179,8 @@ struct _GstValidateScenarioPrivate
   GstStructure *vars;
 
   GWeakRef ref_pipeline;
+
+  GstTestClock *clock;
 };
 
 typedef struct KeyFileGroupName
@@ -610,6 +613,10 @@ gboolean
 gst_validate_action_get_clocktime (GstValidateScenario * scenario,
     GstValidateAction * action, const gchar * name, GstClockTime * retval)
 {
+
+  if (!gst_structure_has_field (action->structure, name))
+    return FALSE;
+
   if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) {
     gdouble val;
     gchar *error = NULL, *strval;
@@ -1710,12 +1717,12 @@ static gboolean
 _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act,
     GstClockTime position, gdouble rate)
 {
-  GstElement *pipeline;
+  GstElement *pipeline = NULL;
 
   if (!act) {
     GST_DEBUG_OBJECT (scenario, "No action to execute");
 
-    return FALSE;
+    goto no;
   }
 
   pipeline = gst_validate_scenario_get_pipeline (scenario);
@@ -1776,7 +1783,7 @@ yes:
   return TRUE;
 
 no:
-  gst_object_unref (pipeline);
+  gst_clear_object (&pipeline);
   return FALSE;
 }
 
@@ -3512,6 +3519,9 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario,
       goto failed;
     }
 
+    if (!g_strcmp0 (type, "crank-clock") && !priv->clock)
+      priv->clock = GST_TEST_CLOCK (gst_test_clock_new ());
+
     if (action_type->parameters) {
       guint i;
 
@@ -3833,6 +3843,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario)
   g_weak_ref_init (&scenario->priv->ref_pipeline, NULL);
   priv->max_latency = GST_CLOCK_TIME_NONE;
   priv->max_dropped = -1;
+  priv->clock = NULL;
 
   g_mutex_init (&priv->lock);
 }
@@ -3852,6 +3863,8 @@ gst_validate_scenario_dispose (GObject * object)
     priv->bus = NULL;
   }
 
+  gst_object_replace ((GstObject **) & priv->clock, NULL);
+
   G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object);
 }
 
@@ -4013,6 +4026,11 @@ gst_validate_scenario_new (GstValidateRunner *
       GST_OBJECT_NAME (pipeline));
 
   g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline);
+  if (scenario->priv->clock) {
+    gst_element_set_clock (pipeline, GST_CLOCK_CAST (scenario->priv->clock));
+    gst_pipeline_use_clock (GST_PIPELINE (pipeline),
+        GST_CLOCK_CAST (scenario->priv->clock));
+  }
   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario),
       g_strdup (scenario_name));
 
@@ -4637,6 +4655,56 @@ done:
   return GST_PAD_PROBE_OK;
 }
 
+static GstValidateExecuteActionReturn
+_execute_crank_clock (GstValidateScenario * scenario,
+    GstValidateAction * action)
+{
+  GstClockTime expected_diff, expected_time;
+  GstClockTime prev_time =
+      gst_clock_get_time (GST_CLOCK (scenario->priv->clock));
+
+  if (!gst_test_clock_crank (scenario->priv->clock)) {
+    GST_VALIDATE_REPORT_ACTION (scenario, action,
+        SCENARIO_ACTION_EXECUTION_ERROR, "Cranking clock failed");
+
+    return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
+  }
+
+  if (gst_validate_action_get_clocktime (scenario, action,
+          "expected-elapsed-time", &expected_diff)) {
+    GstClockTime elapsed =
+        gst_clock_get_time (GST_CLOCK (scenario->priv->clock)) - prev_time;
+
+    if (expected_diff != elapsed) {
+      GST_VALIDATE_REPORT_ACTION (scenario, action,
+          SCENARIO_ACTION_EXECUTION_ERROR,
+          "Elapsed time during test clock cranking different than expected,"
+          " waited for %" GST_TIME_FORMAT " instead of the expected %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (elapsed),
+          GST_TIME_ARGS (expected_diff));
+
+      return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
+    }
+  }
+
+  if (gst_validate_action_get_clocktime (scenario, action, "expected-time",
+          &expected_time)) {
+    GstClockTime time = gst_clock_get_time (GST_CLOCK (scenario->priv->clock));
+
+    if (expected_time != time) {
+      GST_VALIDATE_REPORT_ACTION (scenario, action,
+          SCENARIO_ACTION_EXECUTION_ERROR,
+          "Clock time after cranking different than expected,"
+          " got %" GST_TIME_FORMAT " instead of the expected %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (time), GST_TIME_ARGS (expected_time));
+
+      return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
+    }
+  }
+
+  return GST_VALIDATE_EXECUTE_ACTION_OK;
+}
+
 static gboolean
 _execute_request_key_unit (GstValidateScenario * scenario,
     GstValidateAction * action)
@@ -5242,7 +5310,7 @@ register_action_types (void)
         .mandatory = FALSE,
         .types = "boolean",
         .possible_variables = NULL,
-        .def = "false"
+        .def = "true if some action requires a playback-time false otherwise"
       },
       {
         .name = "min-media-duration",
@@ -5820,6 +5888,29 @@ register_action_types (void)
       " for example",
       GST_VALIDATE_ACTION_TYPE_INTERLACED);
 
+    REGISTER_ACTION_TYPE ("crank-clock", _execute_crank_clock,
+      ((GstValidateActionParameter []) {
+        {
+          .name = "expected-time",
+          .description = "Expected clock time after cranking",
+          .mandatory = FALSE,
+          .types = "GstClockTime",
+          NULL
+        },
+        {
+          .name = "expected-elapsed-time",
+          .description = "Check time elapsed during the clock cranking",
+          .mandatory = FALSE,
+          .types = "GstClockTime",
+          NULL
+        },
+      }), "Crank the clock, possibly checking how much time was supposed to be waited on the clock"
+          " and/or the clock running time after the crank."
+          " Using one `crank-clock` action in a scenario implies that the scenario is driving the "
+          " clock and a #GstTestClock will be used. The user will need to crank it the number of "
+          " time required (using the `repeat` parameter comes handy here).",
+        GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK);
+
     REGISTER_ACTION_TYPE ("video-request-key-unit", _execute_request_key_unit,
       ((GstValidateActionParameter []) {
         {
index 107ea7d..090ec78 100644 (file)
@@ -61,7 +61,7 @@ gstvalidate = library('gstvalidate-1.0',
     include_directories : [inc_dirs],
     install: true,
     c_args : [gst_c_args] + ['-D_GNU_SOURCE'],
-    dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep,
+    dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep,
                     gmodule_dep, gst_pbutils_dep, mathlib, json_dep])
 
 gstvalidatetracer = library('gstvalidatetracer',
@@ -70,7 +70,7 @@ gstvalidatetracer = library('gstvalidatetracer',
     install: true,
     c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'],
     install_dir : plugins_install_dir,
-    dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep,
+    dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep,
                     gst_pbutils_dep, mathlib, json_dep])
 
 validate_gen_sources = []
@@ -90,7 +90,7 @@ if build_gir
                         'Gst-' + apiversion,
                         'GstPbutils-' + apiversion],
             install : true,
-            dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep],
+            dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep, gst_check_dep],
             extra_args : gst_validate_gir_extra_args,
     )
     validate_gen_sources += [validate_gir]