3 * Copyright (C) 2013-2016 Collabora Ltd.
4 * Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
5 * Author: Thibault Saunier <thibault.saunier@collabora.com>
7 * gst-validate-runner.c - Validate Runner class
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
34 #include "gst-validate-internal.h"
35 #include "gst-validate-report.h"
36 #include "gst-validate-monitor-factory.h"
37 #include "gst-validate-override-registry.h"
38 #include "gst-validate-runner.h"
39 #include "gst-validate-reporter.h"
40 #include "gst-validate-mockdecryptor.h"
42 GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug);
43 #undef GST_CAT_DEFAULT
44 #define GST_CAT_DEFAULT gst_validate_runner_debug
46 static gboolean element_created = FALSE;
48 /* We create a GstValidateRunner on _init ()
49 * so that we keep backward compatibility when
50 * the user create a Runner after creating the pipeline
51 * but the runner was actually already ready to be used.
53 static GstValidateRunner *first_runner = NULL;
56 * SECTION:gst-validate-runner
57 * @title: GstValidateRunner
58 * @short_description: Class that runs Gst Validate tests for a pipeline
60 * Allows you to test a pipeline within GstValidate. It is the object where
61 * all issue reporting is done.
63 * In the tools using GstValidate the only minimal code to be able to monitor
67 * GstPipeline *pipeline = gst_pipeline_new ("monitored-pipeline");
68 * GstValidateRunner *runner = gst_validate_runner_new ();
69 * GstValidateMonitor *monitor = gst_validate_monitor_factory_create (
70 * GST_OBJECT (pipeline), runner, NULL);
72 * // Run the pipeline and do whatever you want with it
74 * // In that same order
75 * gst_object_unref (pipeline);
76 * gst_object_unref (runner);
77 * gst_object_unref (monitor);
82 struct _GstValidateRunnerPrivate
86 GstValidateReportingDetails default_level;
87 GHashTable *reports_by_type;
89 /* A list of PatternLevel */
90 GList *report_pattern_levels;
92 /* Whether the runner was create with GST_TRACERS=validate or not) */
93 gboolean user_created;
95 gchar *pipeline_names;
96 gchar **pipeline_names_strv;
98 GList *expected_issues;
101 /* Describes the reporting level to apply to a name pattern */
102 typedef struct _PatternLevel
104 GPatternSpec *pattern;
105 GstValidateReportingDetails level;
108 #define GST_VALIDATE_RUNNER_LOCK(r) \
110 GST_LOG_OBJECT (r, "About to lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \
111 (g_mutex_lock (&GST_VALIDATE_RUNNER_CAST(r)->priv->mutex)); \
112 GST_LOG_OBJECT (r, "Acquired lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \
115 #define GST_VALIDATE_RUNNER_UNLOCK(r) \
117 GST_LOG_OBJECT (r, "About to unlock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \
118 (g_mutex_unlock (&GST_VALIDATE_RUNNER_CAST(r)->priv->mutex)); \
119 GST_LOG_OBJECT (r, "Released lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \
122 #define gst_validate_runner_parent_class parent_class
123 G_DEFINE_TYPE_WITH_PRIVATE (GstValidateRunner, gst_validate_runner,
142 static GParamSpec *properties[PROP_LAST];
144 static guint _signals[LAST_SIGNAL] = { 0, };
147 gst_validate_runner_should_monitor (GstValidateRunner * self,
148 GstElement * element)
151 GstValidateMonitor *monitor;
153 if (!GST_IS_PIPELINE (element)) {
157 if (self->priv->user_created)
160 if (!self->priv->pipeline_names_strv)
163 monitor = gst_validate_get_monitor (G_OBJECT (element));
166 GST_ERROR_OBJECT (self, "Pipeline %" GST_PTR_FORMAT " is already"
167 " monitored by %" GST_PTR_FORMAT " using runner: %" GST_PTR_FORMAT
168 " NOT monitoring again.",
170 gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)));
173 for (i = 0; self->priv->pipeline_names_strv[i]; i++) {
174 if (g_pattern_match_simple (self->priv->pipeline_names_strv[i],
175 GST_OBJECT_NAME (element)))
183 do_element_new (GstValidateRunner * self, guint64 ts, GstElement * element)
185 element_created = TRUE;
186 if (gst_validate_runner_should_monitor (self, element)) {
187 /* the reference to the monitor is lost */
188 gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), self, NULL);
193 _parse_reporting_level (gchar * str, GstValidateReportingDetails * level)
201 if (g_ascii_isdigit (str[0])) {
204 l = strtoul (str, &endptr, 10);
205 if (endptr > str && endptr[0] == 0) {
206 *level = (GstValidateReportingDetails) l;
210 } else if (g_ascii_strcasecmp (str, "smart") == 0) {
211 *level = GST_VALIDATE_SHOW_SMART;
212 } else if (g_ascii_strcasecmp (str, "none") == 0) {
213 *level = GST_VALIDATE_SHOW_NONE;
214 } else if (g_ascii_strcasecmp (str, "synthetic") == 0) {
215 *level = GST_VALIDATE_SHOW_SYNTHETIC;
216 } else if (g_ascii_strcasecmp (str, "subchain") == 0) {
217 *level = GST_VALIDATE_SHOW_SUBCHAIN;
218 } else if (g_ascii_strcasecmp (str, "monitor") == 0) {
219 *level = GST_VALIDATE_SHOW_MONITOR;
220 } else if (g_ascii_strcasecmp (str, "all") == 0) {
221 *level = GST_VALIDATE_SHOW_ALL;
229 _free_report_pattern_level (PatternLevel * pattern_level)
231 g_pattern_spec_free (pattern_level->pattern);
232 g_free (pattern_level);
236 _set_reporting_level_for_name (GstValidateRunner * runner,
237 const gchar * pattern, GstValidateReportingDetails level)
239 PatternLevel *pattern_level = g_malloc (sizeof (PatternLevel));
240 GPatternSpec *pattern_spec = g_pattern_spec_new (pattern);
242 pattern_level->pattern = pattern_spec;
243 pattern_level->level = level;
245 /* Allow the user to single out a pad with the "element-name__pad-name" syntax
247 if (g_strrstr (pattern, "__"))
248 runner->priv->report_pattern_levels =
249 g_list_prepend (runner->priv->report_pattern_levels, pattern_level);
251 runner->priv->report_pattern_levels =
252 g_list_append (runner->priv->report_pattern_levels, pattern_level);
256 _replace_double_colons (gchar * word)
259 word = strstr (word, "::");
268 _set_report_levels_from_string (GstValidateRunner * self, const gchar * list)
275 GST_DEBUG_OBJECT (self, "setting report levels from string [%s]", list);
277 split = g_strsplit (list, ",", 0);
279 for (walk = split; *walk; walk++) {
280 _replace_double_colons (*walk);
281 if (strchr (*walk, ':')) {
282 gchar **values = g_strsplit (*walk, ":", 2);
284 if (values[0] && values[1]) {
285 GstValidateReportingDetails level;
287 if (_parse_reporting_level (values[1], &level))
288 _set_reporting_level_for_name (self, values[0], level);
293 GstValidateReportingDetails level;
295 if (_parse_reporting_level (*walk, &level))
296 self->priv->default_level = level;
304 _init_report_levels (GstValidateRunner * self)
308 env = g_getenv ("GST_VALIDATE_REPORTING_DETAILS");
310 _set_report_levels_from_string (self, env);
314 _unref_report_list (gpointer unused, GList * reports, gpointer unused_too)
316 g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref);
320 gst_validate_runner_finalize (GObject * object)
322 GstValidateRunner *runner = GST_VALIDATE_RUNNER_CAST (object);
324 if (!runner->priv->user_created)
325 gst_validate_runner_exit (runner, TRUE);
327 g_list_free_full (runner->priv->reports,
328 (GDestroyNotify) gst_validate_report_unref);
330 g_list_free_full (runner->priv->report_pattern_levels,
331 (GDestroyNotify) _free_report_pattern_level);
333 g_mutex_clear (&runner->priv->mutex);
335 g_free (runner->priv->pipeline_names);
336 g_strfreev (runner->priv->pipeline_names_strv);
338 g_hash_table_foreach (runner->priv->reports_by_type, (GHFunc)
339 _unref_report_list, NULL);
340 g_hash_table_destroy (runner->priv->reports_by_type);
342 G_OBJECT_CLASS (parent_class)->finalize (object);
344 if (!runner->priv->user_created)
345 gst_validate_deinit ();
349 gst_validate_runner_constructor (GType type, guint n_construct_params,
350 GObjectConstructParam * construct_params)
352 GObject *runner = G_OBJECT_CLASS (parent_class)->constructor (type,
353 n_construct_params, construct_params);
355 if (!gst_validate_is_initialized ()) {
356 first_runner = GST_VALIDATE_RUNNER (runner);
357 gst_validate_init ();
368 gst_validate_runner_get_property (GObject * object, guint prop_id,
369 GValue * value, GParamSpec * pspec)
371 GstValidateRunner *runner;
373 runner = GST_VALIDATE_RUNNER (object);
377 g_value_set_string (value, runner->priv->pipeline_names);
381 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
387 gst_validate_runner_set_property (GObject * object, guint prop_id,
388 const GValue * value, GParamSpec * pspec)
390 GstValidateRunner *runner;
392 runner = GST_VALIDATE_RUNNER (object);
396 g_free (runner->priv->pipeline_names);
397 g_strfreev (runner->priv->pipeline_names_strv);
399 runner->priv->pipeline_names = g_value_dup_string (value);
400 if (runner->priv->pipeline_names)
401 runner->priv->pipeline_names_strv =
402 g_strsplit (runner->priv->pipeline_names, ",", -1);
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 gst_validate_runner_class_init (GstValidateRunnerClass * klass)
414 GObjectClass *gobject_class;
416 gobject_class = G_OBJECT_CLASS (klass);
418 gobject_class->finalize = gst_validate_runner_finalize;
420 gobject_class->set_property = gst_validate_runner_set_property;
421 gobject_class->get_property = gst_validate_runner_get_property;
422 gobject_class->constructor = gst_validate_runner_constructor;
424 properties[PROP_PARAMS] =
425 g_param_spec_string ("params", "Params", "Extra configuration parameters",
426 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
428 g_object_class_install_properties (gobject_class, PROP_LAST, properties);
430 _signals[REPORT_ADDED_SIGNAL] =
431 g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass),
432 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1,
433 GST_TYPE_VALIDATE_REPORT);
435 _signals[STOPPING_SIGNAL] =
436 g_signal_new ("stopping", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0,
437 NULL, NULL, NULL, G_TYPE_NONE, 0);
439 GST_DEBUG_CATEGORY_INIT (gst_validate_runner_debug, "gstvalidaterunner",
440 GST_DEBUG_FG_YELLOW, "Gst validate runner");
444 gst_validate_runner_init (GstValidateRunner * runner)
446 runner->priv = gst_validate_runner_get_instance_private (runner);
448 runner->priv->reports_by_type = g_hash_table_new (g_direct_hash,
451 runner->priv->default_level = GST_VALIDATE_SHOW_DEFAULT;
452 _init_report_levels (runner);
454 runner->priv->expected_issues = gst_validate_get_test_file_expected_issues ();
456 gst_tracing_register_hook (GST_TRACER (runner), "element-new",
457 G_CALLBACK (do_element_new));
459 gst_element_register (NULL, GST_MOCKDECRYPTOR_NAME, GST_RANK_MARGINAL,
460 GST_TYPE_MOCKDECRYPTOR);
464 * gst_validate_runner_new:
466 * Create a new #GstValidateRunner
468 * Returns: A newly created #GstValidateRunner
471 gst_validate_runner_new (void)
473 GstValidateRunner *runner;
476 runner = first_runner;
478 } else if (element_created) {
480 ("Should never create a GstValidateRunner after a GstElement "
481 "has been created in the same process.");
485 runner = g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL);
486 runner->priv->user_created = TRUE;
490 GstValidateOverrideRegistry *registry =
491 gst_validate_override_registry_get ();
492 GList *all_overrides =
493 gst_validate_override_registry_get_override_list (registry);
495 for (i = all_overrides; i; i = i->next) {
496 GstValidateOverride *override = (GstValidateOverride *) i->data;
497 gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (override),
500 g_list_free (all_overrides);
507 * gst_validate_runner_get_default_reporting_level:
509 * Returns: the default #GstValidateReportingDetails used to output a report.
511 GstValidateReportingDetails
512 gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner)
514 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
515 GST_VALIDATE_SHOW_UNKNOWN);
517 return runner->priv->default_level;
520 #if !GLIB_CHECK_VERSION(2,70,0)
521 #define g_pattern_spec_match_string g_pattern_match_string
525 * gst_validate_runner_get_reporting_level_for_name:
527 * Returns: the #GstValidateReportingDetails that will be applied for a given name.
528 * If no pattern was set for such a name, this function will return
529 * #GST_VALIDATE_SHOW_UNKNOWN, and reporting for that name will
530 * default to the global reporting level.
532 GstValidateReportingDetails
533 gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner,
539 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
540 GST_VALIDATE_SHOW_UNKNOWN);
542 fixed_name = g_strdup (name);
543 _replace_double_colons (fixed_name);
544 for (tmp = runner->priv->report_pattern_levels; tmp; tmp = tmp->next) {
545 PatternLevel *pattern_level = (PatternLevel *) tmp->data;
546 if (g_pattern_spec_match_string (pattern_level->pattern, fixed_name)) {
549 return pattern_level->level;
554 return GST_VALIDATE_SHOW_UNKNOWN;
558 synthesize_reports (GstValidateRunner * runner, GstValidateReport * report)
560 GstValidateIssueId issue_id;
563 issue_id = report->issue->issue_id;
565 GST_VALIDATE_RUNNER_LOCK (runner);
567 g_hash_table_lookup (runner->priv->reports_by_type,
568 GINT_TO_POINTER (issue_id));
569 reports = g_list_append (reports, gst_validate_report_ref (report));
570 g_hash_table_insert (runner->priv->reports_by_type,
571 GINT_TO_POINTER (issue_id), reports);
572 GST_VALIDATE_RUNNER_UNLOCK (runner);
576 _dot_pipeline (GstValidateReport * report, GstStructure * config)
578 GstPipeline *pipeline = gst_validate_reporter_get_pipeline (report->reporter);
581 gint details = GST_DEBUG_GRAPH_SHOW_ALL;
582 gchar *reporter_basename =
583 g_path_get_basename (gst_validate_reporter_get_name (report->reporter));
584 report->dotfile_name =
585 g_strdup_printf ("%" GST_TIME_FORMAT "-validate-report-%s-on-%s-%s",
586 GST_TIME_ARGS (GST_CLOCK_DIFF (_priv_start_time,
587 gst_util_get_timestamp ())),
588 gst_validate_report_level_get_name (report->level), reporter_basename,
589 g_quark_to_string (report->issue->issue_id));
591 g_free (reporter_basename);
594 gst_structure_get_int (config, "details", &details);
596 GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pipeline),
597 GST_DEBUG_GRAPH_SHOW_ALL, report->dotfile_name);
599 gst_object_unref (pipeline);
605 gst_validate_runner_maybe_dot_pipeline (GstValidateRunner * runner,
606 GstValidateReport * report)
610 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL ||
611 gst_validate_report_check_abort (report)) {
613 _dot_pipeline (report, NULL);
617 for (config = gst_validate_plugin_get_config (NULL);
618 config; config = config->next) {
620 if (gst_structure_has_name (config->data, "core")) {
621 GstValidateReportLevel level;
622 const gchar *level_str,
623 *action = gst_structure_get_string (config->data, "action");
625 if (g_strcmp0 (action, "dot-pipeline"))
628 level_str = gst_structure_get_string (config->data, "report-level");
629 level = level_str ? gst_validate_report_level_from_name (level_str) :
630 GST_VALIDATE_REPORT_LEVEL_CRITICAL;
632 if (level >= report->level) {
633 _dot_pipeline (report, config->data);
642 check_report_expected (GstValidateRunner * runner, GstValidateReport * report)
646 #define GET_STR(name) gst_structure_get_string (known_issue, name)
648 for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) {
649 GstStructure *known_issue = tmp->data;
650 const gchar *id = GET_STR ("issue-id");
652 if (!id || g_quark_from_string (id) == report->issue->issue_id) {
653 const gchar *summary = GET_STR ("summary");
655 if (!summary || !g_strcmp0 (summary, report->issue->summary)) {
656 const gchar *details = GET_STR ("details");
658 if (!details || g_regex_match_simple (details, report->message, 0, 0)) {
659 const gchar *detected_on = GET_STR ("detected-on");
661 if (!detected_on || !g_strcmp0 (detected_on, report->reporter_name)) {
662 const gchar *level = GET_STR ("level");
663 const gchar *report_level =
664 gst_validate_report_level_get_name (report->level);
666 if (!detected_on || !g_strcmp0 (level, report_level)) {
667 gboolean is_sometimes;
669 if (!gst_structure_get_boolean (known_issue, "sometimes",
670 &is_sometimes) || !is_sometimes) {
671 runner->priv->expected_issues =
672 g_list_remove (runner->priv->expected_issues, known_issue);
673 gst_structure_free (known_issue);
688 gst_validate_runner_add_report (GstValidateRunner * runner,
689 GstValidateReport * report)
691 GstValidateReportingDetails details, reporter_details, issue_type_details;
693 g_return_if_fail (GST_IS_VALIDATE_RUNNER (runner));
695 if (report->level == GST_VALIDATE_REPORT_LEVEL_IGNORE)
698 if (check_report_expected (runner, report)) {
699 GST_INFO_OBJECT (runner, "Found expected issue: %p", report);
700 report->level = GST_VALIDATE_REPORT_LEVEL_EXPECTED;
703 gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report),
705 gst_validate_runner_maybe_dot_pipeline (runner, report);
707 details = reporter_details =
708 gst_validate_reporter_get_reporting_level (report->reporter);
710 gst_validate_runner_get_reporting_level_for_name (runner,
711 g_quark_to_string (report->issue->issue_id));
713 if (reporter_details == GST_VALIDATE_SHOW_UNKNOWN)
714 details = issue_type_details;
716 /* Let's use our own reporting strategy */
717 if (details == GST_VALIDATE_SHOW_UNKNOWN) {
718 gst_validate_report_set_reporting_level (report,
719 runner->priv->default_level);
720 switch (runner->priv->default_level) {
721 case GST_VALIDATE_SHOW_NONE:
723 case GST_VALIDATE_SHOW_SMART:
724 if (!gst_validate_report_check_abort (report) &&
725 report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL &&
727 synthesize_reports (runner, report);
731 case GST_VALIDATE_SHOW_SYNTHETIC:
732 if (!report->trace) {
733 synthesize_reports (runner, report);
739 } else if (details == GST_VALIDATE_SHOW_NONE) {
740 GST_DEBUG ("Not reporting.");
744 GST_VALIDATE_RUNNER_LOCK (runner);
745 runner->priv->reports =
746 g_list_append (runner->priv->reports, gst_validate_report_ref (report));
747 GST_VALIDATE_RUNNER_UNLOCK (runner);
749 g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report);
753 * gst_validate_runner_get_reports_count:
754 * @runner: The #GstValidateRunner to get the number of reports from
756 * Get the number of reports present in the runner:
758 * Returns: The number of reports present in the runner.
761 gst_validate_runner_get_reports_count (GstValidateRunner * runner)
766 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 0);
768 GST_VALIDATE_RUNNER_LOCK (runner);
769 l = g_list_length (runner->priv->reports);
770 for (tmp = runner->priv->reports; tmp; tmp = tmp->next) {
771 GstValidateReport *report = (GstValidateReport *) tmp->data;
772 l += g_list_length (report->repeated_reports);
774 l += g_hash_table_size (runner->priv->reports_by_type);
775 GST_VALIDATE_RUNNER_UNLOCK (runner);
781 * gst_validate_runner_get_reports:
782 * @runner: The #GstValidateRunner
784 * Returns: (element-type GstValidateReport) (transfer full): The list of reports
787 gst_validate_runner_get_reports (GstValidateRunner * runner)
791 GST_VALIDATE_RUNNER_LOCK (runner);
793 g_list_copy_deep (runner->priv->reports,
794 (GCopyFunc) gst_validate_report_ref, NULL);
795 GST_VALIDATE_RUNNER_UNLOCK (runner);
801 _do_report_synthesis (GstValidateRunner * runner)
804 GList *reports, *tmp;
806 GList *criticals = NULL;
808 /* Take the lock so the hash table won't be modified while we are iterating
810 GST_VALIDATE_RUNNER_LOCK (runner);
811 g_hash_table_iter_init (&iter, runner->priv->reports_by_type);
812 while (g_hash_table_iter_next (&iter, &key, &value)) {
813 GstValidateReport *report;
814 reports = (GList *) value;
819 report = (GstValidateReport *) (reports->data);
821 gst_validate_report_print_level (report);
822 gst_validate_report_print_detected_on (report);
824 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
825 criticals = g_list_append (criticals, report);
826 gst_validate_report_print_details (report);
827 } else if (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)
828 gst_validate_report_print_details (report);
830 for (tmp = g_list_next (reports); tmp; tmp = tmp->next) {
831 report = (GstValidateReport *) tmp->data;
832 gst_validate_report_print_detected_on (report);
834 if ((report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) ||
835 (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)) {
836 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
837 criticals = g_list_append (criticals, report);
838 gst_validate_report_print_details (report);
841 report = (GstValidateReport *) (reports->data);
842 gst_validate_report_print_description (report);
843 gst_validate_printf (NULL, "\n");
845 GST_VALIDATE_RUNNER_UNLOCK (runner);
851 * gst_validate_runner_printf:
852 * @runner: The #GstValidateRunner to print all the reports for
854 * Prints all the reports on the terminal or on wherever is set
855 * in the `GST_VALIDATE_FILE` env variable.
857 * Returns: 0 if no critical error has been found and 18 if a critical
858 * error has been detected. That return value is usually to be used as
859 * exit code of the application.
862 gst_validate_runner_printf (GstValidateRunner * runner)
864 GList *reports, *tmp;
866 GList *criticals = NULL;
868 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1);
870 criticals = _do_report_synthesis (runner);
871 reports = gst_validate_runner_get_reports (runner);
872 for (tmp = reports; tmp; tmp = tmp->next) {
873 GstValidateReport *report = (GstValidateReport *) tmp->data;
875 if (gst_validate_report_should_print (report))
876 gst_validate_report_printf (report);
878 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
879 criticals = g_list_append (criticals, report);
885 g_printerr ("\n\n**Got criticals. Return value set to 18**:\n");
887 for (iter = criticals; iter; iter = iter->next) {
888 g_printerr (" * critical error %s\n",
889 ((GstValidateReport *) (iter->data))->message);
894 g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref);
895 g_list_free (criticals);
896 gst_validate_printf (NULL, "Issues found: %u\n",
897 gst_validate_runner_get_reports_count (runner));
902 gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result)
905 GList *tmp, *configs;
907 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1);
909 g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0);
911 ret = gst_validate_runner_printf (runner);
914 for (tmp = runner->priv->reports; tmp; tmp = tmp->next) {
915 GstValidateReport *report = (GstValidateReport *) tmp->data;
916 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
921 configs = gst_validate_get_config (NULL);
922 for (tmp = configs; tmp; tmp = tmp->next) {
923 if (!gst_structure_has_field (tmp->data, "__n_usages__")) {
924 gst_validate_error_structure (tmp->data,
925 "Unused config: '%" GST_PTR_FORMAT "'", tmp->data);
928 g_list_free (configs);
930 for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) {
931 GstStructure *known_issue = tmp->data;
932 gboolean is_sometimes;
934 if (!gst_structure_get_boolean (known_issue, "sometimes", &is_sometimes)
936 GstStructure *tmpstruct = gst_structure_copy (known_issue);
937 gst_structure_remove_fields (tmpstruct, "__debug__", "__lineno__",
938 "__filename__", NULL);
939 /* Ideally we should report an issue here.. but we do not have a reporter */
940 gst_validate_error_structure (known_issue,
941 "Expected issue didn't happen: '%" GST_PTR_FORMAT "'", tmpstruct);
942 gst_structure_free (tmpstruct);
946 g_list_free_full (runner->priv->expected_issues,
947 (GDestroyNotify) gst_structure_free);
948 runner->priv->expected_issues = NULL;
954 gst_validate_init_runner (void)
957 first_runner = g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL);
958 first_runner->priv->user_created = TRUE;
959 } /* else the first runner has been created through the GST_TRACERS system */
963 gst_validate_deinit_runner (void)
965 g_clear_object (&first_runner);
968 GstValidateReportingDetails
969 gst_validate_runner_get_default_reporting_details (GstValidateRunner * runner)
971 g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
972 GST_VALIDATE_SHOW_UNKNOWN);
974 return runner->priv->default_level;
977 #ifdef __GST_VALIDATE_PLUGIN
979 plugin_init (GstPlugin * plugin)
981 if (!gst_tracer_register (plugin, "validate", GST_TYPE_VALIDATE_RUNNER))
987 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, validatetracer,
988 "GStreamer Validate tracers", plugin_init, VERSION, GST_LICENSE,
989 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
990 #endif /* __GST_VALIDATE_PLUGIN */