[SCM] Samba Shared Repository - branch master updated - 717ef3867a22a5f7427a04083da6cc0b50353bd2

Jelmer Vernooij jelmer at samba.org
Wed Oct 8 02:23:46 GMT 2008


The branch, master has been updated
       via  717ef3867a22a5f7427a04083da6cc0b50353bd2 (commit)
       via  f8a02a1a804fdb8640989595e2b57df86281c0f7 (commit)
       via  df4e9c7066059f072420d869ba6d2f383838afad (commit)
       via  f9facb51207713d1f294038e68909ba7701c61e4 (commit)
       via  99b2089752e202adbf4113b1854636e1db2f97c7 (commit)
       via  68837ff597bd39ff215ef30b4616692d2e31b1b4 (commit)
       via  3ecde315d3ef6d13ea3811d34deb51f87cdeaa6d (commit)
       via  8da78b732554a88bee0f1dd547e329fe8d82b7f9 (commit)
       via  c024fb7d5745dbca96b969c88284b70ac7c520e4 (commit)
       via  20b73b1309a74eee3fbf37738407584dce63bb78 (commit)
      from  859facda89ff3589e87c4cbe1708578769d7c535 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 717ef3867a22a5f7427a04083da6cc0b50353bd2
Merge: f8a02a1a804fdb8640989595e2b57df86281c0f7 859facda89ff3589e87c4cbe1708578769d7c535
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 03:39:17 2008 +0200

    Merge branch 'master' of ssh://git.samba.org/data/git/samba

commit f8a02a1a804fdb8640989595e2b57df86281c0f7
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 03:33:38 2008 +0200

    Fix subunit files location after cherrypicks.

commit df4e9c7066059f072420d869ba6d2f383838afad
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 02:23:51 2008 +0200

    Fix path apparently gone wrong by cherrypick.

commit f9facb51207713d1f294038e68909ba7701c61e4
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 02:17:47 2008 +0200

    Move all subunit files to lib directory.

commit 99b2089752e202adbf4113b1854636e1db2f97c7
Merge: 68837ff597bd39ff215ef30b4616692d2e31b1b4 2024d87cf5ffa0633225ed189fa48f0f56151e7e
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 02:21:49 2008 +0200

    Merge branch 'master' of ssh://git.samba.org/data/git/samba

commit 68837ff597bd39ff215ef30b4616692d2e31b1b4
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Oct 7 01:23:34 2008 +0200

    Fix syntax errors in minschema.

commit 3ecde315d3ef6d13ea3811d34deb51f87cdeaa6d
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 01:58:42 2008 +0200

    Import tests for subunit python module.

commit 8da78b732554a88bee0f1dd547e329fe8d82b7f9
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Wed Oct 8 01:48:44 2008 +0200

    Move subunit helper utility to specific subunit directory.

commit c024fb7d5745dbca96b969c88284b70ac7c520e4
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Mon Oct 6 16:00:10 2008 +0200

    Allow 'make testenv-dc', 'make testenv-member', etc.

commit 20b73b1309a74eee3fbf37738407584dce63bb78
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Mon Oct 6 04:54:48 2008 +0200

    Print proper error if include file can't be found.

-----------------------------------------------------------------------

Summary of changes:
 lib/subunit/harness2subunit.pl                     |   36 +
 lib/subunit/python/subunit/__init__.py             |  388 +++++++++++
 lib/subunit/python/subunit/tests/TestUtil.py       |   80 +++
 lib/subunit/python/subunit/tests/__init__.py       |   25 +
 lib/subunit/python/subunit/tests/sample-script.py  |   11 +
 .../python/subunit/tests/sample-two-script.py      |    7 +
 .../python/subunit/tests/test_test_protocol.py     |  730 ++++++++++++++++++++
 pidl/lib/Parse/Pidl/ODL.pm                         |    4 +
 source4/lib/ldb/tests/python/ldap.py               |    1 +
 source4/script/harness2subunit.pl                  |   36 -
 source4/scripting/bin/minschema                    |   36 +-
 source4/scripting/bin/subunitrun                   |    1 +
 source4/scripting/python/config.mk                 |    4 +-
 source4/scripting/python/subunit/__init__.py       |  388 -----------
 source4/selftest/config.mk                         |    3 +
 source4/selftest/samba4_tests.sh                   |    3 +-
 16 files changed, 1306 insertions(+), 447 deletions(-)
 create mode 100755 lib/subunit/harness2subunit.pl
 create mode 100644 lib/subunit/python/subunit/__init__.py
 create mode 100644 lib/subunit/python/subunit/tests/TestUtil.py
 create mode 100644 lib/subunit/python/subunit/tests/__init__.py
 create mode 100755 lib/subunit/python/subunit/tests/sample-script.py
 create mode 100755 lib/subunit/python/subunit/tests/sample-two-script.py
 create mode 100644 lib/subunit/python/subunit/tests/test_test_protocol.py
 delete mode 100755 source4/script/harness2subunit.pl
 delete mode 100644 source4/scripting/python/subunit/__init__.py


