#include "gst-validate-monitor-factory.h"
#include "gst-validate-override-registry.h"
#include "gst-validate-runner.h"
+#include "gst-validate-reporter.h"
+#include "gst-validate-mockdecryptor.h"
GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug);
#undef GST_CAT_DEFAULT
/**
* SECTION:gst-validate-runner
+ * @title: GstValidateRunner
* @short_description: Class that runs Gst Validate tests for a pipeline
*
* Allows you to test a pipeline within GstValidate. It is the object where
* gst_object_unref (runner);
* gst_object_unref (monitor);
* ]|
+ *
*/
struct _GstValidateRunnerPrivate
gchar *pipeline_names;
gchar **pipeline_names_strv;
+
+ GList *expected_issues;
};
/* Describes the reporting level to apply to a name pattern */
} G_STMT_END
#define gst_validate_runner_parent_class parent_class
-G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, GST_TYPE_TRACER);
+G_DEFINE_TYPE_WITH_PRIVATE (GstValidateRunner, gst_validate_runner,
+ GST_TYPE_TRACER);
/* signals */
enum
gobject_class->get_property = gst_validate_runner_get_property;
gobject_class->constructor = gst_validate_runner_constructor;
- g_type_class_add_private (klass, sizeof (GstValidateRunnerPrivate));
-
properties[PROP_PARAMS] =
g_param_spec_string ("params", "Params", "Extra configuration parameters",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
static void
gst_validate_runner_init (GstValidateRunner * runner)
{
- runner->priv = G_TYPE_INSTANCE_GET_PRIVATE (runner, GST_TYPE_VALIDATE_RUNNER,
- GstValidateRunnerPrivate);
- g_mutex_init (&runner->priv->mutex);
+ runner->priv = gst_validate_runner_get_instance_private (runner);
runner->priv->reports_by_type = g_hash_table_new (g_direct_hash,
g_direct_equal);
runner->priv->default_level = GST_VALIDATE_SHOW_DEFAULT;
_init_report_levels (runner);
+ runner->priv->expected_issues = gst_validate_get_test_file_expected_issues ();
+
gst_tracing_register_hook (GST_TRACER (runner), "element-new",
G_CALLBACK (do_element_new));
+
+ gst_element_register (NULL, GST_MOCKDECRYPTOR_NAME, GST_RANK_MARGINAL,
+ GST_TYPE_MOCKDECRYPTOR);
}
/**
runner = first_runner;
first_runner = NULL;
} else if (element_created) {
- g_error ("Should never create a GstValidateRunner after a GstElement"
+ gst_validate_abort
+ ("Should never create a GstValidateRunner after a GstElement "
"has been created in the same process.");
return NULL;
runner->priv->user_created = TRUE;
}
+ {
+ GstValidateOverrideRegistry *registry =
+ gst_validate_override_registry_get ();
+ GList *all_overrides =
+ gst_validate_override_registry_get_override_list (registry);
+ GList *i;
+ for (i = all_overrides; i; i = i->next) {
+ GstValidateOverride *override = (GstValidateOverride *) i->data;
+ gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (override),
+ runner);
+ }
+ g_list_free (all_overrides);
+ }
+
return runner;
}
GstValidateReportingDetails
gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner)
{
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
+ GST_VALIDATE_SHOW_UNKNOWN);
+
return runner->priv->default_level;
}
const gchar * name)
{
GList *tmp;
+ gchar *fixed_name;
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
+ GST_VALIDATE_SHOW_UNKNOWN);
+
+ fixed_name = g_strdup (name);
+ _replace_double_colons (fixed_name);
for (tmp = runner->priv->report_pattern_levels; tmp; tmp = tmp->next) {
PatternLevel *pattern_level = (PatternLevel *) tmp->data;
- if (g_pattern_match_string (pattern_level->pattern, name))
+ if (g_pattern_match_string (pattern_level->pattern, fixed_name)) {
+ g_free (fixed_name);
+
return pattern_level->level;
+ }
}
+ g_free (fixed_name);
return GST_VALIDATE_SHOW_UNKNOWN;
}
GST_VALIDATE_RUNNER_UNLOCK (runner);
}
+static void
+_dot_pipeline (GstValidateReport * report, GstStructure * config)
+{
+ GstPipeline *pipeline = gst_validate_reporter_get_pipeline (report->reporter);
+
+ if (pipeline) {
+ gint details = GST_DEBUG_GRAPH_SHOW_ALL;
+ gchar *reporter_basename =
+ g_path_get_basename (gst_validate_reporter_get_name (report->reporter));
+ report->dotfile_name =
+ g_strdup_printf ("%" GST_TIME_FORMAT "-validate-report-%s-on-%s-%s",
+ GST_TIME_ARGS (GST_CLOCK_DIFF (_priv_start_time,
+ gst_util_get_timestamp ())),
+ gst_validate_report_level_get_name (report->level), reporter_basename,
+ g_quark_to_string (report->issue->issue_id));
+
+ g_free (reporter_basename);
+
+ if (config)
+ gst_structure_get_int (config, "details", &details);
+
+ GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pipeline),
+ GST_DEBUG_GRAPH_SHOW_ALL, report->dotfile_name);
+
+ gst_object_unref (pipeline);
+ }
+
+}
+
+static void
+gst_validate_runner_maybe_dot_pipeline (GstValidateRunner * runner,
+ GstValidateReport * report)
+{
+ GList *config;
+
+ if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL ||
+ gst_validate_report_check_abort (report)) {
+
+ _dot_pipeline (report, NULL);
+ return;
+ }
+
+ for (config = gst_validate_plugin_get_config (NULL);
+ config; config = config->next) {
+
+ if (gst_structure_has_name (config->data, "core")) {
+ GstValidateReportLevel level;
+ const gchar *level_str,
+ *action = gst_structure_get_string (config->data, "action");
+
+ if (g_strcmp0 (action, "dot-pipeline"))
+ continue;
+
+ level_str = gst_structure_get_string (config->data, "report-level");
+ level = level_str ? gst_validate_report_level_from_name (level_str) :
+ GST_VALIDATE_REPORT_LEVEL_CRITICAL;
+
+ if (level >= report->level) {
+ _dot_pipeline (report, config->data);
+
+ return;
+ }
+ }
+ }
+}
+
+static gboolean
+check_report_expected (GstValidateRunner * runner, GstValidateReport * report)
+{
+ GList *tmp;
+
+#define GET_STR(name) gst_structure_get_string (known_issue, name)
+
+ for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) {
+ GstStructure *known_issue = tmp->data;
+ const gchar *id = GET_STR ("issue-id");
+
+ if (!id || g_quark_from_string (id) == report->issue->issue_id) {
+ const gchar *summary = GET_STR ("summary");
+
+ if (!summary || !g_strcmp0 (summary, report->issue->summary)) {
+ const gchar *details = GET_STR ("details");
+
+ if (!details || g_regex_match_simple (details, report->message, 0, 0)) {
+ const gchar *detected_on = GET_STR ("detected-on");
+
+ if (!detected_on || !g_strcmp0 (detected_on, report->reporter_name)) {
+ const gchar *level = GET_STR ("level");
+ const gchar *report_level =
+ gst_validate_report_level_get_name (report->level);
+
+ if (!detected_on || !g_strcmp0 (level, report_level)) {
+ gboolean is_sometimes;
+
+ if (!gst_structure_get_boolean (known_issue, "sometimes",
+ &is_sometimes) || !is_sometimes) {
+ runner->priv->expected_issues =
+ g_list_remove (runner->priv->expected_issues, known_issue);
+ gst_structure_free (known_issue);
+ }
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+#undef GET_STR
+ }
+
+ return FALSE;
+}
+
void
gst_validate_runner_add_report (GstValidateRunner * runner,
GstValidateReport * report)
{
- GstValidateReportingDetails reporter_level =
- gst_validate_reporter_get_reporting_level (report->reporter);
+ GstValidateReportingDetails details, reporter_details, issue_type_details;
+
+ g_return_if_fail (GST_IS_VALIDATE_RUNNER (runner));
+
+ if (report->level == GST_VALIDATE_REPORT_LEVEL_IGNORE)
+ return;
+
+ if (check_report_expected (runner, report)) {
+ GST_INFO_OBJECT (runner, "Found expected issue: %p", report);
+ report->level = GST_VALIDATE_REPORT_LEVEL_EXPECTED;
+ }
gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report),
report));
+ gst_validate_runner_maybe_dot_pipeline (runner, report);
+
+ details = reporter_details =
+ gst_validate_reporter_get_reporting_level (report->reporter);
+ issue_type_details =
+ gst_validate_runner_get_reporting_level_for_name (runner,
+ g_quark_to_string (report->issue->issue_id));
+
+ if (reporter_details == GST_VALIDATE_SHOW_UNKNOWN)
+ details = issue_type_details;
/* Let's use our own reporting strategy */
- if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) {
+ if (details == GST_VALIDATE_SHOW_UNKNOWN) {
gst_validate_report_set_reporting_level (report,
runner->priv->default_level);
switch (runner->priv->default_level) {
return;
case GST_VALIDATE_SHOW_SMART:
if (!gst_validate_report_check_abort (report) &&
- report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
+ report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL &&
+ !report->trace) {
synthesize_reports (runner, report);
return;
}
+ break;
case GST_VALIDATE_SHOW_SYNTHETIC:
- synthesize_reports (runner, report);
- return;
+ if (!report->trace) {
+ synthesize_reports (runner, report);
+ return;
+ }
default:
break;
}
+ } else if (details == GST_VALIDATE_SHOW_NONE) {
+ GST_DEBUG ("Not reporting.");
+ return;
}
GST_VALIDATE_RUNNER_LOCK (runner);
/**
* gst_validate_runner_get_reports_count:
- * @runner: The $GstValidateRunner to get the number of report from
+ * @runner: The $GstValidateRunner to get the number of reports from
*
* Get the number of reports present in the runner:
*
- * Returns: The number of report present in the runner.
+ * Returns: The number of reports present in the runner.
*/
guint
gst_validate_runner_get_reports_count (GstValidateRunner * runner)
GList *tmp;
guint l;
- g_return_val_if_fail (runner != NULL, 0);
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 0);
GST_VALIDATE_RUNNER_LOCK (runner);
l = g_list_length (runner->priv->reports);
- for (tmp = runner->priv->reports; tmp; tmp = tmp->next)
- l += g_list_length (((GstValidateReport *) tmp->data)->repeated_reports);
+ for (tmp = runner->priv->reports; tmp; tmp = tmp->next) {
+ GstValidateReport *report = (GstValidateReport *) tmp->data;
+ l += g_list_length (report->repeated_reports);
+ }
l += g_hash_table_size (runner->priv->reports_by_type);
GST_VALIDATE_RUNNER_UNLOCK (runner);
* gst_validate_runner_get_reports:
* @runner: The #GstValidateRunner
*
- * Return: (element-type GstValidate.Report)(transfer full): all the reports
+ * Return: (element-type GstValidateReport)(transfer full): all the reports
*/
GList *
gst_validate_runner_get_reports (GstValidateRunner * runner)
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
criticals = g_list_append (criticals, report);
gst_validate_report_print_details (report);
- }
+ } else if (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)
+ gst_validate_report_print_details (report);
for (tmp = g_list_next (reports); tmp; tmp = tmp->next) {
- report = (GstValidateReport *) (tmp->data);
+ report = (GstValidateReport *) tmp->data;
gst_validate_report_print_detected_on (report);
- if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
- criticals = g_list_append (criticals, report);
+ if ((report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) ||
+ (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)) {
+ if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
+ criticals = g_list_append (criticals, report);
gst_validate_report_print_details (report);
}
}
* gst_validate_runner_printf:
* @runner: The #GstValidateRunner to print all the reports for
*
- * Prints all the report on the terminal or on wherever set
- * in the #GST_VALIDATE_FILE env variable.
+ * Prints all the reports on the terminal or on wherever is set
+ * in the `GST_VALIDATE_FILE` env variable.
*
* Returns: 0 if no critical error has been found and 18 if a critical
* error has been detected. That return value is usually to be used as
int ret = 0;
GList *criticals = NULL;
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1);
+
criticals = _do_report_synthesis (runner);
reports = gst_validate_runner_get_reports (runner);
for (tmp = reports; tmp; tmp = tmp->next) {
- GstValidateReport *report = tmp->data;
+ GstValidateReport *report = (GstValidateReport *) tmp->data;
if (gst_validate_report_should_print (report))
gst_validate_report_printf (report);
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
- criticals = g_list_append (criticals, tmp->data);
+ criticals = g_list_append (criticals, report);
}
}
if (criticals) {
GList *iter;
-
- g_printerr ("\n\n==== Got criticals, Return value set to 18 ====\n");
+ g_printerr ("\n\n**Got criticals. Return value set to 18**:\n");
ret = 18;
-
for (iter = criticals; iter; iter = iter->next) {
- g_printerr (" Critical error %s\n",
+ g_printerr (" * critical error %s\n",
((GstValidateReport *) (iter->data))->message);
}
g_printerr ("\n");
gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result)
{
gint ret = 0;
+ GList *tmp, *configs;
- g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0);
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1);
+ g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0);
if (print_result) {
ret = gst_validate_runner_printf (runner);
} else {
GList *tmp;
-
for (tmp = runner->priv->reports; tmp; tmp = tmp->next) {
- GstValidateReport *report = tmp->data;
-
+ GstValidateReport *report = (GstValidateReport *) tmp->data;
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
ret = 18;
}
}
+ configs = gst_validate_get_config (NULL);
+ for (tmp = configs; tmp; tmp = tmp->next) {
+ if (!gst_structure_has_field (tmp->data, "__n_usages__")) {
+ gst_validate_error_structure (tmp->data,
+ "Unused config: '%" GST_PTR_FORMAT "'", tmp->data);
+ }
+ }
+ g_list_free (configs);
+
+ for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) {
+ GstStructure *known_issue = tmp->data;
+ gboolean is_sometimes;
+
+ if (!gst_structure_get_boolean (known_issue, "sometimes", &is_sometimes)
+ || !is_sometimes) {
+ GstStructure *tmpstruct = gst_structure_copy (known_issue);
+ gst_structure_remove_fields (tmpstruct, "__debug__", "__lineno__",
+ "__filename__", NULL);
+ /* Ideally we should report an issue here.. but we do not have a reporter */
+ gst_validate_error_structure (known_issue,
+ "Expected issue didn't happen: '%" GST_PTR_FORMAT "'", tmpstruct);
+ gst_structure_free (tmpstruct);
+ }
+ }
+
+ g_list_free_full (runner->priv->expected_issues,
+ (GDestroyNotify) gst_structure_free);
+ runner->priv->expected_issues = NULL;
+
return ret;
}
GstValidateReportingDetails
gst_validate_runner_get_default_reporting_details (GstValidateRunner * runner)
{
+ g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner),
+ GST_VALIDATE_SHOW_UNKNOWN);
+
return runner->priv->default_level;
}