validate: Pass information about GstValidate execution over a socket

Instead of trying to parsing stdout, generate json messages and
send them over a socket so that gst-validate-launcher can properly
have informations about gst-validate subprocess execution.
This commit is contained in:
Thibault Saunier 2016-09-01 17:39:38 -03:00
parent 29e5ac1362
commit 2fff14e469
11 changed files with 333 additions and 117 deletions

View file

@ -201,6 +201,10 @@ if test "x$HAVE_CAIRO" != "xyes"; then
AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool]) AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool])
fi fi
PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0)
AC_SUBST(JSON_GLIB_LIBS)
AC_SUBST(JSON_GLIB_CFLAGS)
dnl checks for gstreamer dnl checks for gstreamer
AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)

View file

@ -50,14 +50,14 @@ lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la
libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c)
libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h)
libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\
$(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \
-DGST_USE_UNSTABLE_API -DGST_USE_UNSTABLE_API
libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
$(GLIB_LIBS) $(LIBM) $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM)
libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate
@ -71,9 +71,9 @@ libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\
libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
$(GLIB_LIBS) $(LIBM) $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM)
CLEANFILES = CLEANFILES =

View file

@ -25,6 +25,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gst-validate-scenario.h" #include "gst-validate-scenario.h"
#include "gst-validate-monitor.h" #include "gst-validate-monitor.h"
#include <json-glib/json-glib.h>
GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug);
#define GST_CAT_DEFAULT gstvalidate_debug #define GST_CAT_DEFAULT gstvalidate_debug
@ -49,5 +50,6 @@ G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void);
G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object); G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object);
G_GNUC_INTERNAL void gst_validate_init_runner (void); G_GNUC_INTERNAL void gst_validate_init_runner (void);
G_GNUC_INTERNAL void gst_validate_deinit_runner (void); G_GNUC_INTERNAL void gst_validate_deinit_runner (void);
G_GNUC_INTERNAL void gst_validate_report_deinit (void);
gboolean gst_validate_send (JsonNode * root);
#endif #endif

View file

