[gcr] Makefile.am: Implement proper make check-memory target



commit 7555cdcab98022e7336e4e49309b6b7d3359b636
Author: Stef Walter <stefw gnome org>
Date:   Wed Mar 5 12:25:24 2014 +0100

    Makefile.am: Implement proper make check-memory target
    
    Uses valgrind to run the tests. Update the tap-driver and
    tap-gtester pieces to accomodate this.

 .gitignore                          |    1 +
 Makefile.am                         |   54 +++++++--
 build/Makefile.am                   |   34 ------
 build/tap-driver                    |  215 +++++++++++++++++++++++------------
 build/{tap-compiler => tap-gtester} |   20 ++--
 5 files changed, 197 insertions(+), 127 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index ea2e9c4..ff41d82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,3 +114,4 @@ stamp-*
 /build/coverage
 /build/coverage.info
 /build/valgrind-suppressions
+/build/test-driver
diff --git a/Makefile.am b/Makefile.am
index 37bbdd5..af36e6a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,12 +8,6 @@ SUBDIRS = \
 
 ACLOCAL_AMFLAGS = -I build/m4 ${ACLOCAL_FLAGS}
 
-EXTRA_DIST = \
-       intltool-extract.in \
-       intltool-merge.in \
-       intltool-update.in \
-       HACKING
-
 DISTCHECK_CONFIGURE_FLAGS = \
        --enable-gtk-doc \
        --enable-strict \
@@ -42,15 +36,40 @@ dist-hook:
                echo A git clone is required to generate a ChangeLog >&2; \
        fi
 
-check-memory:
-       make -C gcr check-memory
-
 check-local: check-gck-symbols check-gcr-symbols check-ui-symbols
 
 upload-release: $(DIST_ARCHIVES)
        scp $(DIST_ARCHIVES) master.gnome.org:
        ssh master.gnome.org ftpadmin install $(DIST_ARCHIVES)
 
+# Default executable tests
+LOG_DRIVER = $(srcdir)/build/tap-driver
+LOG_DRIVER_FLAGS = --format=tap
+LOG_COMPILER = $(srcdir)/build/tap-gtester
+
+VALGRIND_ARGS = --trace-children=no --quiet --error-exitcode=33 \
+       --suppressions=valgrind-suppressions --gen-suppressions=all \
+       --num-callers=16
+VALGRIND_SUPPRESSIONS = \
+       build/gcr.supp \
+       build/gcrypt.supp \
+       build/glib.supp \
+       build/glibc.supp \
+       build/p11-kit.supp \
+       build/pixman.supp \
+       build/pthread.supp \
+       build/unknown.supp
+
+valgrind-suppressions: $(VALGRIND_SUPPRESSIONS)
+       $(AM_V_GEN) cat $^ > $@
+
+check-memory: valgrind-suppressions
+       $(MAKE) LOG_FLAGS="-- libtool --mode=execute valgrind $(VALGRIND_ARGS)" \
+               $(AM_MAKEFLAGS) check
+recheck-memory: valgrind-suppressions
+       $(MAKE) LOG_FLAGS="-- libtool --mode=execute valgrind $(VALGRIND_ARGS)" \
+               $(AM_MAKEFLAGS) recheck
+
 AM_CPPFLAGS = \
        -I$(srcdir) \
        -I$(builddir) \
@@ -63,9 +82,6 @@ AM_CPPFLAGS = \
 LDADD = \
        $(GLIB_LIBS)
 
-LOG_DRIVER = $(srcdir)/build/tap-driver
-LOG_COMPILER = $(srcdir)/build/tap-compiler
-
 BUILT_SOURCES =
 TESTS =
 
@@ -81,6 +97,19 @@ pkgconfigdir = $(libdir)/pkgconfig
 CLEANFILES = \
        $(pkgconfig_DATA)
 
+EXTRA_DIST = \
+       intltool-extract.in \
+       intltool-merge.in \
+       intltool-update.in \
+       HACKING \
+       build/valgrind \
+       $(VALGRIND_SUPPRESSIONS) \
+       build/enum-template.c \
+       build/enum-template.h \
+       build/g-ir-unbreak.xsl \
+       build/tap-driver \
+       build/tap-gtester
+
 TEST_SUPPRESSIONS = $(top_builddir)/build/valgrind-suppressions
 
 V_SED = $(V_SED_$(V))
@@ -162,7 +191,6 @@ endif
 
 endif
 
-include build/Makefile.am
 include egg/Makefile.am
 include gck/Makefile.am
 include gcr/Makefile.am
