]> rtime.felk.cvut.cz Git - omk.git/commitdiff
Test framework finished
authorMichal Sojka <sojkam1@fel.cvut.cz>
Fri, 19 Jan 2007 18:55:00 +0000 (18:55 +0000)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Fri, 19 Jan 2007 18:55:00 +0000 (18:55 +0000)
darcs-hash:20070119185502-f2ef6-c1d9fc90c07afa430f1a503ffdd9334f8b2ca122.gz

tests/Makefile
tests/README.tests
tests/runtests.py

index 9115bc835b895d32ee53d69549e63383361c3a2a..b21a87ad76ba27ba7f5ffb74ce63b59ef832ef73 100644 (file)
@@ -1,3 +1,4 @@
 
 all:
-       python runtests.py
\ No newline at end of file
+       find -name runtest -print0|xargs -0 chmod +x
+       python runtests.py
index 8a3b41475e9a12701320abb1e2b739e4668617b2..469f1e6438956f9c490f01409bec98410db0f48f 100644 (file)
@@ -13,19 +13,15 @@ files: Makefile.test, runtest.
 
 * Testcase Definition:
 
-  - Testcase program: 
-    either Makefile.test, where the commands are in the form of makefile.
-    or runtest, which is the executable file that runs the test(s).
+  - runtest (mandatory): is the executable that runs the test(s).
 
   - rules: Specifies the rules this testcase applies to. The syntax of
     this files is describes in section Rules description.
 
 * Testcase Execution:
 
-  If Makefile.test is found, make is executed as "make -k -f
-  Makefile.test". If no Makefile.test is found, runtest is
-  executed. Tests are executed with OMK_RULES environment variable set
-  to the name of the actual rules tested.
+  Runtest is executed with OMK_RULES environment variable set to the
+  name of the actual rules tested.
 
 * Testcase Output:
 
@@ -39,7 +35,7 @@ files: Makefile.test, runtest.
 
 
   - Error message:
-    In the case of error, the file 'error' should contain more
+    In the case of error, the file '_error' should contain more
     detailed description of the error.
 
   - stdout and stderr: TODO
index 9f64ad01d9154e43ac648460f734dcb9538cf236..4228ad24fab284e94523f1ce60c34ae4c2cd0495 100755 (executable)
@@ -5,15 +5,146 @@ import os.path
 import sys
 import re
 import shutil
+import subprocess
+import time
 
 sys.path.append("..")
 import rulesdef
 
+class Results(dict):
+    def __init__(self):
+        self.time = time.gmtime()
+        self.datetime = time.strftime("%Y-%m-%d %H:%M:%S +0000", self.time)
+        self.filename = "results-"+time.strftime("%Y%m%d-%H%M%S", self.time)+".html"
+        
+    def toHtml(self):
+        s="""
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+  <title>OMK test report %(datetime)s</title>
+</head>
+<body>
+<h2>Summary</h2>TODO
+        """
+        s+="""
+<h2>Chart</h2>
+<table cellpadding='2' border='1'>
+<tbody>
+        """ % self.__dict__
+        tests = sorted(self.keys())
+        for t in tests:
+            s+=self[t].toHtml()
+        s+="""
+</tbody></table>
+<h2>Outputs of tests</h2>
+        """
+        for t in tests:
+            s+=self[t].toHtmlOutputs()
+        s+="""
+</body></html>
+        """
+        return s
+    
+    def save(self):
+        f = file(self.filename, "w+")
+        f.write(self.toHtml())
+        try:
+            os.remove("results.html")
+        except:
+            pass
+        os.symlink(self.filename, "results.html")
+        print "Results written to "+self.filename
+
+class TestCaseResult(dict):
+    def __init__(self, tcname):
+        self.tcname = tcname
+        
+    def toHtml(self):
+        rules = sorted(self.keys())
+        s="""
+  <tr><td colspan='6'><strong>%s</strong></td></tr>
+        """ % self.tcname
+        for r in rules:
+            s+=self[r].toHtml()
+        return s
+
+    def toHtmlOutputs(self):
+        rules = sorted(self.keys())
+        s="<h3>Testcase: %s</h3>" % self.tcname
+        for r in rules:
+            s+=self[r].toHtmlOutputs()
+        return s
+
+class ResultEntry:
+    def __init__(self, tcname, rules):
+        self.tcname = tcname
+        self.rules = rules
+        
+    def toHtml(self):
+        if self.exitcode == 0: color=''
+        else:
+            if self.exitcode == 1:   color=' bgcolor="red"'
+            elif self.exitcode == 2: color=' bgcolor="yellow"'
+            else: color=' bgcolor="silver"'
+        if self.stdout: stdoutlink="<a href='#stdout-%(tcname)s-%(rules)s'>stdout</a>" % self.__dict__
+        else: stdoutlink=''
+        if self.stderr: stderrlink="<a href='#stderr-%(tcname)s-%(rules)s'>stderr</a>" % self.__dict__
+        else: stderrlink=''
+        s="""
+  <tr%(color)s>
+    <td>%(rules)s</td>
+    <td>%(exitcode)d</td>
+    <td>%(message)s</td>
+    <td>%(time).1f s</td>
+    <td>%(stdoutlink)s</td>
+    <td>%(stderrlink)s</td>
+  </tr>
+        """ % {
+            'color' : color,
+            'tcname' : self.rules,
+            'rules' : self.rules,
+            'exitcode' : self.exitcode,
+            'message' : self.message,
+            'time' : self.time,
+            'stdoutlink' : stdoutlink,
+            'stderrlink' : stderrlink,
+            }
+        return s
+    def toHtmlOutputs(self):
+        vals = {
+            'tcname':self.tcname,
+            'rules':self.rules,
+            'stdout':self.stdout,
+            'stderr':self.stderr
+            }
+        s=""
+        if self.stdout: s+="""
+<a name='stdout-%(tcname)s-%(rules)s'/>
+<h5>Test %(tcname)s, rules %(rules)s, stdout</h5>
+<pre>%(stdout)s</pre>""" % vals
+        if self.stderr: s+="""
+<a name='stderr-%(tcname)s-%(rules)s'/>
+<h5>Test %(tcname)s, rules %(rules)s, stderr</h5>
+<pre>%(stderr)s</pre>""" % vals
+        return s
+
 class TestCase:
     def __init__(self, directory):
         self.directory = directory      # Absolute directory