@ -90,6 +90,7 @@ print_position (GstValidateMonitor * monitor)
{ {
GstQuery *query; GstQuery *query;
gint64 position, duration; gint64 position, duration;
JsonBuilder *jbuilder;
GstElement *pipeline = GstElement *pipeline =
GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor));
@ -114,6 +115,21 @@ print_position (GstValidateMonitor * monitor)
gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_parse_segment (query, &rate, NULL, NULL, NULL);
gst_query_unref (query); gst_query_unref (query);
jbuilder = json_builder_new ();
json_builder_begin_object (jbuilder);
json_builder_set_member_name (jbuilder, "type");
json_builder_add_string_value (jbuilder, "position");
json_builder_set_member_name (jbuilder, "position");
json_builder_add_int_value (jbuilder, position);
json_builder_set_member_name (jbuilder, "duration");
json_builder_add_int_value (jbuilder, duration);
json_builder_set_member_name (jbuilder, "speed");
json_builder_add_double_value (jbuilder, rate);
json_builder_end_object (jbuilder);
gst_validate_send (json_builder_get_root (jbuilder));
g_object_unref (jbuilder);
gst_validate_printf (NULL, gst_validate_printf (NULL,
"<position: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT "<position: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT
" speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), " speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration),
@ -423,15 +439,21 @@ _bus_handler (GstBus * bus, GstMessage * message,
} }
case GST_MESSAGE_BUFFERING: case GST_MESSAGE_BUFFERING:
{ {
JsonBuilder *jbuilder = json_builder_new ();
GstBufferingMode mode; GstBufferingMode mode;
gint percent; gint percent;
gst_message_parse_buffering (message, &percent); gst_message_parse_buffering (message, &percent);
gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
json_builder_begin_object (jbuilder);
json_builder_set_member_name (jbuilder, "type");
json_builder_add_string_value (jbuilder, "buffering");
json_builder_set_member_name (jbuilder, "state");
if (percent == 100) { if (percent == 100) {
/* a 100% message means buffering is done */ /* a 100% message means buffering is done */
gst_validate_printf (NULL, "\nDone buffering\n"); gst_validate_printf (NULL, "\nDone buffering\n");
json_builder_add_string_value (jbuilder, "done");
if (monitor->buffering) { if (monitor->buffering) {
monitor->print_pos_srcid = monitor->print_pos_srcid =
g_timeout_add (PRINT_POSITION_TIMEOUT, g_timeout_add (PRINT_POSITION_TIMEOUT,
@ -443,13 +465,22 @@ _bus_handler (GstBus * bus, GstMessage * message,
if (!monitor->buffering) { if (!monitor->buffering) {
monitor->buffering = TRUE; monitor->buffering = TRUE;
gst_validate_printf (NULL, "\nStart buffering\n"); gst_validate_printf (NULL, "\nStart buffering\n");
json_builder_add_string_value (jbuilder, "started");
if (monitor->print_pos_srcid if (monitor->print_pos_srcid
&& g_source_remove (monitor->print_pos_srcid)) { && g_source_remove (monitor->print_pos_srcid)) {
monitor->print_pos_srcid = 0; monitor->print_pos_srcid = 0;
} }
} else {
json_builder_add_string_value (jbuilder, "progress");
} }
gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent); gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent);
} }
json_builder_set_member_name (jbuilder, "position");
json_builder_add_int_value (jbuilder, percent);
json_builder_end_object (jbuilder);
gst_validate_send (json_builder_get_root (jbuilder));
g_object_unref (jbuilder);
break; break;
} }
case GST_MESSAGE_STREAM_COLLECTION: case GST_MESSAGE_STREAM_COLLECTION:

View file

@ -43,8 +43,48 @@ static GstValidateDebugFlags _gst_validate_flags = 0;
static GHashTable *_gst_validate_issues = NULL; static GHashTable *_gst_validate_issues = NULL;
static FILE **log_files = NULL; static FILE **log_files = NULL;
GType _gst_validate_report_type; /* Tcp server for communications with gst-validate-launcher */
GST_DEFINE_MINI_OBJECT_TYPE (GstValidateReport, gst_validate_report); GSocketClient *socket_client = NULL;
GSocketConnection *server_connection = NULL;
GOutputStream *server_ostream = NULL;
GType _gst_validate_report_type = 0;
static JsonNode *
gst_validate_report_serialize (GstValidateReport * report)
{
JsonNode *node = json_node_alloc ();
JsonObject *jreport = json_object_new ();
json_object_set_string_member (jreport, "type", "report");
json_object_set_string_member (jreport, "summary", report->issue->summary);
json_object_set_string_member (jreport, "level",
gst_validate_report_level_get_name (report->level));
json_object_set_string_member (jreport, "detected-on", report->reporter_name);
json_object_set_string_member (jreport, "details", report->message);
node = json_node_init_object (node, jreport);
return node;
}
GType
gst_validate_report_get_type (void)
{
if (_gst_validate_report_type == 0) {
_gst_validate_report_type =
g_boxed_type_register_static (g_intern_static_string
("GstValidateReport"), (GBoxedCopyFunc) gst_mini_object_ref,
(GBoxedFreeFunc) gst_mini_object_unref);
json_boxed_register_serialize_func (_gst_validate_report_type,
JSON_NODE_OBJECT,
(JsonBoxedSerializeFunc) gst_validate_report_serialize);
}
return _gst_validate_report_type;
}
GRegex *newline_regex = NULL; GRegex *newline_regex = NULL;
@ -319,8 +359,7 @@ gst_validate_report_load_issues (void)
_("a gstreamer plugin is missing and prevented Validate from running"), _("a gstreamer plugin is missing and prevented Validate from running"),
NULL); NULL);
REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED, REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED,
_("a NOT NEGOTIATED message has been emitted on the bus."), _("a NOT NEGOTIATED message has been posted on the bus."), NULL);
NULL);
REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS, REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS,
_("We got a WARNING message on the bus"), NULL); _("We got a WARNING message on the bus"), NULL);
REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS, REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS,
@ -348,10 +387,58 @@ gst_validate_report_load_issues (void)
REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL);
} }
gboolean
gst_validate_send (JsonNode * root)
{
gboolean res = FALSE;
JsonGenerator *jgen;
gsize message_length;
gchar *object, *message;
GError *error = NULL;
if (!server_ostream)
goto done;
jgen = json_generator_new ();
json_generator_set_root (jgen, root);
object = json_generator_to_data (jgen, &message_length);
message = g_malloc0 (message_length + 5);
GST_WRITE_UINT32_BE (message, message_length);
strcpy (&message[4], object);
g_free (object);
res = g_output_stream_write_all (server_ostream, message, message_length + 4,
NULL, NULL, &error);
if (!res) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) {
GST_ERROR ("Stream was busy, trying again later.");
g_free (message);
g_object_unref (jgen);
g_idle_add ((GSourceFunc) gst_validate_send, root);
return G_SOURCE_REMOVE;
}
GST_ERROR ("ERROR: Can't write to remote: %s", error->message);
} else if (!g_output_stream_flush (server_ostream, NULL, &error)) {
GST_ERROR ("ERROR: Can't flush stream: %s", error->message);
}
g_free (message);
g_object_unref (jgen);
done:
json_node_free (root);
return G_SOURCE_REMOVE;
}
void void
gst_validate_report_init (void) gst_validate_report_init (void)
{ {
const gchar *var, *file_env; const gchar *var, *file_env, *server_env;
const GDebugKey keys[] = { const GDebugKey keys[] = {
{"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS},
{"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS},
@ -379,6 +466,42 @@ gst_validate_report_init (void)
gst_validate_report_load_issues (); gst_validate_report_load_issues ();
} }
server_env = g_getenv ("GST_VALIDATE_SERVER");
if (server_env) {
GstUri *server_uri = gst_uri_from_string (server_env);
if (server_uri && !g_strcmp0 (gst_uri_get_scheme (server_uri), "tcp")) {
JsonBuilder *jbuilder;
GError *err = NULL;
socket_client = g_socket_client_new ();
server_connection = g_socket_client_connect_to_host (socket_client,
gst_uri_get_host (server_uri), gst_uri_get_port (server_uri),
NULL, &err);
if (!server_connection) {
g_clear_error (&err);
g_clear_object (&socket_client);
} else {
server_ostream =
g_io_stream_get_output_stream (G_IO_STREAM (server_connection));
jbuilder = json_builder_new ();
json_builder_begin_object (jbuilder);
json_builder_set_member_name (jbuilder, "started");
json_builder_add_boolean_value (jbuilder, TRUE);
json_builder_end_object (jbuilder);
gst_validate_send (json_builder_get_root (jbuilder));
g_object_unref (jbuilder);
}
gst_uri_unref (server_uri);
} else {
GST_ERROR ("Server URI not valid: %s", server_env);
}
}
file_env = g_getenv ("GST_VALIDATE_FILE"); file_env = g_getenv ("GST_VALIDATE_FILE");
if (file_env != NULL && *file_env != '\0') { if (file_env != NULL && *file_env != '\0') {
gint i; gint i;
@ -391,12 +514,11 @@ gst_validate_report_init (void)
g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1)); g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1));
for (i = 0; i < g_strv_length (wanted_files); i++) { for (i = 0; i < g_strv_length (wanted_files); i++) {
FILE *log_file; FILE *log_file;
if (g_strcmp0 (wanted_files[i], "stderr") == 0) { if (g_strcmp0 (wanted_files[i], "stderr") == 0) {
log_file = stderr; log_file = stderr;
} else if (g_strcmp0 (wanted_files[i], "stdout") == 0) } else if (g_strcmp0 (wanted_files[i], "stdout") == 0) {
log_file = stdout; log_file = stdout;
else { } else {
log_file = g_fopen (wanted_files[i], "w"); log_file = g_fopen (wanted_files[i], "w");
} }
@ -422,6 +544,16 @@ gst_validate_report_init (void)
#endif #endif
} }
void
gst_validate_report_deinit (void)
{
if (server_ostream)
g_output_stream_close (server_ostream, NULL, NULL);
g_clear_object (&socket_client);
g_clear_object (&server_connection);
g_clear_object (&server_ostream);
}
GstValidateIssue * GstValidateIssue *
gst_validate_issue_from_id (GstValidateIssueId issue_id) gst_validate_issue_from_id (GstValidateIssueId issue_id)
{ {

View file

@ -538,6 +538,8 @@ gst_validate_runner_add_report (GstValidateRunner * runner,
GstValidateReportingDetails reporter_level = GstValidateReportingDetails reporter_level =
gst_validate_reporter_get_reporting_level (report->reporter); gst_validate_reporter_get_reporting_level (report->reporter);
gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report),
report));
/* Let's use our own reporting strategy */ /* Let's use our own reporting strategy */
if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) { if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) {
gst_validate_report_set_reporting_level (report, gst_validate_report_set_reporting_level (report,
@ -633,18 +635,23 @@ _do_report_synthesis (GstValidateRunner * runner)
continue; continue;
report = (GstValidateReport *) (reports->data); report = (GstValidateReport *) (reports->data);
gst_validate_report_print_level (report); gst_validate_report_print_level (report);
gst_validate_report_print_detected_on (report); gst_validate_report_print_detected_on (report);
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
criticals = g_list_append (criticals, report); criticals = g_list_append (criticals, report);
gst_validate_report_print_details (report);
}
for (tmp = g_list_next (reports); tmp; tmp = tmp->next) { 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); gst_validate_report_print_detected_on (report);
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
criticals = g_list_append (criticals, report); criticals = g_list_append (criticals, report);
gst_validate_report_print_details (report);
}
} }
report = (GstValidateReport *) (reports->data); report = (GstValidateReport *) (reports->data);
gst_validate_report_print_description (report); gst_validate_report_print_description (report);