diff --git a/build/tap-driver b/build/tap-driver
index eb22462..3906b40 100755
--- a/build/tap-driver
+++ b/build/tap-driver
@@ -35,21 +35,16 @@ import subprocess
 import sys
 
 class Driver:
-    def __init__(self, command, args):
-        self.argv = command
-        self.output = ""
+    def __init__(self, args):
+        self.argv = args.command
         self.test_name = args.test_name
         self.log = open(args.log_file, "w")
+        self.log.write("# %s\n" % " ".join(sys.argv))
         self.trs = open(args.trs_file, "w")
         self.color_tests = args.color_tests
         self.expect_failure = args.expect_failure
-        self.reported = { }
-        self.test_plan = None
-        self.late_plan = False
-        self.errored = False
-        self.bail_out = False
 
-    def report(self, code, num, *args):
+    def report(self, code, *args):
         CODES = {
             "XPASS": '\x1b[0;31m', # red
             "FAIL": '\x1b[0;31m', # red
@@ -69,9 +64,6 @@ class Driver:
         sys.stdout.write(": ")
         sys.stdout.write(self.test_name)
         sys.stdout.write(" ")
-        if num:
-            sys.stdout.write(str(num))
-            sys.stdout.write(" ")
         for arg in args:
             sys.stdout.write(str(arg))
         sys.stdout.write("\n")
@@ -79,32 +71,81 @@ class Driver:
 
         # Book keeping
         if code in CODES:
-            if num != None:
-                self.reported[num] = code
             self.trs.write(":test-result: %s\n" % code)
-        if code == "ERROR":
-            self.errored = True
 
-    def result_pass(self, num, description):
+    def result_pass(self, *args):
         if self.expect_failure:
-            self.report("XPASS", num, description)
+            self.report("XPASS", *args)
         else:
-            self.report("PASS", num, description)
+            self.report("PASS", *args)
 
-    def result_fail(self, num, description):
+    def result_fail(self, *args):
         if self.expect_failure:
-            self.report("XFAIL", num, description)
+            self.report("XFAIL", *args)
         else:
-            self.report("FAIL", num, description)
+            self.report("FAIL", *args)
 
-    def result_skip(self, num, description, ok):
+    def result_skip(self, *args):
         if self.expect_failure:
-            self.report("XFAIL", num, description)
+            self.report("XFAIL", *args)
         else:
-            self.report("SKIP", num, description)
+            self.report("SKIP", *args)
 
-    def report_error(self, problem):
-        self.report("ERROR", None, problem)
+    def report_error(self, description=""):
+        self.report("ERROR", "", description)
+
+    def process(self, output):
+        pass
+
+    def execute(self):
+        try:
+            proc = subprocess.Popen(self.argv, close_fds=True,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
+        except OSError, ex:
+            self.report_error("Couldn't run %s: %s" % (self.argv[0], str(ex)))
+            return
+
+        outf = proc.stdout.fileno()
+        errf = proc.stderr.fileno()
+        rset = [outf, errf]
+        while len(rset) > 0:
+            ret = select.select(rset, [], [], 10)
+            if outf in ret[0]:
+                data = os.read(outf, 1024)
+                if data == "":
+                    rset.remove(outf)
+                self.log.write(data)
+                self.process(data)
+            if errf in ret[0]:
+                data = os.read(errf, 1024)
+                if data == "":
+                    rset.remove(errf)
+                self.log.write(data)
+                sys.stderr.write(data)
+
+        proc.wait()
+        return proc.returncode
+
+
+class TapDriver(Driver):
+    def __init__(self, args):
+        Driver.__init__(self, args)
+        self.output = ""
+        self.reported = { }
+        self.test_plan = None
+        self.late_plan = False
+        self.errored = False
+        self.bail_out = False
+
+    def report(self, code, num, *args):
+        if num:
+            Driver.report(self, code, num, " ", *args)
+            self.reported[num] = code
+        else:
+            Driver.report(self, code, *args)
+        if code == "ERROR":
+            self.errored = True
 
     def consume_test_line(self, ok, data):
         # It's an error if the caller sends a test plan in the middle of tests
@@ -117,13 +158,13 @@ class Driver:
         try:
             num = int(num)
         except ValueError:
-            self.report_error("Invalid test number: %s" %  data)
+            self.report_error("Invalid test number: %s" % data)
             return
         description = description.lstrip()
 
         # Special case if description starts with this, then skip
         if description.lower().startswith("# skip"):
-            self.result_skip(num, description, ok)
+            self.result_skip(num, description)
         elif ok:
             self.result_pass(num, description)
         else:
@@ -149,12 +190,13 @@ class Driver:
         self.bail_out = True
         self.report("SKIP", 0, line)
 
-    def drain(self):
+    def process(self, output):
+        if output:
+            self.output += output
+        elif self.output:
+            self.output += "\n"
         (ready, unused, self.output) = self.output.rpartition("\n")
         for line in ready.split("\n"):
-            self.log.write(line)
-            self.log.write("\n")
-
             if line.startswith("ok "):
                 self.consume_test_line(True, line[3:])
             elif line.startswith("not ok "):
@@ -165,41 +207,8 @@ class Driver:
             elif line.lower().startswith("bail out!"):
                 self.consume_bail_out(line)
 
-    def execute(self):
-        try:
-            proc = subprocess.Popen(self.argv, close_fds=True,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-        except OSError, ex:
-            self.report_error("Couldn't run %s: %s" % (self.argv[0], str(ex)))
-            return
-
-        outf = proc.stdout.fileno()
-        errf = proc.stderr.fileno()
-        rset = [outf, errf]
-        while len(rset) > 0:
-            ret = select.select(rset, [], [], 10)
-            if outf in ret[0]:
-                data = os.read(outf, 1024)
-                if data == "":
-                    if self.output:
-                        self.output += "\n"
-                    rset.remove(outf)
-                else:
-                    self.output += data
-                self.drain()
-            if errf in ret[0]:
-                data = os.read(errf, 1024)
-                if data == "":
-                    rset.remove(errf)
-                self.log.write(data)
-                sys.stderr.write(data)
-
-        proc.wait()
-        self.returncode = proc.returncode
-
     def run(self):
-        self.execute()
+        returncode = self.execute()
 
         failed = False
         skipped = True
@@ -213,6 +222,10 @@ class Driver:
             if code != "SKIP":
                 skipped = False
 
+        if not self.errored and returncode:
+            self.report_error("process failed: %d" % returncode)
+            self.errored = True
+
         # Check the plan
         if not self.errored:
             if not self.test_plan:
@@ -231,7 +244,7 @@ class Driver:
         if self.errored:
             self.trs.write(":global-test-result: ERROR\n")
             self.trs.write(":test-global-result: ERROR\n")
-            self.trs.write(":recheck: no\n")
+            self.trs.write(":recheck: yes\n")
         elif failed:
             self.trs.write(":global-test-result: FAIL\n")
             self.trs.write(":test-global-result: FAIL\n")
@@ -240,11 +253,62 @@ class Driver:
             self.trs.write(":global-test-result: SKIP\n")
             self.trs.write(":test-global-result: SKIP\n")
             self.trs.write(":recheck: no\n")
+        else:
+            self.trs.write(":global-test-result: PASS\n")
+            self.trs.write(":test-global-result: PASS\n")
+            self.trs.write(":recheck: no\n")
         if self.errored or failed:
             self.trs.write(":copy-in-global-log: yes\n")
 
         # Process result code
-        return self.errored and 1 or 0
+        return 0
+
+
+class SimpleDriver(Driver):
+    def __init__(self, args):
+        Driver.__init__(self, args)
+
+    def run(self):
+        returncode = self.execute()
+        if returncode == 0:
+            self.result_pass()
+            self.trs.write(":global-test-result: PASS\n")
+            self.trs.write(":test-global-result: PASS\n")
+            self.trs.write(":recheck: no\n")
+        elif returncode == 77:
+            self.result_skip()
+            self.trs.write(":global-test-result: SKIP\n")
+            self.trs.write(":test-global-result: SKIP\n")
+            self.trs.write(":recheck: no\n")
+        elif returncode == 99:
+            self.report_error()
+            self.trs.write(":global-test-result: ERROR\n")
+            self.trs.write(":test-global-result: ERROR\n")
+            self.trs.write(":copy-in-global-log: yes\n")
+            self.trs.write(":recheck: yes\n")
+        else:
+            self.result_fail()
+            self.trs.write(":global-test-result: FAIL\n")
+            self.trs.write(":test-global-result: FAIL\n")
+            self.trs.write(":copy-in-global-log: yes\n")
+            self.trs.write(":recheck: yes\n")
+
+        # Process result code
+        return 0
+
+
+class MissingDriver(Driver):
+    def __init__(self, args):
+        Driver.__init__(self, args)
+        self.missing = args.missing
+
+    def run(self):
+        self.result_skip("skipping due to: ", self.missing)
+        self.trs.write(":global-test-result: SKIP\n")
+        self.trs.write(":test-global-result: SKIP\n")
+        self.trs.write(":recheck: no\n")
+        return 0
+
 
 class YesNoAction(argparse.Action):
     def __init__(self, option_strings, dest, **kwargs):
@@ -256,8 +320,13 @@ class YesNoAction(argparse.Action):
         else:
             setattr(namespace, self.dest, False)
 
+
 def main(argv):
     parser = argparse.ArgumentParser(description='Automake TAP driver')
+    parser.add_argument('--format', metavar='FORMAT', choices=[ "simple", "tap" ],
+                        default="simple", help='The type of test to drive')
+    parser.add_argument('--missing', metavar="TOOL", nargs='?',
+                        help="Force the test to skip due to missing tool")
     parser.add_argument('--test-name', metavar='NAME',
                         help='The name of the test')
     parser.add_argument('--log-file', metavar='PATH.log', required=True,
@@ -276,8 +345,12 @@ def main(argv):
 
     if not args.test_name:
         args.test_name = os.path.basename(args.command[0])
-
-    driver = Driver(args.command, args)
+    if args.missing:
+        driver = MissingDriver(args)
+    elif args.format == "simple":
+        driver = SimpleDriver(args)
+    elif args.format == "tap":
+        driver = TapDriver(args)
     return driver.run()
 
 if __name__ == "__main__":
diff --git a/build/tap-compiler b/build/tap-gtester
similarity index 92%
rename from build/tap-compiler
rename to build/tap-gtester
index 76b3171..ff7506a 100755
--- a/build/tap-compiler
+++ b/build/tap-gtester
@@ -80,7 +80,8 @@ class GTestCompiler(NullCompiler):
                    print "not ok %d %s", (self.test_num, self.test_name)
                self.test_name = None
            elif cmd == "skipping":
-               print "ok %d # skip -- %s" % (self.test_num, self.test_name)
+               if "/subprocess" not in data:
+                   print "ok %d # skip -- %s" % (self.test_num, data)
                self.test_name = None
            elif data:
                print "# %s: %s" % (cmd, data)
@@ -97,7 +98,8 @@ class GTestCompiler(NullCompiler):
         output += proc.stdout.read()
         proc.wait()
         if proc.returncode:
-            raise subprocess.CalledProcessError(proc.returncode, self.command)
+            sys.stderr.write("tap-gtester: listing GTest tests failed: %d\n" % proc.returncode)
+            return proc.returncode
         self.test_remaining = []
         for line in output.split("\n"):
             if line.startswith("/"):
@@ -130,14 +132,14 @@ class GTestCompiler(NullCompiler):
             result = self.process(proc)
 
             # The various exit codes and signals we continue for
-            if result not in [ 0, 1, -4, -5, -6, -7, -8, -11 ]:
+            if result not in [ 0, 1, -4, -5, -6, -7, -8, -11, 33 ]:
                 break
 
         return result
 
 def main(argv):
     parser = argparse.ArgumentParser(description='Automake TAP compiler')
-    parser.add_argument('--format', metavar='FORMAT', choices=[ "auto", "GTest", "TAP" ],
+    parser.add_argument('--format', metavar='FORMAT', choices=[ "auto", "gtest", "tap" ],
                         default="auto", help='The input format to compile')
     parser.add_argument('--verbose', action='store_true',
                         default=True, help='Verbose mode (ignored)')
@@ -149,21 +151,21 @@ def main(argv):
     cmd = args.command
     proc = None
 
-    if format in ["auto", "GTest"]:
+    if format in ["auto", "gtest"]:
         list_cmd = cmd + ["-l", "--verbose"]
         proc = subprocess.Popen(list_cmd, close_fds=True, stdout=subprocess.PIPE)
         output = proc.stdout.readline()
         # Smell whether we're dealing with GTest list output from first line
         if "random seed" in output or "GTest" in output or output.startswith("/"):
-            format = "GTest"
+            format = "gtest"
         else:
-            format = "TAP"
+            format = "tap"
     else:
         proc = subprocess.Popen(cmd, close_fds=True, stdout=subprocess.PIPE)
 
-    if format == "GTest":
+    if format == "gtest":
         compiler = GTestCompiler(cmd)
-    elif format == "TAP":
+    elif format == "tap":
         compiler = NullCompiler(cmd)
     else:
         assert False, "not reached"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]