+        self.name = self._getName()
         self._whichRules()
 
+    def _getName(self):
+        name = self.directory
+        if name.startswith(testsRoot+"/"):
+            name = name[len(testsRoot)+1:]
+        return name
+
     def _whichRules(self):
         """Reads the rules file and creates the self.rules list of all
         rules to test"""
@@ -48,39 +179,82 @@ class TestCase:
         
 
     def run(self):
-        print "Testing %s:" % self.directory,
+        self.results = TestCaseResult(self.name)
+        print "Testing %s:" % self.name,
         os.chdir(os.path.join(testsRoot, self.directory))
+#         if os.path.exists("Makefile.test"):
+#             self._exec = self._execMake
+        if os.path.exists("runtest"):
+            self._exec = self._execRuntest
+        else: return
         for rules in self.rules:
+            resultEntry = ResultEntry(self.name, rules)
+            self.results[rules] = resultEntry
+            print rules,
             os.environ['OMK_RULES'] = rules
+            filesBefore = self._getFileSet()
             self._copyRules(rules)
-            self._doRun()
+            self._doRun(resultEntry)
+            filesAfter = self._getFileSet()
+            self._clean(filesBefore, filesAfter)
         print
-        # TODO remove makefile rules if sucessfull
+
+    def _getFileSet(self):
+        files = set()
+        for f in os.listdir("."):
+            files.add(f)
+        return files
+        
+    def _clean(self, filesBefore, filesAfter):
+        remove = filesAfter - filesBefore
+        for f in remove:
+            os.system("rm -rf "+f)
+
+#     def _execMake(self):
+#         return os.system("make -k -f Makefile.test > /dev/null 2>&1")
+
+    def _execRuntest(self, log):
+        startTime = time.clock()
+        pipe = subprocess.Popen("./runtest", stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
+        endTime = time.clock()
+        (output, errors) = pipe.communicate()
+        ret = pipe.returncode
+        log.exitcode = ret
+        log.time = endTime - startTime
+        log.stdout = output
+        log.stderr = errors
+        if ret != 0 and os.path.exists("_error"):
+            log.message = file("_error").read()
+        else: log.message = ''
+        
+        return ret
 
     def _copyRules(self, rules):
         "Copies the rules to the current directory"
         src = os.path.join(testsRoot, "..", "rules", rules, "Makefile.rules")
         shutil.copy(src, ".")
     
-    def _doRun(self):
+    def _doRun(self, log):
         "Runs the teset in current directory."
-        if os.path.exists("Makefile.test"):
-            ret = os.system("make -k -f Makefile.test")
-        elif os.path.exists("runtest"):
-            ret = os.system("./runtest")
+        ret = self._exec(log)
         print ret,
 
 
 testsRoot = os.path.dirname(os.path.abspath(__file__))
 if not os.path.exists(os.path.join(testsRoot, "runtests.py")): raise "Can't find tests root directory!"
 
+results = Results()
+
 for dirpath, dirnames, filenames in os.walk(testsRoot):
     if not ("Makefile.test" in filenames or \
             "runtest" in filenames):
         continue
-    print dirpath
     t = TestCase(dirpath)
     t.run()
+    results[t.name] = t.results
+
+os.chdir(testsRoot)
+results.save()
 
 # Local Variables:
 # compile-command: "python runtests.py"