View file

@ -188,7 +188,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario,
_reporter_iface_init)); _reporter_iface_init));
/* GstValidateAction implementation */ /* GstValidateAction implementation */
GType _gst_validate_action_type; GType _gst_validate_action_type = 0;
struct _GstValidateActionPrivate struct _GstValidateActionPrivate
{ {
@ -204,7 +204,42 @@ struct _GstValidateActionPrivate
GWeakRef scenario; GWeakRef scenario;
}; };
GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static JsonNode *
gst_validate_action_serialize (GstValidateAction * action)
{
JsonNode *node = json_node_alloc ();
JsonObject *jreport = json_object_new ();
gchar *action_args = gst_structure_to_string (action->structure);
json_object_set_string_member (jreport, "type", "action");
json_object_set_string_member (jreport, "action-type", action->type);
json_object_set_int_member (jreport, "playback-time",
(gint64) action->playback_time);
json_object_set_string_member (jreport, "args", action_args);
g_free (action_args);
node = json_node_init_object (node, jreport);
return node;
}
GType
gst_validate_action_get_type (void)
{
if (_gst_validate_action_type == 0) {
_gst_validate_action_type =
g_boxed_type_register_static (g_intern_static_string
("GstValidateAction"), (GBoxedCopyFunc) gst_mini_object_ref,
(GBoxedFreeFunc) gst_mini_object_unref);
json_boxed_register_serialize_func (_gst_validate_action_type,
JSON_NODE_OBJECT,
(JsonBoxedSerializeFunc) gst_validate_action_serialize);
}
return _gst_validate_action_type;
}
static GstValidateAction *gst_validate_action_new (GstValidateScenario * static GstValidateAction *gst_validate_action_new (GstValidateScenario *
scenario, GstValidateActionType * type); scenario, GstValidateActionType * type);
static gboolean execute_next_action (GstValidateScenario * scenario); static gboolean execute_next_action (GstValidateScenario * scenario);
@ -294,6 +329,9 @@ gboolean
_action_check_and_set_printed (GstValidateAction * action) _action_check_and_set_printed (GstValidateAction * action)
{ {
if (action->priv->printed == FALSE) { if (action->priv->printed == FALSE) {
gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE
(action), action));
action->priv->printed = TRUE; action->priv->printed = TRUE;
return FALSE; return FALSE;

View file

@ -46,7 +46,7 @@ gstvalidate = shared_library('gstvalidate',
install: true, install: true,
c_args : [gst_c_args], c_args : [gst_c_args],
dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep,
gst_pbutils_dep, mathlib]) gst_pbutils_dep, mathlib, json_dep])
validate_gen_sources = [] validate_gen_sources = []
if build_gir if build_gir

