Some re-achitecturing of the plugins interface. The caller is now required to

pass in a 'sender' arg to the buildDefault(), buildDsym(), buildDwarf(), and
cleanup() functions.  The sender arg will be the test instance itself (i.e.,
an instance of TestBase).  This is so that the relevant command execution can be
recorded in the TestBase.session object if sender is available.

The lldbtest.system() command has been modified to pop the 'sender' arg out of
the keyword arguments dictionary and use it as the test instance to facilitate
seesion recordings.  An example is in test/types/AbstractBase.py:

    def generic_type_tester(self, atoms, quotedDisplay=False):
        """Test that variables with basic types are displayed correctly."""

        # First, capture the golden output emitted by the oracle, i.e., the
        # series of printf statements.
        go = system("./a.out", sender=self)

There are cases when sender is None.  This is the case when the @classmethod is
involved in the use of these APIs.  When this happens, there is no recording
into a session object, but printing on the sys.stderr is still honored if the
trace flag is ON.

An example is in test/settings/TestSettings.py:

    @classmethod
    def classCleanup(cls):
        system(["/bin/sh", "-c", "rm -f output.txt"])
        system(["/bin/sh", "-c", "rm -f stdout.txt"])

llvm-svn: 116648
This commit is contained in:
Johnny Chen 2010-10-15 23:55:05 +00:00
parent 1f81ced14c
commit 690fcef762
3 changed files with 74 additions and 76 deletions

View File

