From 20c28def3c48bfdf8ab6aa470f1102292fd979b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Aug 2014 12:04:31 +0200 Subject: [PATCH] validate:launcher: Handle stdout/stderr as possible logfiles Allowing people to get all the logs in the terminal --- validate/tools/launcher/baseclasses.py | 81 +++++++++++++++++--------- validate/tools/launcher/httpserver.py | 7 ++- validate/tools/launcher/main.py | 4 +- validate/tools/launcher/reporters.py | 27 ++++++--- 4 files changed, 84 insertions(+), 35 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index ab7d258635..1c0e3a04c5 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -30,6 +30,7 @@ import subprocess import reporters import ConfigParser import loggable +import tempfile from loggable import Loggable from optparse import OptionGroup import xml.etree.ElementTree as ET @@ -61,9 +62,12 @@ class Test(Loggable): self.process = None self.duration = duration - self.clean() + self.clean(True) + + def clean(self, full=True): + if not full: + return - def clean(self): self.message = "" self.error_str = "" self.time_taken = 0.0 @@ -78,10 +82,11 @@ class Test(Loggable): string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'\n" \ - " You can reproduce with: %s\n" \ - " You can find logs in:\n" \ - " - %s" % (self.message, self.command, - self.logfile) + " You can reproduce with: %s\n" % (self.message, self.command) + + if not self.reporter.uses_standard_output(): + string += " You can find logs in:\n" \ + " - %s" % (self.logfile) for log in self.extra_logfiles: string += "\n - %s" % log @@ -205,12 +210,13 @@ class Test(Loggable): proc_env = self.get_subproc_env() message = "Launching: %s%s\n" \ - " Command: '%s'\n" \ - " Logs:\n" \ - " - %s" % (Colors.ENDC, self.classname, - self.command, self.logfile) - for log in self.extra_logfiles: - message += "\n - %s" % log + " Command: '%s'\n" %(Colors.ENDC, self.classname, + self.command) + if not self.reporter.uses_standard_output(): + message += " Logs:\n" \ + " - %s" % (self.logfile) + for log in self.extra_logfiles: + message += "\n - %s" % log printc(message, Colors.OKBLUE) @@ -232,12 +238,14 @@ class Test(Loggable): self.time_taken = time.time() - self._starting_time - self.reporter.out.seek(0) - self.reporter.out.write("=================\n" - "Test name: %s\n" - "Command: '%s'\n" - "=================\n\n" - % (self.classname, self.command)) + if not self.reporter.uses_standard_output(): + self.reporter.out.seek(0) + self.reporter.out.write("=================\n" + "Test name: %s\n" + "Command: '%s'\n" + "=================\n\n" + % (self.classname, self.command)) + printc("Result: %s%s\n" % (self.result, " (" + self.message + ")" if self.message else ""), color=utils.get_color_for_result(self.result)) @@ -270,23 +278,38 @@ class GstValidateTest(Test): self.scenario = scenario def get_subproc_env(self): + if self.reporter.uses_standard_output(): + self.validatelogs = os.path.join (tempfile.gettempdir(), 'tmp.validate.logs') + logfiles = self.validatelogs + logfiles += os.pathsep + self.reporter.out.name.replace("<", '').replace(">", '') + else: + self.validatelogs = self.logfile + '.validate.logs' + logfiles = self.validatelogs + subproc_env = os.environ.copy() - self.validatelogs = self.logfile + '.validate.logs' utils.touch(self.validatelogs) - subproc_env["GST_VALIDATE_FILE"] = self.validatelogs + subproc_env["GST_VALIDATE_FILE"] = logfiles self.extra_logfiles.append(self.validatelogs) - if 'GST_DEBUG' in os.environ: + if 'GST_DEBUG' in os.environ and \ + not self.reporter.uses_standard_output(): gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile return subproc_env - def clean(self): - Test.clean(self) - self._sent_eos_pos = None + def clean(self, full=True): + Test.clean(self, full=full) + if self.reporter.uses_standard_output(): + try: + os.remove(self.validatelogs) + except OSError: + pass + + if full: + self._sent_eos_pos = None def build_arguments(self): if self.scenario is not None: @@ -681,6 +704,7 @@ class TestsManager(Loggable): self.reporter.after_test() if res != Result.PASSED and (self.options.forever or self.options.fatal_error): + test.clean(full=False) return test.result return Result.PASSED @@ -754,7 +778,8 @@ class _TestsLauncher(Loggable): def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) - mkdir(options.logsdir) + if not options.logsdir in[sys.stderr, sys.stdout]: + mkdir(options.logsdir) self.options = options wanted_testers = None @@ -920,7 +945,11 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") - logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + if self.config.logsdir in ["stdout", "stderr"]: + logs = open(os.devnull) + else: + logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + try: command = [self.GST_VALIDATE_COMMAND, "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py index 86c80a73f9..5c51c39d97 100644 --- a/validate/tools/launcher/httpserver.py +++ b/validate/tools/launcher/httpserver.py @@ -22,6 +22,7 @@ import time import loggable import subprocess import sys +import tempfile logcat = "httpserver" @@ -54,7 +55,11 @@ class HTTPServer(loggable.Loggable): def start(self): """ Start the server in a subprocess """ - self._logsfile = open(os.path.join(self.options.logsdir, + if self.options.logsdir in ["stdout", "stderr"]: + self.info("Using devnull as HTTP server log file") + self._logsfile = tempfile.TemporaryFile() + else: + self._logsfile = open(os.path.join(self.options.logsdir, "httpserver.logs"), 'w+') if self.options.http_server_dir is not None: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 59b8fba506..ff7b2158e8 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -257,7 +257,9 @@ user argument, you can thus overrides command line options using that. help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", default=None, - help="Directory where to store logs, default is OUTPUT_DIR/logs") + help="Directory where to store logs, default is OUTPUT_DIR/logs." + " Note that 'stdout' and 'sdterr' are valid values that lets you get all the logs" + " printed in the terminal") dir_group.add_argument("-R", "--render-path", dest="dest", default=None, help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index a67940f2f3..9722c8fc47 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -21,6 +21,7 @@ import os import re +import sys import time import codecs import datetime @@ -65,14 +66,24 @@ class Reporter(Loggable): } self.results = [] + def uses_standard_output(self): + return self.out in [sys.stdout, sys.stderr] + def before_test(self, test): """Initialize a timer before starting a test.""" - path = os.path.join(self.options.logsdir, - test.classname.replace(".", os.sep)) - mkdir(os.path.dirname(path)) - self.out = open(path, 'w+') + if self.options.logsdir == 'stdout': + self.out = sys.stdout + test.logfile = 'stdout' + elif self.options.logsdir == 'stderr': + self.out = sys.stderr + test.logfile = 'stderr' + else: + path = os.path.join(self.options.logsdir, + test.classname.replace(".", os.sep)) + mkdir(os.path.dirname(path)) + self.out = open(path, 'w+') + test.logfile = path self._current_test = test - test.logfile = path if self._start_time == 0: self._start_time = time.time() @@ -98,7 +109,9 @@ class Reporter(Loggable): self.results.append(self._current_test) self.add_results(self._current_test) - self.out.close() + if not self.uses_standard_output(): + self.out.close() + self.out = None self._current_test = None @@ -146,7 +159,7 @@ class XunitReporter(Reporter): def _get_captured(self): captured = "" - if self.out: + if self.out and not self.uses_standard_output(): self.out.seek(0) value = self.out.read() if value: