# -*- coding: utf-8 -*-
# $Id$
# pylint: disable=C0302
"""
Testdriver reporter module.
"""
__copyright__ = \
"""
Copyright (C) 2010-2014 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
General Public License (GPL) as published by the Free Software
Foundation, in version 2 as it comes in the "COPYING" file of the
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
The contents of this file may alternatively be used under the terms
of the Common Development and Distribution License Version 1.0
(CDDL) only, as it comes in the "COPYING.CDDL" file of the
VirtualBox OSE distribution, in which case the provisions of the
CDDL are applicable instead of those of the GPL.
You may elect to license modified versions of this file under the
terms and conditions of either the GPL or the CDDL or both.
"""
# Standard Python imports.
import array
import datetime
import errno
import os
import sys
import time
import threading
import traceback
# Validation Kit imports.
## test reporter instance
g_oReporter = None;
g_sReporterName = None;
"""
Python logging => testdriver/reporter.py stream.
"""
"""Writes python log message to our stream."""
if g_oReporter != None:
#g_oReporter.log(0, 'python: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
return True;
"""Flushes the stream."""
return True;
"""
Base class for the reporters.
"""
# Hook into the python logging.
import logging;
format = '%(name)-12s %(levelname)-8s %(message)s');
#
# Introspection and configuration.
#
"""Is this a local reporter?"""
return False;
"""Increases the verbosity level."""
"""Increases the debug level."""
#
# Generic logging.
#
"""
Writes the specfied text to the log if iLevel is less or requal
to iVerbose.
"""
return 0;
#
# XML output from the reporter.
#
"""Escapes an XML attribute value."""
#sValue = sValue.replace('\'', ''');
return sValue;
"""XML output function for the reporter."""
return None;
"""Flushes XML output if buffered."""
return None;
#
# XML output from child.
#
"""Called by the file wrapper when the first bytes are written to the test pipe."""
_ = oFileWrapper;
return None;
"""Called by the file wrapper write method for test pipes."""
return self.log(0, 'raw xml%s: %s' % (oFileWrapper.sPrefix, sRawXml), sCaller, utils.getTimePrefix());
"""Called by the file wrapper __del__ method for test pipes."""
_ = oFileWrapper;
return None;
#
# File output.
#
"""
Adds the file to the report.
Returns True on success, False on failure.
"""
return True;
#
# Test reporting
#
"""
Mangles the test names in atTest into a single name to make it easier
to spot where we are.
"""
sName = '';
if sName != '':
sName += ', ';
sName += t[0];
return sName;
"""Increates the error count."""
"""Sets time out indicator for the current test and increases the error counter."""
return None;
""" Starts a new test, may be nested. """
""" Reports a benchmark value or something simiarlly useful. """
""" Reports a failure. """
self._xmlWrite([ '<FailureDetails timestamp="%s" text="%s"/>' % (sTsIso, self._xmlEscAttr(sDetails),), ]);
"""
Marks the current test as DONE, pops it and maks the next test on the
stack current.
Returns (name, errors).
"""
# safe pop
return ('internal error', 0);
# log + xml.
if cErrors == 0:
else:
elif fTimedOut:
else:
# Flush buffers when reaching the last test.
"""
Returns the number of errors accumulated by the current test.
"""
if cTests <= 0:
"""
Closes all open test as failed.
Returns True if no open tests, False if there were open tests.
"""
return True;
return False;
"""
Local reporter instance.
"""
#
# Figure the main log directory.
#
try:
import user;
except:
try:
except:
#
# Make a subdirectory for this test run.
#
try:
except:
#
# Open the log file and write a header.
#
#
# Open the xml log file and write the mandatory introduction.
#
# Note! This is done here and not in the base class because the remote
# logger doesn't really need this. It doesn't need the outer
# test wrapper either.
#
"""Ends and completes the log files."""
try:
except: pass;
"""Closes the XML file."""
# pop the test stack
'</%s>' % (sName,), ]);
# The outer one is not on the stack.
try:
except:
pass;
"""Writes to the XML file."""
if fIndent:
sText += '\n';
try:
except:
return False;
return True;
#
# Overridden methods.
#
"""Is this a local reporter?"""
return True;
# format it.
else:
# output it.
else:
sLogText += '\n';
try:
except:
pass;
return 0;
# Figure the destination filename.
self.log(0, 'Other log file: %s - %s (%s)' % (sDstFilename, sDescription, sSrcFilename), sCaller, sTsPrf);
# Open the destination file and copy over the data.
try:
else:
while True:
try:
else:
try:
else:
continue;
break;
# Leave a mark in the XML log.
% (utils.getIsoTimestamp(), self._xmlEscAttr(os.path.basename(sDstFilename)), self._xmlEscAttr(sSrcFilename), \
_ = sAltName;
return fRc;
# Open a new file and just include it from the main XML.
try:
except:
oFileWrapper.oSubXmlFile = None;
else:
return None;
if oFileWrapper.oSubXmlFile is not None:
try:
except:
pass;
if sCaller is None: pass; # pychecker - NOREF
return None;
if oFileWrapper.oSubXmlFile is not None:
try:
oFileWrapper.oSubXmlFile = None;
except:
pass;
return None;
"""
Reporter that talks to the test manager server.
"""
## The XML sync min time (seconds).
## The XML sync max time (seconds).
## The XML sync idle time before flushing (seconds).
## The XML sync line count threshold.
## The retry timeout.
## The request timeout.
# Prepare the TM connecting.
import urlparse;
import httplib;
import urllib;
else:
else:
else:
self._dHttpHeader = \
{
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'User-Agent': 'TestDriverReporter/%s.0 (%s, %s)' % (__version__, utils.getHostOs(), utils.getHostArch(),),
'Accept': 'text/plain,application/x-www-form-urlencoded',
'Accept-Encoding': 'identity',
'Cache-Control': 'max-age=0',
#'Connection': 'keep-alive',
};
dParams = {
};
"""Flush pending log messages?"""
""" Does the actual writing and flushing. """
return None;
#
# Talking to TM.
#
"""
Processes HTTP reponse from the test manager.
Returns True, False or None. None should be retried, the others not.
May raise exception on HTTP issue (retry ok).
"""
import httplib;
# Read the response and (optionally) close the connection.
try:
except: pass;
# Check the content type.
# Parse the body and check the RESULT parameter.
if sResult is not None:
return True;
return False;
self._writeOutput('%s: %s: Failed - dResponse=%s' % (utils.getTimePrefix(), sOperation, dResponse,));
else:
self._writeOutput('%s: %s: Unexpected Content-Type: %s' % (utils.getTimePrefix(), sOperation, sContentType,));
return None;
""" Uploads the given file to the test manager. """
# Prepare header and url.
});
# Retry loop.
while True:
try:
if fRc is not None:
return fRc;
except:
logXcpt('warning: exception during UPLOAD request');
break;
except:
logXcpt();
break;
return False;
"""
The code that does the actual talking to the server.
Used by both xmlFlush and __del__.
"""
while True:
fRc = None;
try:
# Post.
return (None, False);
return (None, True);
if not fDtor:
logXcpt('warning: exception during XML_RESULTS request');
else:
break;
#
# Overridden methods.
#
return False;
else:
return 0;
else:
return fRc;
"""
Flushes the XML back log. Called with the lock held, may leave it
while communicating with the server.
"""
if not self._fXmlFlushing:
if fIncErrors:
if asXml is None:
else:
return True;
return False;
"""Flushes the XML back log if necessary."""
# Absolute flush thresholds.
# Flush if idle long enough.
return False;
"""XML output function for the reporter."""
_ = fIndent; # No pretty printing, thank you.
return None;
return None;
_ = sCaller;
return None;
## @todo should validate the document here and maybe auto terminate things. Adding some hints to have the server do
# this instead.
return None;
#
# Helpers
#
"""
Log an exception, optionally with a preceeding message and more than one
call frame.
"""
if fIncErrors:
## @todo skip all this if iLevel is too high!
# Try get exception info.
try:
except:
if oType is not None:
# Try format the info
try:
rc = 0;
if sText is not None:
asInfo = [];
try:
else:
except:
g_oReporter.log(0, 'internal-error: Hit exception #2! %s' % (traceback.format_exc()), sCaller, sTsPrf);
# Do the logging.
else:
rc = -3;
except:
rc = -2;
else:
rc = -1;
return rc;
#
# The public Classes
#
""" File like class for TXS EXEC and similar. """
"""file.read"""
_ = cb;
return "";
"""file.write"""
try:
except:
pass;
try:
except:
return None;
""" File like class for the test pipe (TXS EXEC and similar). """
""" file.close """
except:
except: pass;
return True;
"""file.read"""
_ = cb;
return "";
"""file.write"""
# lazy start.
try:
except:
try:
except:
pass;
try:
except:
return None;
#
# The public APIs.
#
"""Writes the specfied text to the log."""
try:
except:
rc = -1;
return rc;
"""
Log an exception, optionally with a preceeding message and more than one
call frame.
"""
"""Log level 2: Writes the specfied text to the log."""
try:
except:
rc = -1;
return rc;
"""
Log level 2: Log an exception, optionally with a preceeding message and
more than one call frame.
"""
""" Maybe error or maybe normal log entry. """
""" Maybe error or maybe normal log exception entry. """
""" Maybe error or maybe normal log entry. """
if fIsNotError is not True:
""" Maybe error or maybe normal log exception entry. """
if fIsNotError is not True:
"""
Writes the specfied error message to the log.
This will add an error to the current test.
Always returns False for the convenience of methods returning boolean
success indicators.
"""
try:
except:
pass;
return False;
"""
Log an error caused by an exception. If sText is given, it will preceed
the exception information. cFrames can be used to display more stack.
This will add an error to the current test.
Always returns False for the convenience of methods returning boolean
success indicators.
"""
return False;
"""
Flags the current test as having timed out and writes the specified message to the log.
This will add an error to the current test.
Always returns False for the convenience of methods returning boolean
success indicators.
"""
try:
except:
pass;
return False;
"""
Writes a fatal error to the log.
This will add an error to the current test.
Always returns False for the convenience of methods returning boolean
success indicators.
"""
try:
except:
pass
return False;
"""
Log a fatal error caused by an exception. If sText is given, it will
preceed the exception information. cFrames can be used to display more
stack.
This will add an error to the current test.
Always returns False for the convenience of methods returning boolean
success indicators.
"""
return False;
"""
Adds the specified log file to the report if the file exists.
The sDescription is a free form description of the log file.
The sKind parameter is for adding some machine parsable hint what kind of
log file this really is.
Returns True on success, False on failure (no ENOENT errors are logged).
"""
if sAltName is None:
try:
else:
except:
else:
return fRc;
def isLocal():
"""Is this a local reporter?"""
return g_oReporter.isLocal()
def incVerbosity():
"""Increases the verbosity level."""
return g_oReporter.incVerbosity()
def incDebug():
"""Increases the debug level."""
return g_oReporter.incDebug()
def getErrorCount():
"""
Get the current error count for the entire test run.
"""
return cErrors;
#
# Test reporting, a bit similar to RTTestI*.
#
"""
Starts a new test (pushes it).
"""
return rc;
"""
Reports a benchmark value or something simiarlly useful.
"""
return rc;
"""
Reports a failure.
We count these calls and testDone will use them to report PASSED or FAILED.
Returns False so that a return False line can be saved.
"""
return False;
"""
Reports a failure with exception.
We count these calls and testDone will use them to report PASSED or FAILED.
Returns False so that a return False line can be saved.
"""
# Extract exception info.
try:
except:
if oType is not None:
else:
# Use testFailure to do the work.
if sDetails == '':
else:
return False;
"""
Completes the current test (pops it), logging PASSED / FAILURE.
Returns a tuple with the name of the test and its error count.
"""
return rc;
def testErrorCount():
"""
Gets the error count of the current test.
Returns the number of errors.
"""
return cErrors;
def testCleanup():
"""
Closes all open tests with a generic error condition.
Returns True if no open tests, False if something had to be closed with failure.
"""
return fRc;
#
# Sub XML stuff.
#
"""
Adds a sub-xml result file to the party.
"""
try:
except:
else:
try:
except:
return fRc;
#
# Other useful debugging tools.
#
"""
Logs the stacks of all python threads.
"""
cThread = 0;
try:
if cThread > 0:
try:
except:
else:
except:
pass;
cThread += 1;
return None;
def checkTestManagerConnection():
"""
Checks the connection to the test manager.
Returns True if the connection is fine, False if not, None if not remote
reporter.
Note! This as the sideeffect of flushing XML.
"""
return fRc;
def flushall():
"""
Flushes all output streams, both standard and logger related.
"""
except: pass;
except: pass;
# Note! Current no logger specific streams to flush.
return True;
#
# Module initialization.
#
def _InitReporterModule():
"""
Instantiate the test reporter.
"""
global g_oReporter, g_sReporterName
if g_sReporterName == "local":
g_oReporter = LocalReporter();
elif g_sReporterName == "remote":
else:
print >> sys.stderr, os.path.basename(__file__) + ": Unknown TESTBOX_REPORTER value: '" + g_sReporterName + "'";