View file

@ -276,6 +276,7 @@ gst_validate_deinit (void)
_priv_validate_override_registry_deinit (); _priv_validate_override_registry_deinit ();
core_config = NULL; core_config = NULL;
validate_initialized = FALSE; validate_initialized = FALSE;
gst_validate_report_deinit ();
g_mutex_unlock (&_gst_validate_registry_mutex); g_mutex_unlock (&_gst_validate_registry_mutex);
g_mutex_clear (&_gst_validate_registry_mutex); g_mutex_clear (&_gst_validate_registry_mutex);

View file

@ -19,9 +19,12 @@
""" Class representing tests and test managers. """ """ Class representing tests and test managers. """
import json
import os import os
import sys import sys
import re import re
import SocketServer
import struct
import time import time
import utils import utils
import signal import signal
@ -441,6 +444,33 @@ class Test(Loggable):
return self.result return self.result
class GstValidateListener(SocketServer.BaseRequestHandler):
def handle(self):
"""Implements BaseRequestHandler handle method"""
while True:
raw_len = self.request.recv(4)
if raw_len == '':
return
msglen = struct.unpack('>I', raw_len)[0]
msg = self.request.recv(msglen)
if msg == '':
return
obj = json.loads(msg)
test = getattr(self.server, "test")
obj_type = obj.get("type", '')
if obj_type == 'position':
test.set_position(obj['position'], obj['duration'],
obj['speed'])
elif obj_type == 'buffering':
test.set_position(obj['position'], 100)
elif obj_type == 'action':
test.add_action_execution(obj)
elif obj_type == 'report':
test.add_report(obj)
class GstValidateTest(Test): class GstValidateTest(Test):
""" A class representing a particular test. """ """ A class representing a particular test. """
@ -474,6 +504,11 @@ class GstValidateTest(Test):
if p: if p:
application_name = p application_name = p
self.reports = []
self.position = -1
self.duration = -1
self.speed = 1.0
self.actions_infos = []
self.media_descriptor = media_descriptor self.media_descriptor = media_descriptor
override_path = self.get_override_file(media_descriptor) override_path = self.get_override_file(media_descriptor)
@ -500,6 +535,57 @@ class GstValidateTest(Test):
self.scenario = None self.scenario = None
else: else:
self.scenario = scenario self.scenario = scenario
self.server = None
def stop_server(self):
if self.server:
self.server.server_close()
self.server.shutdown()
self.server_thread.join()
self.server = None
def kill_subprocess(self):
Test.kill_subprocess(self)
self.stop_server()
def add_report(self, report):
self.reports.append(report)
def set_position(self, position, duration, speed=None):
self.position = position
self.duration = duration
if speed:
self.speed = speed
def add_action_execution(self, action_infos):
if action_infos['action-type'] == 'eos':
self._sent_eos_pos = time.time()
self.actions_infos.append(action_infos)
def server_wrapper(self, ready):
self.server = SocketServer.TCPServer(('localhost', 0), GstValidateListener)
self.server.socket.settimeout(0.0)
self.server.test = self
self.serverport = self.server.socket.getsockname()[1]
self.info("%s server port: %s" % (self, self.serverport))
ready.set()
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
self.server.serve_forever()
def test_start(self, queue):
ready = threading.Event()
self.server_thread = threading.Thread(target=self.server_wrapper,
kwargs={'ready': ready})
self.server_thread.start()
ready.wait()
Test.test_start(self, queue)
def test_end(self):
Test.test_end(self)
self.stop_server()
def get_override_file(self, media_descriptor): def get_override_file(self, media_descriptor):
if media_descriptor: if media_descriptor:
@ -510,10 +596,12 @@ class GstValidateTest(Test):
return None return None
def get_current_position(self):
return self.position
def get_current_value(self): def get_current_value(self):
if self.scenario: if self.scenario:
sent_eos = self.sent_eos_position() if self._sent_eos_pos is not None:
if sent_eos is not None:
t = time.time() t = time.time()
if ((t - sent_eos)) > 30: if ((t - sent_eos)) > 30:
if self.media_descriptor.get_protocol() == Protocols.HLS: if self.media_descriptor.get_protocol() == Protocols.HLS:
@ -528,7 +616,7 @@ class GstValidateTest(Test):
return Result.FAILED return Result.FAILED
return self.get_current_position() return self.position
def get_subproc_env(self): def get_subproc_env(self):
self.validatelogs = self.logfile + '.validate.logs' self.validatelogs = self.logfile + '.validate.logs'
@ -541,6 +629,7 @@ class GstValidateTest(Test):
utils.touch(self.validatelogs) utils.touch(self.validatelogs)
subproc_env["GST_VALIDATE_FILE"] = logfiles subproc_env["GST_VALIDATE_FILE"] = logfiles
subproc_env["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport
self.extra_logfiles.append(self.validatelogs) self.extra_logfiles.append(self.validatelogs)
if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: if 'GST_DEBUG' in os.environ and not self.options.redirect_logs:
@ -598,21 +687,15 @@ class GstValidateTest(Test):
return value return value
def get_validate_criticals_errors(self): def get_validate_criticals_errors(self):
ret = "[" ret = []
errors = [] for report in self.reports:
for l in open(self.validatelogs, 'r').readlines(): if report['level'] == 'critical':
if "critical : " in l: ret.append(report['summary'])
error = l.split("critical : ")[1].replace("\n", '')
if error not in errors:
if ret != "[":
ret += ", "
ret += error
errors.append(error)
if ret == "[": if not ret:
return None return None
else:
return ret + "]" return str(ret)
def check_results(self): def check_results(self):
if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT: if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT:
@ -638,89 +721,6 @@ class GstValidateTest(Test):
else: else:
self.set_result(Result.PASSED) self.set_result(Result.PASSED)
def _parse_position(self, p):
self.log("Parsing %s" % p)
times = self.findpos_regex.findall(p)
if len(times) != 1:
self.warning("Got a unparsable value: %s" % p)
return 0, 0
return (utils.gsttime_from_tuple(times[0][:4]),
utils.gsttime_from_tuple(times[0][4:]))
def _parse_buffering(self, b):
return b.lower().split("buffering... ")[1].split("%")[0], 100
def _get_position(self):
position = duration = -1
self.debug("Getting position")
m = None
for l in reversed(open(self.validatelogs, 'r').readlines()):
l = l.lower()
if "<position:" in l or "buffering" in l:
m = l
break
if m is None:
self.debug("Could not fine any positionning info")
return position, duration
for j in m.split("\r"):
j = j.lstrip().rstrip()
if j.startswith("<position:") and j.endswith("/>"):
position, duration = self._parse_position(j)
elif j.startswith("buffering") and j.endswith("%"):
position, duration = self._parse_buffering(j)
else:
self.log("No info in %s" % j)
return position, duration
def _get_last_seek_values(self):
m = None
rate = start = stop = None
for l in reversed(open(self.validatelogs, 'r').readlines()):
l = l.lower()
if "seeking to: " in l:
m = l
break
if m is None:
self.debug("Could not fine any seeking info")
return start, stop, rate
values = self.findlastseek_regex.findall(m)
if len(values) != 1:
self.warning("Got an unparsable seek value %s", m)
return start, stop, rate
v = values[0]
return (utils.gsttime_from_tuple(v[:4]),
utils.gsttime_from_tuple(v[4:8]),
float(str(v[8]) + "." + str(v[9])))
def sent_eos_position(self):
if self._sent_eos_pos is not None:
return self._sent_eos_pos
for l in reversed(open(self.validatelogs, 'r').readlines()):
l = l.lower()
if "sending eos" in l:
self._sent_eos_pos = time.time()
return self._sent_eos_pos
return None
def get_current_position(self):
position, duration = self._get_position()
if position == -1:
return position
return position
def get_valgrind_suppression_file(self, subdir, name): def get_valgrind_suppression_file(self, subdir, name):
p = get_data_file(subdir, name) p = get_data_file(subdir, name)
if p: if p:

View file

@ -1,5 +1,6 @@
inc_dirs = include_directories('.') inc_dirs = include_directories('.')
json_dep = dependency('json-glib-1.0')
cdata = configuration_data() cdata = configuration_data()
cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion)) cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion))
cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir'))) cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir')))