build/pymake/tests/runtests.py

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 #!/usr/bin/env python
michael@0 2 """
michael@0 3 Run the test(s) listed on the command line. If a directory is listed, the script will recursively
michael@0 4 walk the directory for files named .mk and run each.
michael@0 5
michael@0 6 For each test, we run gmake -f test.mk. By default, make must exit with an exit code of 0, and must print 'TEST-PASS'.
michael@0 7
michael@0 8 Each test is run in an empty directory.
michael@0 9
michael@0 10 The test file may contain lines at the beginning to alter the default behavior. These are all evaluated as python:
michael@0 11
michael@0 12 #T commandline: ['extra', 'params', 'here']
michael@0 13 #T returncode: 2
michael@0 14 #T returncode-on: {'win32': 2}
michael@0 15 #T environment: {'VAR': 'VALUE}
michael@0 16 #T grep-for: "text"
michael@0 17 """
michael@0 18
michael@0 19 from subprocess import Popen, PIPE, STDOUT
michael@0 20 from optparse import OptionParser
michael@0 21 import os, re, sys, shutil, glob
michael@0 22
michael@0 23 class ParentDict(dict):
michael@0 24 def __init__(self, parent, **kwargs):
michael@0 25 self.d = dict(kwargs)
michael@0 26 self.parent = parent
michael@0 27
michael@0 28 def __setitem__(self, k, v):
michael@0 29 self.d[k] = v
michael@0 30
michael@0 31 def __getitem__(self, k):
michael@0 32 if k in self.d:
michael@0 33 return self.d[k]
michael@0 34
michael@0 35 return self.parent[k]
michael@0 36
michael@0 37 thisdir = os.path.dirname(os.path.abspath(__file__))
michael@0 38
michael@0 39 pymake = [sys.executable, os.path.join(os.path.dirname(thisdir), 'make.py')]
michael@0 40 manifest = os.path.join(thisdir, 'tests.manifest')
michael@0 41
michael@0 42 o = OptionParser()
michael@0 43 o.add_option('-g', '--gmake',
michael@0 44 dest="gmake", default="gmake")
michael@0 45 o.add_option('-d', '--tempdir',
michael@0 46 dest="tempdir", default="_mktests")
michael@0 47 opts, args = o.parse_args()
michael@0 48
michael@0 49 if len(args) == 0:
michael@0 50 args = [thisdir]
michael@0 51
michael@0 52 makefiles = []
michael@0 53 for a in args:
michael@0 54 if os.path.isfile(a):
michael@0 55 makefiles.append(a)
michael@0 56 elif os.path.isdir(a):
michael@0 57 makefiles.extend(sorted(glob.glob(os.path.join(a, '*.mk'))))
michael@0 58
michael@0 59 def runTest(makefile, make, logfile, options):
michael@0 60 """
michael@0 61 Given a makefile path, test it with a given `make` and return
michael@0 62 (pass, message).
michael@0 63 """
michael@0 64
michael@0 65 if os.path.exists(opts.tempdir): shutil.rmtree(opts.tempdir)
michael@0 66 os.mkdir(opts.tempdir, 0755)
michael@0 67
michael@0 68 logfd = open(logfile, 'w')
michael@0 69 p = Popen(make + options['commandline'], stdout=logfd, stderr=STDOUT, env=options['env'])
michael@0 70 logfd.close()
michael@0 71 retcode = p.wait()
michael@0 72
michael@0 73 if retcode != options['returncode']:
michael@0 74 return False, "FAIL (returncode=%i)" % retcode
michael@0 75
michael@0 76 logfd = open(logfile)
michael@0 77 stdout = logfd.read()
michael@0 78 logfd.close()
michael@0 79
michael@0 80 if stdout.find('TEST-FAIL') != -1:
michael@0 81 print stdout
michael@0 82 return False, "FAIL (TEST-FAIL printed)"
michael@0 83
michael@0 84 if options['grepfor'] and stdout.find(options['grepfor']) == -1:
michael@0 85 print stdout
michael@0 86 return False, "FAIL (%s not in output)" % options['grepfor']
michael@0 87
michael@0 88 if options['returncode'] == 0 and stdout.find('TEST-PASS') == -1:
michael@0 89 print stdout
michael@0 90 return False, 'FAIL (No TEST-PASS printed)'
michael@0 91
michael@0 92 if options['returncode'] != 0:
michael@0 93 return True, 'PASS (retcode=%s)' % retcode
michael@0 94
michael@0 95 return True, 'PASS'
michael@0 96
michael@0 97 print "%-30s%-28s%-28s" % ("Test:", "gmake:", "pymake:")
michael@0 98
michael@0 99 gmakefails = 0
michael@0 100 pymakefails = 0
michael@0 101
michael@0 102 tre = re.compile('^#T (gmake |pymake )?([a-z-]+)(?:: (.*))?$')
michael@0 103
michael@0 104 for makefile in makefiles:
michael@0 105 # For some reason, MAKEFILE_LIST uses native paths in GNU make on Windows
michael@0 106 # (even in MSYS!) so we pass both TESTPATH and NATIVE_TESTPATH
michael@0 107 cline = ['-C', opts.tempdir, '-f', os.path.abspath(makefile), 'TESTPATH=%s' % thisdir.replace('\\','/'), 'NATIVE_TESTPATH=%s' % thisdir]
michael@0 108 if sys.platform == 'win32':
michael@0 109 #XXX: hack so we can specialize the separator character on windows.
michael@0 110 # we really shouldn't need this, but y'know
michael@0 111 cline += ['__WIN32__=1']
michael@0 112
michael@0 113 options = {
michael@0 114 'returncode': 0,
michael@0 115 'grepfor': None,
michael@0 116 'env': dict(os.environ),
michael@0 117 'commandline': cline,
michael@0 118 'pass': True,
michael@0 119 'skip': False,
michael@0 120 }
michael@0 121
michael@0 122 gmakeoptions = ParentDict(options)
michael@0 123 pymakeoptions = ParentDict(options)
michael@0 124
michael@0 125 dmap = {None: options, 'gmake ': gmakeoptions, 'pymake ': pymakeoptions}
michael@0 126
michael@0 127 mdata = open(makefile)
michael@0 128 for line in mdata:
michael@0 129 line = line.strip()
michael@0 130 m = tre.search(line)
michael@0 131 if m is None:
michael@0 132 break
michael@0 133
michael@0 134 make, key, data = m.group(1, 2, 3)
michael@0 135 d = dmap[make]
michael@0 136 if data is not None:
michael@0 137 data = eval(data)
michael@0 138 if key == 'commandline':
michael@0 139 assert make is None
michael@0 140 d['commandline'].extend(data)
michael@0 141 elif key == 'returncode':
michael@0 142 d['returncode'] = data
michael@0 143 elif key == 'returncode-on':
michael@0 144 if sys.platform in data:
michael@0 145 d['returncode'] = data[sys.platform]
michael@0 146 elif key == 'environment':
michael@0 147 for k, v in data.iteritems():
michael@0 148 d['env'][k] = v
michael@0 149 elif key == 'grep-for':
michael@0 150 d['grepfor'] = data
michael@0 151 elif key == 'fail':
michael@0 152 d['pass'] = False
michael@0 153 elif key == 'skip':
michael@0 154 d['skip'] = True
michael@0 155 else:
michael@0 156 print >>sys.stderr, "%s: Unexpected #T key: %s" % (makefile, key)
michael@0 157 sys.exit(1)
michael@0 158
michael@0 159 mdata.close()
michael@0 160
michael@0 161 if gmakeoptions['skip']:
michael@0 162 gmakepass, gmakemsg = True, ''
michael@0 163 else:
michael@0 164 gmakepass, gmakemsg = runTest(makefile, [opts.gmake],
michael@0 165 makefile + '.gmakelog', gmakeoptions)
michael@0 166
michael@0 167 if gmakeoptions['pass']:
michael@0 168 if not gmakepass:
michael@0 169 gmakefails += 1
michael@0 170 else:
michael@0 171 if gmakepass:
michael@0 172 gmakefails += 1
michael@0 173 gmakemsg = "UNEXPECTED PASS"
michael@0 174 else:
michael@0 175 gmakemsg = "KNOWN FAIL"
michael@0 176
michael@0 177 if pymakeoptions['skip']:
michael@0 178 pymakepass, pymakemsg = True, ''
michael@0 179 else:
michael@0 180 pymakepass, pymakemsg = runTest(makefile, pymake,
michael@0 181 makefile + '.pymakelog', pymakeoptions)
michael@0 182
michael@0 183 if pymakeoptions['pass']:
michael@0 184 if not pymakepass:
michael@0 185 pymakefails += 1
michael@0 186 else:
michael@0 187 if pymakepass:
michael@0 188 pymakefails += 1
michael@0 189 pymakemsg = "UNEXPECTED PASS"
michael@0 190 else:
michael@0 191 pymakemsg = "OK (known fail)"
michael@0 192
michael@0 193 print "%-30.30s%-28.28s%-28.28s" % (os.path.basename(makefile),
michael@0 194 gmakemsg, pymakemsg)
michael@0 195
michael@0 196 print
michael@0 197 print "Summary:"
michael@0 198 print "%-30s%-28s%-28s" % ("", "gmake:", "pymake:")
michael@0 199
michael@0 200 if gmakefails == 0:
michael@0 201 gmakemsg = 'PASS'
michael@0 202 else:
michael@0 203 gmakemsg = 'FAIL (%i failures)' % gmakefails
michael@0 204
michael@0 205 if pymakefails == 0:
michael@0 206 pymakemsg = 'PASS'
michael@0 207 else:
michael@0 208 pymakemsg = 'FAIL (%i failures)' % pymakefails
michael@0 209
michael@0 210 print "%-30.30s%-28.28s%-28.28s" % ('', gmakemsg, pymakemsg)
michael@0 211
michael@0 212 shutil.rmtree(opts.tempdir)
michael@0 213
michael@0 214 if gmakefails or pymakefails:
michael@0 215 sys.exit(1)

mercurial