@ -185,52 +185,6 @@ def CMD_MSG(str, exe):
def EnvArray():
return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values())
# From 2.7's subprocess.check_output() convenience function.
def system(*popenargs, **kwargs):
r"""Run command with arguments and return its output as a byte string.
If the exit code was non-zero it raises a CalledProcessError. The
CalledProcessError object will have the return code in the returncode
attribute and output in the output attribute.
The arguments are the same as for the Popen constructor. Example:
>>> check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
The stdout argument is not allowed as it is used internally.
To capture standard error in the result, use stderr=STDOUT.
>>> check_output(["/bin/sh", "-c",
... "ls -l non_existent_file ; exit 0"],
... stderr=STDOUT)
'ls: non_existent_file: No such file or directory\n'
"""
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = Popen(stdout=PIPE, *popenargs, **kwargs)
output, error = process.communicate()
retcode = process.poll()
if traceAlways:
if isinstance(popenargs, types.StringTypes):
args = [popenargs]
else:
args = list(popenargs)
print >> sys.stderr
print >> sys.stderr, "os command:", args
print >> sys.stderr, "stdout:", output
print >> sys.stderr, "stderr:", error
print >> sys.stderr, "retcode:", retcode
print >> sys.stderr
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd)
return output
def line_number(filename, string_to_match):
"""Helper function to return the line number of the first matched string."""
with open(filename, 'r') as f:
@ -254,10 +208,9 @@ class recording(StringIO.StringIO):
into the stderr.
"""
def __init__(self, test, trace):
"""Create a StringIO instance; record session, stderr, and trace."""
"""Create a StringIO instance; record the session obj and trace flag."""
StringIO.StringIO.__init__(self)
self.session = test.session
self.stderr = test.old_stderr
self.session = test.session if test else None
self.trace = trace
def __enter__(self):
@ -274,10 +227,61 @@ class recording(StringIO.StringIO):
recordings to our session object. And close the StringIO object, too.
"""
if self.trace:
print >> self.stderr, self.getvalue()
print >> self.session, self.getvalue()
print >> sys.stderr, self.getvalue()
if self.session:
print >> self.session, self.getvalue()
self.close()
# From 2.7's subprocess.check_output() convenience function.
def system(*popenargs, **kwargs):
r"""Run command with arguments and return its output as a byte string.
If the exit code was non-zero it raises a CalledProcessError. The
CalledProcessError object will have the return code in the returncode
attribute and output in the output attribute.
The arguments are the same as for the Popen constructor. Example:
>>> check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
The stdout argument is not allowed as it is used internally.
To capture standard error in the result, use stderr=STDOUT.
>>> check_output(["/bin/sh", "-c",
... "ls -l non_existent_file ; exit 0"],
... stderr=STDOUT)
'ls: non_existent_file: No such file or directory\n'
"""
# Assign the sender object to variable 'test' and remove it from kwargs.
test = kwargs.pop('sender', None)
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = Popen(stdout=PIPE, *popenargs, **kwargs)
output, error = process.communicate()
retcode = process.poll()
with recording(test, traceAlways) as sbuf:
if isinstance(popenargs, types.StringTypes):
args = [popenargs]
else:
args = list(popenargs)
print >> sbuf
print >> sbuf, "os command:", args
print >> sbuf, "stdout:", output
print >> sbuf, "stderr:", error
print >> sbuf, "retcode:", retcode
print >> sbuf
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd)
return output
class TestBase(unittest2.TestCase):
"""This LLDB abstract base class is meant to be subclassed."""
@ -403,16 +407,10 @@ class TestBase(unittest2.TestCase):
self.dict = None
self.doTearDownCleanup = False
# Create a string buffer to record the session info.
# Create a string buffer to record the session info, to be dumped into a
# test case specific file if test failure is encountered.
self.session = StringIO.StringIO()
# Substitute self.session as the sys.stderr and restore it at the end of
# the test during tearDown(). If trace is ON, we dump the session info
# into the real stderr as well. The session info will be dumped into a
# test case specific file if a failure is encountered.
self.old_stderr = sys.stderr
sys.stderr = self.session
# Optimistically set self.__failed__ to False initially. If the test
# failed, the session info (self.session) is then dumped into a session
# specific file for diagnosis.
@ -469,9 +467,6 @@ class TestBase(unittest2.TestCase):
if self.__failed__:
self.dumpSessionInfo()
# Restore the sys.stderr to what it was before.
sys.stderr = self.old_stderr
def runCmd(self, cmd, msg=None, check=True, trace=False, setCookie=True):
"""
Ask the command interpreter to handle the command and then check its
@ -656,19 +651,19 @@ class TestBase(unittest2.TestCase):
def buildDefault(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build the default binaries."""
module = __import__(sys.platform)
if not module.buildDefault(architecture, compiler, dictionary):
if not module.buildDefault(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build default binary")
def buildDsym(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build binaries with dsym info."""
module = __import__(sys.platform)
if not module.buildDsym(architecture, compiler, dictionary):
if not module.buildDsym(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build binary with dsym")
def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build binaries with dwarf maps."""
module = __import__(sys.platform)
if not module.buildDwarf(architecture, compiler, dictionary):
if not module.buildDwarf(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build binary with dwarf")
def DebugSBValue(self, frame, val):

View File

@ -57,43 +57,46 @@ def getCmdLine(d):
return " " + cmdline
def buildDefault(architecture=None, compiler=None, dictionary=None):
def buildDefault(sender=None, architecture=None, compiler=None, dictionary=None):
"""Build the binaries the default way."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary) + "; make"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)])
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building default.
return True
def buildDsym(architecture=None, compiler=None, dictionary=None):
def buildDsym(sender=None, architecture=None, compiler=None, dictionary=None):
"""Build the binaries with dsym debug info."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=YES"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)])
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building dsym.
return True
def buildDwarf(architecture=None, compiler=None, dictionary=None):
def buildDwarf(sender=None, architecture=None, compiler=None, dictionary=None):
"""Build the binaries with dwarf debug info."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=NO"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)])
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building dsym.
return True
def cleanup(dictionary=None):
def cleanup(sender=None, dictionary=None):
"""Perform a platform-specific cleanup after the test."""
if os.path.isfile("Makefile"):
lldbtest.system(["/bin/sh", "-c", "make clean" + getCmdLine(dictionary)]
)
lldbtest.system(["/bin/sh", "-c", "make clean"+getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building dsym.
return True

View File

@ -24,7 +24,7 @@ class GenericTester(TestBase):
# First, capture the golden output emitted by the oracle, i.e., the
# series of printf statements.
go = system("./a.out")
go = system("./a.out", sender=self)
# This golden list contains a list of (variable, value) pairs extracted
# from the golden output.
gl = []
@ -102,7 +102,7 @@ class GenericTester(TestBase):
# First, capture the golden output emitted by the oracle, i.e., the
# series of printf statements.
go = system("./a.out")
go = system("./a.out", sender=self)
# This golden list contains a list of (variable, value) pairs extracted
# from the golden output.
gl = []