Changeset truncated at 500 lines:

diff --git a/lib/subunit/harness2subunit.pl b/lib/subunit/harness2subunit.pl
new file mode 100755
index 0000000..45f5155
--- /dev/null
+++ b/lib/subunit/harness2subunit.pl
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+# Simple script that converts Perl test harness output to 
+# Subunit
+# Copyright (C) 2008 Jelmer Vernooij <jelmer at samba.org>
+# Published under the GNU GPL, v3 or later
+
+my $firstline = 1;
+my $error = 0;
+while(<STDIN>) {
+	if ($firstline) {
+		$firstline = 0;
+		next;
+	}
+	if (/^not ok (\d+) - (.*)$/) {
+		print "test: $2\n";
+		print "failure: $2\n";
+		$error = 1;
+	} elsif (/^ok (\d+) - (.*)$/) {
+		print "test: $2\n";
+		print "success: $2\n";
+	} elsif (/^ok (\d+)$/) {
+		print "test: $1\n";
+		print "success: $1\n";
+	} elsif (/^ok (\d+) # skip (.*)$/) {
+		print "test: $1\n";
+		print "skip: $1 [\n$2\n]\n";
+	} elsif (/^not ok (\d+)$/) {
+		print "test: $1\n";
+		print "failure: $1\n";
+		$error = 1;
+	} else {
+		print;
+	}
+}
+exit $error;
+
diff --git a/lib/subunit/python/subunit/__init__.py b/lib/subunit/python/subunit/__init__.py
new file mode 100644
index 0000000..406cd87
--- /dev/null
+++ b/lib/subunit/python/subunit/__init__.py
@@ -0,0 +1,388 @@
+#
+#  subunit: extensions to python unittest to get test results from subprocesses.
+#  Copyright (C) 2005  Robert Collins <robertc at robertcollins.net>
+#  Copyright (C) 2007  Jelmer Vernooij <jelmer at samba.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import os
+from StringIO import StringIO
+import sys
+import unittest
+
+def test_suite():
+    import subunit.tests
+    return subunit.tests.test_suite()
+
+
+def join_dir(base_path, path):
+    """
+    Returns an absolute path to C{path}, calculated relative to the parent
+    of C{base_path}.
+
+    @param base_path: A path to a file or directory.
+    @param path: An absolute path, or a path relative to the containing
+    directory of C{base_path}.
+
+    @return: An absolute path to C{path}.
+    """
+    return os.path.join(os.path.dirname(os.path.abspath(base_path)), path)
+
+
+class TestProtocolServer(object):
+    """A class for receiving results from a TestProtocol client."""
+
+    OUTSIDE_TEST = 0
+    TEST_STARTED = 1
+    READING_FAILURE = 2
+    READING_ERROR = 3
+
+    def __init__(self, client, stream=sys.stdout):
+        """Create a TestProtocol server instance.
+
+        client should be an object that provides
+         - startTest
+         - addSuccess
+         - addFailure
+         - addError
+         - stopTest
+        methods, i.e. a TestResult.
+        """
+        self.state = TestProtocolServer.OUTSIDE_TEST
+        self.client = client
+        self._stream = stream
+
+    def _addError(self, offset, line):
+        if (self.state == TestProtocolServer.TEST_STARTED and
+            self.current_test_description == line[offset:-1]):
+            self.state = TestProtocolServer.OUTSIDE_TEST
+            self.current_test_description = None
+            self.client.addError(self._current_test, RemoteError(""))
+            self.client.stopTest(self._current_test)
+            self._current_test = None
+        elif (self.state == TestProtocolServer.TEST_STARTED and
+            self.current_test_description + " [" == line[offset:-1]):
+            self.state = TestProtocolServer.READING_ERROR
+            self._message = ""
+        else:
+            self.stdOutLineReceived(line)
+
+    def _addFailure(self, offset, line):
+        if (self.state == TestProtocolServer.TEST_STARTED and
+            self.current_test_description == line[offset:-1]):
+            self.state = TestProtocolServer.OUTSIDE_TEST
+            self.current_test_description = None
+            self.client.addFailure(self._current_test, RemoteError())
+            self.client.stopTest(self._current_test)
+        elif (self.state == TestProtocolServer.TEST_STARTED and
+            self.current_test_description + " [" == line[offset:-1]):
+            self.state = TestProtocolServer.READING_FAILURE
+            self._message = ""
+        else:
+            self.stdOutLineReceived(line)
+
+    def _addSuccess(self, offset, line):
+        if (self.state == TestProtocolServer.TEST_STARTED and
+            self.current_test_description == line[offset:-1]):
+            self.client.addSuccess(self._current_test)
+            self.client.stopTest(self._current_test)
+            self.current_test_description = None
+            self._current_test = None
+            self.state = TestProtocolServer.OUTSIDE_TEST
+        else:
+            self.stdOutLineReceived(line)
+
+    def _appendMessage(self, line):
+        if line[0:2] == " ]":
+            # quoted ] start
+            self._message += line[1:]
+        else:
+            self._message += line
+
+    def endQuote(self, line):
+        if self.state == TestProtocolServer.READING_FAILURE:
+            self.state = TestProtocolServer.OUTSIDE_TEST
+            self.current_test_description = None
+            self.client.addFailure(self._current_test,
+                                   RemoteError(self._message))
+            self.client.stopTest(self._current_test)
+        elif self.state == TestProtocolServer.READING_ERROR:
+            self.state = TestProtocolServer.OUTSIDE_TEST
+            self.current_test_description = None
+            self.client.addError(self._current_test,
+                                 RemoteError(self._message))
+            self.client.stopTest(self._current_test)
+        else:
+            self.stdOutLineReceived(line)
+
+    def lineReceived(self, line):
+        """Call the appropriate local method for the received line."""
+        if line == "]\n":
+            self.endQuote(line)
+        elif (self.state == TestProtocolServer.READING_FAILURE or
+              self.state == TestProtocolServer.READING_ERROR):
+            self._appendMessage(line)
+        else:
+            parts = line.split(None, 1)
+            if len(parts) == 2:
+                cmd, rest = parts
+                offset = len(cmd) + 1
+                cmd = cmd.strip(':')
+                if cmd in ('test', 'testing'):
+                    self._startTest(offset, line)
+                elif cmd == 'error':
+                    self._addError(offset, line)
+                elif cmd == 'failure':
+                    self._addFailure(offset, line)
+                elif cmd in ('success', 'successful'):
+                    self._addSuccess(offset, line)
+                else:
+                    self.stdOutLineReceived(line)
+            else:
+                self.stdOutLineReceived(line)
+
+    def lostConnection(self):
+        """The input connection has finished."""
+        if self.state == TestProtocolServer.TEST_STARTED:
+            self.client.addError(self._current_test,
+                                 RemoteError("lost connection during test '%s'"
+                                             % self.current_test_description))
+            self.client.stopTest(self._current_test)
+        elif self.state == TestProtocolServer.READING_ERROR:
+            self.client.addError(self._current_test,
+                                 RemoteError("lost connection during "
+                                             "error report of test "
+                                             "'%s'" %
+                                             self.current_test_description))
+            self.client.stopTest(self._current_test)
+        elif self.state == TestProtocolServer.READING_FAILURE:
+            self.client.addError(self._current_test,
+                                 RemoteError("lost connection during "
+                                             "failure report of test "
+                                             "'%s'" %
+                                             self.current_test_description))
+            self.client.stopTest(self._current_test)
+
+    def readFrom(self, pipe):
+        for line in pipe.readlines():
+            self.lineReceived(line)
+        self.lostConnection()
+
+    def _startTest(self, offset, line):
+        """Internal call to change state machine. Override startTest()."""
+        if self.state == TestProtocolServer.OUTSIDE_TEST:
+            self.state = TestProtocolServer.TEST_STARTED
+            self._current_test = RemotedTestCase(line[offset:-1])
+            self.current_test_description = line[offset:-1]
+            self.client.startTest(self._current_test)
+        else:
+            self.stdOutLineReceived(line)
+
+    def stdOutLineReceived(self, line):
+        self._stream.write(line)
+
+
+class RemoteException(Exception):
+    """An exception that occured remotely to python."""
+
+    def __eq__(self, other):
+        try:
+            return self.args == other.args
+        except AttributeError:
+            return False
+
+
+class TestProtocolClient(unittest.TestResult):
+    """A class that looks like a TestResult and informs a TestProtocolServer."""
+
+    def __init__(self, stream):
+        super(TestProtocolClient, self).__init__()
+        self._stream = stream
+
+    def addError(self, test, error):
+        """Report an error in test test."""
+        self._stream.write("error: %s [\n" % (test.shortDescription() or str(test)))
+        for line in self._exc_info_to_string(error, test).splitlines():
+            self._stream.write("%s\n" % line)
+        self._stream.write("]\n")
+        super(TestProtocolClient, self).addError(test, error)
+
+    def addFailure(self, test, error):
+        """Report a failure in test test."""
+        self._stream.write("failure: %s [\n" % (test.shortDescription() or str(test)))
+        for line in self._exc_info_to_string(error, test).splitlines():
+            self._stream.write("%s\n" % line)
+        self._stream.write("]\n")
+        super(TestProtocolClient, self).addFailure(test, error)
+
+    def addSuccess(self, test):
+        """Report a success in a test."""
+        self._stream.write("successful: %s\n" % (test.shortDescription() or str(test)))
+        super(TestProtocolClient, self).addSuccess(test)
+
+    def startTest(self, test):
+        """Mark a test as starting its test run."""
+        self._stream.write("test: %s\n" % (test.shortDescription() or str(test)))
+        super(TestProtocolClient, self).startTest(test)
+
+
+def RemoteError(description=""):
+    if description == "":
+        description = "\n"
+    return (RemoteException, RemoteException(description), None)
+
+
+class RemotedTestCase(unittest.TestCase):
+    """A class to represent test cases run in child processes."""
+
+    def __eq__ (self, other):
+        try:
+            return self.__description == other.__description
+        except AttributeError:
+            return False
+
+    def __init__(self, description):
+        """Create a psuedo test case with description description."""
+        self.__description = description
+
+    def error(self, label):
+        raise NotImplementedError("%s on RemotedTestCases is not permitted." %
+            label)
+
+    def setUp(self):
+        self.error("setUp")
+
+    def tearDown(self):
+        self.error("tearDown")
+
+    def shortDescription(self):
+        return self.__description
+
+    def id(self):
+        return "%s.%s" % (self._strclass(), self.__description)
+
+    def __str__(self):
+        return "%s (%s)" % (self.__description, self._strclass())
+
+    def __repr__(self):
+        return "<%s description='%s'>" % \
+               (self._strclass(), self.__description)
+
+    def run(self, result=None):
+        if result is None: result = self.defaultTestResult()
+        result.startTest(self)
+        result.addError(self, RemoteError("Cannot run RemotedTestCases.\n"))
+        result.stopTest(self)
+
+    def _strclass(self):
+        cls = self.__class__
+        return "%s.%s" % (cls.__module__, cls.__name__)
+
+
+class ExecTestCase(unittest.TestCase):
+    """A test case which runs external scripts for test fixtures."""
+
+    def __init__(self, methodName='runTest'):
+        """Create an instance of the class that will use the named test
+           method when executed. Raises a ValueError if the instance does
+           not have a method with the specified name.
+        """
+        unittest.TestCase.__init__(self, methodName)
+        testMethod = getattr(self, methodName)
+        self.script = join_dir(sys.modules[self.__class__.__module__].__file__,
+                               testMethod.__doc__)
+
+    def countTestCases(self):
+        return 1
+
+    def run(self, result=None):
+        if result is None: result = self.defaultTestResult()
+        self._run(result)
+
+    def debug(self):
+        """Run the test without collecting errors in a TestResult"""
+        self._run(unittest.TestResult())
+
+    def _run(self, result):
+        protocol = TestProtocolServer(result)
+        output = os.popen(self.script, mode='r')
+        protocol.readFrom(output)
+
+
+class IsolatedTestCase(unittest.TestCase):
+    """A TestCase which runs its tests in a forked process."""
+
+    def run(self, result=None):
+        if result is None: result = self.defaultTestResult()
+        run_isolated(unittest.TestCase, self, result)
+
+
+class IsolatedTestSuite(unittest.TestSuite):
+    """A TestCase which runs its tests in a forked process."""
+
+    def run(self, result=None):
+        if result is None: result = unittest.TestResult()
+        run_isolated(unittest.TestSuite, self, result)
+
+
+def run_isolated(klass, self, result):
+    """Run a test suite or case in a subprocess, using the run method on klass.
+    """
+    c2pread, c2pwrite = os.pipe()
+    # fixme - error -> result
+    # now fork
+    pid = os.fork()
+    if pid == 0:
+        # Child
+        # Close parent's pipe ends
+        os.close(c2pread)
+        # Dup fds for child
+        os.dup2(c2pwrite, 1)
+        # Close pipe fds.
+        os.close(c2pwrite)
+
+        # at this point, sys.stdin is redirected, now we want
+        # to filter it to escape ]'s.
+        ### XXX: test and write that bit.
+
+        result = TestProtocolClient(sys.stdout)
+        klass.run(self, result)
+        sys.stdout.flush()
+        sys.stderr.flush()
+        # exit HARD, exit NOW.
+        os._exit(0)
+    else:
+        # Parent
+        # Close child pipe ends
+        os.close(c2pwrite)
+        # hookup a protocol engine
+        protocol = TestProtocolServer(result)
+        protocol.readFrom(os.fdopen(c2pread, 'rU'))
+        os.waitpid(pid, 0)
+        # TODO return code evaluation.
+    return result
+
+
+class SubunitTestRunner(object):
+    def __init__(self, stream=sys.stdout):
+        self.stream = stream
+
+    def run(self, test):
+        "Run the given test case or test suite."
+        result = TestProtocolClient(self.stream)
+        test(result)
+        return result
+
diff --git a/lib/subunit/python/subunit/tests/TestUtil.py b/lib/subunit/python/subunit/tests/TestUtil.py
new file mode 100644
index 0000000..1b5ba9c
--- /dev/null
+++ b/lib/subunit/python/subunit/tests/TestUtil.py
@@ -0,0 +1,80 @@
+# Copyright (c) 2004 Canonical Limited
+#       Author: Robert Collins <robert.collins at canonical.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import sys
+import logging
+import unittest
+
+
+class LogCollector(logging.Handler):
+    def __init__(self):
+        logging.Handler.__init__(self)
+        self.records=[]
+    def emit(self, record):
+        self.records.append(record.getMessage())
+
+
+def makeCollectingLogger():
+    """I make a logger instance that collects its logs for programmatic analysis
+    -> (logger, collector)"""
+    logger=logging.Logger("collector")
+    handler=LogCollector()
+    handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
+    logger.addHandler(handler)
+    return logger, handler
+
+
+def visitTests(suite, visitor):
+    """A foreign method for visiting the tests in a test suite."""
+    for test in suite._tests:
+        #Abusing types to avoid monkey patching unittest.TestCase.
+        # Maybe that would be better?
+        try:
+            test.visit(visitor)
+        except AttributeError:
+            if isinstance(test, unittest.TestCase):
+                visitor.visitCase(test)
+            elif isinstance(test, unittest.TestSuite):
+                visitor.visitSuite(test)
+                visitTests(test, visitor)
+            else:
+                print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
+
+


-- 
Samba Shared Repository


More information about the samba-cvs mailing list