mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 20:05:38 +00:00
validate: Implement RTSP support
This commit is contained in:
parent
a18cef9c3f
commit
3c62c315a9
7 changed files with 291 additions and 91 deletions
|
@ -1,4 +1,4 @@
|
|||
description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true
|
||||
description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true, needs_preroll=true
|
||||
pause, playback-time=1.0;
|
||||
|
||||
# Wait so that humans can see the pipeline is paused
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true
|
||||
description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true, needs_preroll=true
|
||||
pause;
|
||||
wait, duration=0.5
|
||||
switch-track, type=text, index=(string)+1
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
== Main components
|
||||
|
||||
Gst-validate is composed of 4 parts: the issues, the reports, the runner and
|
||||
|
@ -58,4 +57,3 @@ The file checker is another reporter that is used to make sure a file has a
|
|||
few expected properties. It inspects the file and compares the results with
|
||||
expected values set by the user. Values such as file duration, file size, if
|
||||
it can be played back and also if its encoding and container types.
|
||||
|
||||
|
|
|
@ -137,9 +137,10 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer)
|
|||
caps_str = g_strdup ("");
|
||||
|
||||
res = g_string_new (tmpstr);
|
||||
g_string_append_printf (res, " <streams caps=\"%s\">\n", caps_str);
|
||||
g_free (caps_str);
|
||||
g_free (tmpstr);
|
||||
tmpstr = g_markup_printf_escaped (" <streams caps=\"%s\">\n", caps_str);
|
||||
g_string_append (res, tmpstr);
|
||||
g_free (caps_str);
|
||||
for (tmp = filenode->streams; tmp; tmp = tmp->next) {
|
||||
GList *tmp3;
|
||||
GstValidateMediaStreamNode
|
||||
|
@ -658,6 +659,7 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner,
|
|||
media_descriptor = (GstValidateMediaDescriptor *) writer;
|
||||
if (streams == NULL && media_descriptor->filenode->caps)
|
||||
writer->priv->raw_caps = gst_caps_copy (media_descriptor->filenode->caps);
|
||||
|
||||
gst_discoverer_stream_info_list_free (streams);
|
||||
|
||||
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
# Boston, MA 02110-1301, USA.
|
||||
import argparse
|
||||
import os
|
||||
import copy
|
||||
import sys
|
||||
import time
|
||||
import urllib.parse
|
||||
import shlex
|
||||
import socket
|
||||
import subprocess
|
||||
import configparser
|
||||
from launcher.loggable import Loggable
|
||||
|
@ -31,7 +34,8 @@ from launcher.baseclasses import GstValidateTest, Test, \
|
|||
GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination
|
||||
|
||||
from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \
|
||||
GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file
|
||||
GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \
|
||||
kill_subprocess
|
||||
|
||||
#
|
||||
# Private global variables #
|
||||
|
@ -40,14 +44,17 @@ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \
|
|||
# definitions of commands to use
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument("--validate-tools-path", dest="validate_tools_path",
|
||||
default="",
|
||||
help="defines the paths to look for GstValidate tools.")
|
||||
default="",
|
||||
help="defines the paths to look for GstValidate tools.")
|
||||
options, args = parser.parse_known_args()
|
||||
|
||||
GST_VALIDATE_COMMAND = which("gst-validate-1.0", options.validate_tools_path)
|
||||
GST_VALIDATE_TRANSCODING_COMMAND = which("gst-validate-transcoding-1.0", options.validate_tools_path)
|
||||
G_V_DISCOVERER_COMMAND = which("gst-validate-media-check-1.0", options.validate_tools_path)
|
||||
GST_VALIDATE_TRANSCODING_COMMAND = which(
|
||||
"gst-validate-transcoding-1.0", options.validate_tools_path)
|
||||
G_V_DISCOVERER_COMMAND = which(
|
||||
"gst-validate-media-check-1.0", options.validate_tools_path)
|
||||
ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND
|
||||
RTSP_SERVER_COMMAND = "gst-rtsp-server-example-uri-1.0"
|
||||
|
||||
AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5
|
||||
|
||||
|
@ -62,6 +69,7 @@ GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS),
|
|||
("application/dash+xml", Protocols.DASH)]
|
||||
GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120,
|
||||
Protocols.HLS: 240,
|
||||
Protocols.RTSP: 240,
|
||||
Protocols.DASH: 240}
|
||||
|
||||
|
||||
|
@ -99,6 +107,10 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator):
|
|||
if mediainfo.media_descriptor.is_image():
|
||||
continue
|
||||
|
||||
protocol = mediainfo.media_descriptor.get_protocol()
|
||||
if protocol == Protocols.RTSP:
|
||||
continue
|
||||
|
||||
for comb in self.test_manager.get_encoding_formats():
|
||||
classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(),
|
||||
str(comb).replace(
|
||||
|
@ -113,6 +125,7 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator):
|
|||
|
||||
|
||||
class FakeMediaDescriptor(MediaDescriptor):
|
||||
|
||||
def __init__(self, infos, pipeline_desc):
|
||||
MediaDescriptor.__init__(self)
|
||||
self._infos = infos
|
||||
|
@ -210,7 +223,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator):
|
|||
|
||||
for scenario in extra_datas.get('scenarios', scenarios):
|
||||
if isinstance(scenario, str):
|
||||
scenario = self.test_manager.scenarios_manager.get_scenario(scenario)
|
||||
scenario = self.test_manager.scenarios_manager.get_scenario(
|
||||
scenario)
|
||||
|
||||
mediainfo = FakeMediaDescriptor(extra_datas, pipeline)
|
||||
if not mediainfo.is_compatible(scenario):
|
||||
|
@ -229,7 +243,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator):
|
|||
pipeline_desc = pipeline % {'videosink': videosink,
|
||||
'audiosink': audiosink}
|
||||
|
||||
fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name)
|
||||
fname = self.get_fname(
|
||||
scenario, protocol=mediainfo.get_protocol(), name=name)
|
||||
|
||||
expected_failures = extra_datas.get("expected-failures")
|
||||
extra_env_vars = extra_datas.get("extra_env_vars")
|
||||
|
@ -254,11 +269,43 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator):
|
|||
GstValidatePipelineTestsGenerator.__init__(
|
||||
self, "playback", test_manager, "playbin3")
|
||||
|
||||
def _set_sinks(self, minfo, pipe_str, scenario):
|
||||
if self.test_manager.options.mute:
|
||||
if scenario.needs_clock_sync() or \
|
||||
minfo.media_descriptor.need_clock_sync():
|
||||
afakesink = "'fakesink sync=true'"
|
||||
vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'"
|
||||
else:
|
||||
vfakesink = afakesink = "'fakesink'"
|
||||
|
||||
pipe_str += " audio-sink=%s video-sink=%s" % (
|
||||
afakesink, vfakesink)
|
||||
|
||||
return pipe_str
|
||||
|
||||
def _get_name(self, scenario, protocol, minfo):
|
||||
return "%s.%s" % (self.get_fname(scenario,
|
||||
protocol),
|
||||
os.path.basename(minfo.media_descriptor.get_clean_name()))
|
||||
|
||||
def populate_tests(self, uri_minfo_special_scenarios, scenarios):
|
||||
test_rtsp = which(RTSP_SERVER_COMMAND)
|
||||
if not test_rtsp:
|
||||
printc("\n\nRTSP server not available, you should make sure"
|
||||
" that %s is available in your $PATH." % RTSP_SERVER_COMMAND,
|
||||
Colors.FAIL)
|
||||
elif self.test_manager.options.disable_rtsp:
|
||||
printc("\n\nRTSP tests are disabled")
|
||||
test_rtsp = False
|
||||
|
||||
for uri, minfo, special_scenarios in uri_minfo_special_scenarios:
|
||||
pipe = self._pipeline_template
|
||||
protocol = minfo.media_descriptor.get_protocol()
|
||||
|
||||
if protocol == Protocols.RTSP:
|
||||
self.debug("SKIPPING %s as it is a RTSP stream" % uri)
|
||||
continue
|
||||
|
||||
pipe += " uri=%s" % uri
|
||||
|
||||
for scenario in special_scenarios + scenarios:
|
||||
|
@ -266,20 +313,9 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator):
|
|||
if not minfo.media_descriptor.is_compatible(scenario):
|
||||
continue
|
||||
|
||||
if self.test_manager.options.mute:
|
||||
if scenario.needs_clock_sync() or \
|
||||
minfo.media_descriptor.need_clock_sync():
|
||||
afakesink = "'fakesink sync=true'"
|
||||
vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'"
|
||||
else:
|
||||
vfakesink = afakesink = "'fakesink'"
|
||||
cpipe = self._set_sinks(minfo, cpipe, scenario)
|
||||
fname = self._get_name(scenario, protocol, minfo)
|
||||
|
||||
cpipe += " audio-sink=%s video-sink=%s" % (
|
||||
afakesink, vfakesink)
|
||||
|
||||
fname = "%s.%s" % (self.get_fname(scenario,
|
||||
protocol),
|
||||
os.path.basename(minfo.media_descriptor.get_clean_name()))
|
||||
self.debug("Adding: %s", fname)
|
||||
|
||||
if scenario.does_reverse_playback() and protocol == Protocols.HTTP:
|
||||
|
@ -294,6 +330,21 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator):
|
|||
media_descriptor=minfo.media_descriptor)
|
||||
)
|
||||
|
||||
if test_rtsp and protocol == Protocols.FILE and not minfo.media_descriptor.is_image():
|
||||
rtspminfo = copy.deepcopy(minfo)
|
||||
rtspminfo.media_descriptor = GstValidateRTSPMediaDesciptor(minfo.media_descriptor.get_path())
|
||||
if not rtspminfo.media_descriptor.is_compatible(scenario):
|
||||
continue
|
||||
|
||||
cpipe = self._set_sinks(rtspminfo, "%s uri=rtsp://127.0.0.1:<RTSPPORTNUMBER>/test"
|
||||
% self._pipeline_template, scenario)
|
||||
fname = self._get_name(scenario, Protocols.RTSP, rtspminfo)
|
||||
|
||||
self.add_test(GstValidateRTSPTest(
|
||||
fname, self.test_manager.options, self.test_manager.reporter,
|
||||
cpipe, uri, scenario=scenario,
|
||||
media_descriptor=rtspminfo.media_descriptor))
|
||||
|
||||
|
||||
class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator):
|
||||
|
||||
|
@ -443,7 +494,8 @@ class GstValidateMediaCheckTest(GstValidateTest):
|
|||
|
||||
def build_arguments(self):
|
||||
Test.build_arguments(self)
|
||||
self.add_arguments(self._uri, "--expected-results", self._media_info_path)
|
||||
self.add_arguments(self._uri, "--expected-results",
|
||||
self._media_info_path)
|
||||
|
||||
|
||||
class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface):
|
||||
|
@ -541,6 +593,112 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa
|
|||
self.set_result(res, msg)
|
||||
|
||||
|
||||
class GstValidateBaseRTSPTest:
|
||||
""" Interface for RTSP tests, requires implementing Test"""
|
||||
__used_ports = set()
|
||||
|
||||
def __init__(self, local_uri):
|
||||
self._local_uri = local_uri
|
||||
self.rtsp_server = None
|
||||
self._unsetport_pipeline_desc = None
|
||||
self.optional = True
|
||||
|
||||
@classmethod
|
||||
def __get_open_port(cls):
|
||||
while True:
|
||||
# hackish trick from
|
||||
# http://stackoverflow.com/questions/2838244/get-open-tcp-port-in-python?answertab=votes#tab-top
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(("", 0))
|
||||
port = s.getsockname()[1]
|
||||
if port not in cls.__used_ports:
|
||||
cls.__used_ports.add(port)
|
||||
s.close()
|
||||
return port
|
||||
|
||||
s.close()
|
||||
|
||||
def launch_server(self):
|
||||
if self.options.redirect_logs == 'stdout':
|
||||
self.rtspserver_logs = sys.stdout
|
||||
elif self.options.redirect_logs == 'stderr':
|
||||
self.rtspserver_logs = sys.stderr
|
||||
|
||||
self.server_port = self.__get_open_port()
|
||||
command = [RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)]
|
||||
|
||||
if self.options.validate_gdb_server:
|
||||
command = self.use_gdb(command)
|
||||
self.rtspserver_logs = sys.stdout
|
||||
elif self.options.redirect_logs:
|
||||
self.rtspserver_logs = sys.stdout
|
||||
else:
|
||||
self.rtspserver_logs = open(self.logfile + '_rtspserver.log', 'w+')
|
||||
self.extra_logfiles.append(self.rtspserver_logs.name)
|
||||
|
||||
server_env = os.environ.copy()
|
||||
server_env['GST_TRACERS'] = 'validate'
|
||||
|
||||
self.rtsp_server = subprocess.Popen(command,
|
||||
stderr=self.rtspserver_logs,
|
||||
stdout=self.rtspserver_logs,
|
||||
env=server_env)
|
||||
while True:
|
||||
s = socket.socket()
|
||||
try:
|
||||
s.connect((("127.0.0.1", self.server_port)))
|
||||
break
|
||||
except ConnectionRefusedError:
|
||||
time.sleep(0.5)
|
||||
continue
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
if not self._unsetport_pipeline_desc:
|
||||
self._unsetport_pipeline_desc = self.pipeline_desc
|
||||
|
||||
self.pipeline_desc = self._unsetport_pipeline_desc.replace(
|
||||
"<RTSPPORTNUMBER>", str(self.server_port))
|
||||
|
||||
return 'GST_TRACERS=validate ' + ' '.join(command)
|
||||
|
||||
def close_logfile(self):
|
||||
super().close_logfile()
|
||||
if not self.options.redirect_logs:
|
||||
self.rtspserver_logs.close()
|
||||
|
||||
def process_update(self):
|
||||
res = super().process_update()
|
||||
if res:
|
||||
kill_subprocess(self, self.rtsp_server, DEFAULT_TIMEOUT)
|
||||
self.__used_ports.remove(self.server_port)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class GstValidateRTSPTest(GstValidateBaseRTSPTest, GstValidateLaunchTest):
|
||||
|
||||
def __init__(self, classname, options, reporter, pipeline_desc,
|
||||
local_uri, timeout=DEFAULT_TIMEOUT, scenario=None,
|
||||
media_descriptor=None):
|
||||
GstValidateLaunchTest.__init__(self, classname, options, reporter,
|
||||
pipeline_desc, timeout, scenario,
|
||||
media_descriptor)
|
||||
GstValidateBaseRTSPTest.__init__(self, local_uri)
|
||||
|
||||
|
||||
class GstValidateRTSPMediaDesciptor(GstValidateMediaDescriptor):
|
||||
|
||||
def __init__(self, xml_path):
|
||||
GstValidateMediaDescriptor.__init__(self, xml_path)
|
||||
|
||||
def get_uri(self):
|
||||
return "rtsp://127.0.0.1:8554/test"
|
||||
|
||||
def get_protocol(self):
|
||||
return Protocols.RTSP
|
||||
|
||||
|
||||
class GstValidateTestManager(GstValidateBaseTestManager):
|
||||
|
||||
name = "validate"
|
||||
|
@ -582,6 +740,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
action="append", help="defines the uris to run default tests on")
|
||||
group.add_argument("--validate-tools-path", dest="validate_tools_path",
|
||||
action="append", help="defines the paths to look for GstValidate tools.")
|
||||
group.add_argument("--validate-gdb-server", dest="validate_gdb_server",
|
||||
help="Run the server in GDB.")
|
||||
group.add_argument("--validate-disable-rtsp", dest="disable_rtsp",
|
||||
help="Disable RTSP tests.")
|
||||
|
||||
def print_valgrind_bugs(self):
|
||||
# Look for all the 'pending' bugs in our supp file
|
||||
|
@ -629,7 +791,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
self.add_test(test)
|
||||
|
||||
if not self.tests and not uris:
|
||||
printc("No valid uris present in the path. Check if media files and info files exist", Colors.FAIL)
|
||||
printc(
|
||||
"No valid uris present in the path. Check if media files and info files exist", Colors.FAIL)
|
||||
|
||||
return self.tests
|
||||
|
||||
|
@ -681,10 +844,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
self._add_media(fpath)
|
||||
return True
|
||||
elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris:
|
||||
self.info("%s not present. Use --generate-media-info", media_info)
|
||||
self.info(
|
||||
"%s not present. Use --generate-media-info", media_info)
|
||||
return True
|
||||
elif self.options.update_media_info and not os.path.isfile(media_info):
|
||||
self.info("%s not present. Use --generate-media-info", media_info)
|
||||
self.info(
|
||||
"%s not present. Use --generate-media-info", media_info)
|
||||
return True
|
||||
|
||||
include_frames = 0
|
||||
|
@ -750,7 +915,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
|
||||
if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \
|
||||
("127.0.0.1:%s" % (self.options.http_server_port) in uri or
|
||||
"127.0.0.1:8079" in uri):
|
||||
"127.0.0.1:8079" in uri):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -862,9 +1027,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
"https://bugzilla.gnome.org/show_bug.cgi?id=702595"),
|
||||
|
||||
# Fragmented MP4 disabled tests:
|
||||
('validate.file.playback..*seek.*.fragmented_nonseekable_sink_mp4',
|
||||
('validate.*.playback..*seek.*.fragmented_nonseekable_sink_mp4',
|
||||
"Seeking on fragmented files without indexes isn't implemented"),
|
||||
('validate.file.playback.reverse_playback.fragmented_nonseekable_sink_mp4',
|
||||
('validate.*.playback.reverse_playback.fragmented_nonseekable_sink_mp4',
|
||||
"Seeking on fragmented files without indexes isn't implemented"),
|
||||
|
||||
# HTTP known issues:
|
||||
|
@ -889,7 +1054,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
|
|||
|
||||
# ogg known issues
|
||||
("validate.http.playback.seek.*vorbis_theora_1_ogg",
|
||||
"https://bugzilla.gnome.org/show_bug.cgi?id=769545")
|
||||
"https://bugzilla.gnome.org/show_bug.cgi?id=769545"),
|
||||
# RTSP known issues
|
||||
('validate.rtsp.playback.reverse.*',
|
||||
'https://bugzilla.gnome.org/show_bug.cgi?id=626811'),
|
||||
('validate.rtsp.playback.fast_*',
|
||||
'https://bugzilla.gnome.org/show_bug.cgi?id=754575'),
|
||||
])
|
||||
|
||||
def register_default_test_generators(self):
|
||||
|
|
|
@ -82,6 +82,7 @@ class Test(Loggable):
|
|||
self.options = options
|
||||
self.application = application_name
|
||||
self.command = []
|
||||
self.server_command = None
|
||||
self.reporter = reporter
|
||||
self.process = None
|
||||
self.proc_env = None
|
||||
|
@ -98,6 +99,7 @@ class Test(Loggable):
|
|||
|
||||
extra_env_variables = extra_env_variables or {}
|
||||
self.extra_env_variables = extra_env_variables
|
||||
self.optional = False
|
||||
|
||||
self.clean()
|
||||
|
||||
|
@ -333,26 +335,7 @@ class Test(Loggable):
|
|||
return os.environ.copy()
|
||||
|
||||
def kill_subprocess(self):
|
||||
if self.process is None:
|
||||
return
|
||||
|
||||
stime = time.time()
|
||||
res = self.process.poll()
|
||||
while res is None:
|
||||
try:
|
||||
self.debug("Subprocess is still alive, sending KILL signal")
|
||||
if utils.is_windows():
|
||||
subprocess.call(['taskkill', '/F', '/T', '/PID', str(self.process.pid)])
|
||||
else:
|
||||
self.process.send_signal(signal.SIGKILL)
|
||||
time.sleep(1)
|
||||
except OSError:
|
||||
pass
|
||||
if time.time() - stime > DEFAULT_TIMEOUT:
|
||||
raise RuntimeError("Could not kill subprocess after %s second"
|
||||
" Something is really wrong, => EXITING"
|
||||
% DEFAULT_TIMEOUT)
|
||||
res = self.process.poll()
|
||||
utils.kill_subprocess(self, self.process, DEFAULT_TIMEOUT)
|
||||
|
||||
def thread_wrapper(self):
|
||||
self.process = subprocess.Popen(self.command,
|
||||
|
@ -373,14 +356,15 @@ class Test(Loggable):
|
|||
def get_valgrind_suppressions(self):
|
||||
return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')]
|
||||
|
||||
def use_gdb(self):
|
||||
def use_gdb(self, command):
|
||||
if self.hard_timeout is not None:
|
||||
self.hard_timeout *= GDB_TIMEOUT_FACTOR
|
||||
self.timeout *= GDB_TIMEOUT_FACTOR
|
||||
self.command = ["gdb", "-ex", "run", "-ex", "quit",
|
||||
"--args"] + self.command
|
||||
return ["gdb", "-ex", "run", "-ex", "backtrace", "-ex", "quit", "--args"] + command
|
||||
|
||||
def use_valgrind(self):
|
||||
def use_valgrind(self, command, subenv):
|
||||
vglogsfile = self.logfile + '.valgrind'
|
||||
self.extra_logfiles.append(vglogsfile)
|
||||
|
||||
vg_args = []
|
||||
|
||||
|
@ -404,14 +388,11 @@ class Test(Loggable):
|
|||
for supp in self.get_valgrind_suppressions():
|
||||
vg_args.append("--suppressions=%s" % supp)
|
||||
|
||||
self.command = ["valgrind"] + vg_args + self.command
|
||||
command = ["valgrind"] + vg_args + command
|
||||
|
||||
# Tune GLib's memory allocator to be more valgrind friendly
|
||||
self.proc_env['G_DEBUG'] = 'gc-friendly'
|
||||
self.add_env_variable('G_DEBUG', 'gc-friendly')
|
||||
|
||||
self.proc_env['G_SLICE'] = 'always-malloc'
|
||||
self.add_env_variable('G_SLICE', 'always-malloc')
|
||||
subenv['G_DEBUG'] = 'gc-friendly'
|
||||
subenv['G_SLICE'] = 'always-malloc'
|
||||
|
||||
if self.hard_timeout is not None:
|
||||
self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR
|
||||
|
@ -421,15 +402,24 @@ class Test(Loggable):
|
|||
vg_config = get_data_file('data', 'valgrind.config')
|
||||
|
||||
if self.proc_env.get('GST_VALIDATE_CONFIG'):
|
||||
self.proc_env['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config)
|
||||
subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config)
|
||||
else:
|
||||
self.proc_env['GST_VALIDATE_CONFIG'] = vg_config
|
||||
subenv['GST_VALIDATE_CONFIG'] = vg_config
|
||||
|
||||
self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG'])
|
||||
if subenv == self.proc_env:
|
||||
self.add_env_variable('G_DEBUG', 'gc-friendly')
|
||||
self.add_env_variable('G_SLICE', 'always-malloc')
|
||||
self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG'])
|
||||
|
||||
return command
|
||||
|
||||
def launch_server(self):
|
||||
return None
|
||||
|
||||
def test_start(self, queue):
|
||||
self.open_logfile()
|
||||
|
||||
server_command = self.launch_server()
|
||||
self.queue = queue
|
||||
self.command = [self.application]
|
||||
self._starting_time = time.time()
|
||||
|
@ -442,14 +432,17 @@ class Test(Loggable):
|
|||
self.add_env_variable(var, self.proc_env[var])
|
||||
|
||||
if self.options.gdb:
|
||||
self.use_gdb()
|
||||
|
||||
self.command = self.use_gdb(self.command)
|
||||
if self.options.valgrind:
|
||||
self.use_valgrind()
|
||||
self.command = self.use_valgrind(self.command, self.proc_env)
|
||||
|
||||
message = "Launching: %s%s\n" \
|
||||
" Command: '%s %s'\n" % (Colors.ENDC, self.classname,
|
||||
self._env_variable, ' '.join(self.command))
|
||||
" Command: '%s & %s %s'\n" % (
|
||||
Colors.ENDC, self.classname, server_command,
|
||||
self._env_variable, ' '.join(self.command))
|
||||
if server_command:
|
||||
message += " Server command: %s\n" % server_command
|
||||
|
||||
if not self.options.redirect_logs:
|
||||
message += " Logs:\n" \
|
||||
" - %s" % (self.logfile)
|
||||
|
@ -1541,16 +1534,18 @@ class _TestsLauncher(Loggable):
|
|||
testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist",
|
||||
'w')
|
||||
except IOError:
|
||||
return
|
||||
continue
|
||||
|
||||
for test in know_tests:
|
||||
if test and test not in tests_names:
|
||||
testlist_changed = True
|
||||
printc("Test %s Not in testsuite %s anymore"
|
||||
% (test, testsuite.__file__), Colors.FAIL)
|
||||
if test and test.strip('~') not in tests_names:
|
||||
if not test.startswith('~'):
|
||||
testlist_changed = True
|
||||
printc("Test %s Not in testsuite %s anymore"
|
||||
% (test, testsuite.__file__), Colors.FAIL)
|
||||
|
||||
for test in tests_names:
|
||||
testlist_file.write("%s\n" % test)
|
||||
for test in tests:
|
||||
testlist_file.write("%s%s\n" % ('~' if test.optional else '',
|
||||
test.classname))
|
||||
if test and test not in know_tests:
|
||||
printc("Test %s is NEW in testsuite %s"
|
||||
% (test, testsuite.__file__), Colors.OKGREEN)
|
||||
|
@ -1719,6 +1714,7 @@ class Scenario(object):
|
|||
def __repr__(self):
|
||||
return "<Scenario %s>" % self.name
|
||||
|
||||
|
||||
class ScenarioManager(Loggable):
|
||||
_instance = None
|
||||
all_scenarios = []
|
||||
|
@ -1844,7 +1840,7 @@ class GstValidateBaseTestManager(TestsManager):
|
|||
"""
|
||||
self._scenarios = []
|
||||
self.add_scenarios(scenarios)
|
||||
|
||||
|
||||
def get_scenarios(self):
|
||||
return self._scenarios
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import os
|
|||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
@ -43,7 +44,8 @@ from xml.etree import ElementTree
|
|||
GST_SECOND = int(1000000000)
|
||||
DEFAULT_TIMEOUT = 30
|
||||
DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate")
|
||||
DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites")
|
||||
DEFAULT_GST_QA_ASSETS = os.path.join(
|
||||
DEFAULT_MAIN_DIR, "gst-integration-testsuites")
|
||||
DISCOVERER_COMMAND = "gst-discoverer-1.0"
|
||||
# Use to set the duration from which a test is considered as being 'long'
|
||||
LONG_TEST = 40
|
||||
|
@ -63,6 +65,7 @@ class Protocols(object):
|
|||
FILE = "file"
|
||||
HLS = "hls"
|
||||
DASH = "dash"
|
||||
RTSP = "rtsp"
|
||||
|
||||
@staticmethod
|
||||
def needs_clock_sync(protocol):
|
||||
|
@ -208,7 +211,8 @@ def TIME_ARGS(time):
|
|||
|
||||
|
||||
def look_for_file_in_source_dir(subdir, name):
|
||||
root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__)))))
|
||||
root_dir = os.path.abspath(os.path.dirname(
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)))))
|
||||
p = os.path.join(root_dir, subdir, name)
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
|
@ -253,7 +257,8 @@ def get_duration(media_file):
|
|||
duration = 0
|
||||
res = ''
|
||||
try:
|
||||
res = subprocess.check_output([DISCOVERER_COMMAND, media_file]).decode()
|
||||
res = subprocess.check_output(
|
||||
[DISCOVERER_COMMAND, media_file]).decode()
|
||||
except subprocess.CalledProcessError:
|
||||
# gst-media-check returns !0 if seeking is not possible, we do not care
|
||||
# in that case.
|
||||
|
@ -308,7 +313,7 @@ class BackTraceGenerator(Loggable):
|
|||
"installed."
|
||||
|
||||
gdb = ['gdb', '-ex', 't a a bt', '-batch',
|
||||
'-p', str(test.process.pid)]
|
||||
'-p', str(test.process.pid)]
|
||||
|
||||
try:
|
||||
return subprocess.check_output(
|
||||
|
@ -320,7 +325,8 @@ class BackTraceGenerator(Loggable):
|
|||
def get_trace_from_systemd(self, test):
|
||||
for ntry in range(10):
|
||||
if ntry != 0:
|
||||
# Loopping, it means we conceder the logs might not be ready yet.
|
||||
# Loopping, it means we conceder the logs might not be ready
|
||||
# yet.
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
|
@ -334,7 +340,8 @@ class BackTraceGenerator(Loggable):
|
|||
|
||||
info = info.decode()
|
||||
try:
|
||||
executable = BackTraceGenerator._executable_regex.findall(info)[0]
|
||||
executable = BackTraceGenerator._executable_regex.findall(info)[
|
||||
0]
|
||||
except IndexError:
|
||||
self.debug("Backtrace could not be found yet, trying harder.")
|
||||
# The trace might not be ready yet
|
||||
|
@ -357,11 +364,11 @@ class BackTraceGenerator(Loggable):
|
|||
try:
|
||||
tf = tempfile.NamedTemporaryFile()
|
||||
subprocess.check_output(['coredumpctl', 'dump',
|
||||
str(test.process.pid), '--output=' +
|
||||
tf.name], stderr=subprocess.STDOUT)
|
||||
str(test.process.pid), '--output=' +
|
||||
tf.name], stderr=subprocess.STDOUT)
|
||||
|
||||
gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit',
|
||||
test.application, tf.name]
|
||||
test.application, tf.name]
|
||||
bt_all = subprocess.check_output(
|
||||
gdb, stderr=subprocess.STDOUT).decode()
|
||||
|
||||
|
@ -387,13 +394,14 @@ def check_bugs_resolution(bugs_definitions):
|
|||
|
||||
if "bugzilla" not in url.netloc:
|
||||
printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug),
|
||||
Colors.WARNING)
|
||||
Colors.WARNING)
|
||||
continue
|
||||
|
||||
query = urllib.parse.parse_qs(url.query)
|
||||
_id = query.get('id')
|
||||
if not _id:
|
||||
printc(" + '%s' -- Can't check bug '%s'\n" % (regex, bug), Colors.WARNING)
|
||||
printc(" + '%s' -- Can't check bug '%s'\n" %
|
||||
(regex, bug), Colors.WARNING)
|
||||
continue
|
||||
|
||||
if isinstance(_id, list):
|
||||
|
@ -447,3 +455,29 @@ def check_bugs_resolution(bugs_definitions):
|
|||
regex, bugid, desc, status), Colors.OKGREEN)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def kill_subprocess(owner, process, timeout):
|
||||
if process is None:
|
||||
return
|
||||
|
||||
stime = time.time()
|
||||
res = process.poll()
|
||||
while res is None:
|
||||
try:
|
||||
owner.debug("Subprocess is still alive, sending KILL signal")
|
||||
if is_windows():
|
||||
subprocess.call(
|
||||
['taskkill', '/F', '/T', '/PID', str(process.pid)])
|
||||
else:
|
||||
process.send_signal(signal.SIGKILL)
|
||||
time.sleep(1)
|
||||
except OSError:
|
||||
pass
|
||||
if time.time() - stime > DEFAULT_TIMEOUT:
|
||||
raise RuntimeError("Could not kill subprocess after %s second"
|
||||
" Something is really wrong, => EXITING"
|
||||
% DEFAULT_TIMEOUT)
|
||||
res = process.poll()
|
||||
|
||||
return res
|
||||
|
|
Loading…
Reference in a new issue