Changes in src/tests/test.py [20340c2:a43e1d7]
- File:
-
- 1 edited
-
src/tests/test.py (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/tests/test.py
r20340c2 ra43e1d7 15 15 # help functions 16 16 ################################################################################ 17 18 # Test class that defines what a test is19 class Test:20 def __init__(self, name, path):21 self.name, self.path = name, path22 23 # parses the Makefile to find the machine type (32-bit / 64-bit)24 def getMachineType():25 sh('echo "int main() { return 0; }" > .dummy.c')26 sh("make .dummy", print2stdout=False)27 _, out = sh("file .dummy", print2stdout=False)28 sh("rm -f .dummy.c > /dev/null 2>&1")29 sh("rm -f .dummy > /dev/null 2>&1")30 return re.search("ELF\s([0-9]+)-bit", out).group(1)31 32 # reads the directory ./.expect and indentifies the tests33 17 def listTests(): 34 machineType = getMachineType() 35 36 print(machineType) 37 38 # tests directly in the .expect folder will always be processed 39 generic_list = map(lambda fname: Test(fname, fname), 40 [splitext(f)[0] for f in listdir('./.expect') 18 list = [splitext(f)[0] for f in listdir('./.expect') 41 19 if not f.startswith('.') and f.endswith('.txt') 42 ]) 43 44 # tests in the machineType folder will be ran only for the corresponding compiler 45 typed_list = map(lambda fname: Test( fname, "%s/%s" % (machineType, fname) ), 46 [splitext(f)[0] for f in listdir("./.expect/%s" % machineType) 47 if not f.startswith('.') and f.endswith('.txt') 48 ]) 49 50 # append both lists to get 51 return generic_list + typed_list 52 53 # helper functions to run terminal commands 20 ] 21 22 return list 23 54 24 def sh(cmd, dry_run = False, print2stdout = True): 55 if dry_run : # if this is a dry_run, only print the commands that would be ran25 if dry_run : 56 26 print("cmd: %s" % cmd) 57 27 return 0, None 58 else : # otherwise create a pipe and run the desired command28 else : 59 29 proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True) 60 30 out, err = proc.communicate() 61 31 return proc.returncode, out 62 32 63 # helper function to replace patterns in a file64 33 def file_replace(fname, pat, s_after): 65 34 # first, see if the pattern is even in the file. … … 77 46 os.rename(out_fname, fname) 78 47 79 # tests output may differ depending on the depth of the makefile80 48 def fix_MakeLevel(file) : 81 49 if environ.get('MAKELEVEL') : 82 50 file_replace(file, "make\[%i\]" % int(environ.get('MAKELEVEL')), 'make' ) 83 51 84 # helper function to check if a files contains only a spacific string85 52 def fileContainsOnly(file, text) : 86 53 with open(file) as f: 87 54 ff = f.read().strip() 88 55 result = ff == text.strip() 56 # 57 # print("Comparing :\n\t'%s'\nWith:\n\t'%s'" % (ff, text)) 58 # print("Result is : \n\t", end="") 59 # print(result) 89 60 90 61 return result; 91 62 92 # check whether or not a file is executable93 63 def fileIsExecutable(file) : 94 64 try : … … 101 71 return False 102 72 103 # find the test data for a given test name104 def filterTests(testname) :105 found = [test for test in allTests if test.name == testname]106 return (found[0] if len(found) == 1 else Test(testname, testname) )107 108 73 ################################################################################ 109 74 # running test functions … … 111 76 def run_test_instance(test, generate, dry_run): 112 77 113 # find the output file based on the test name and options flag 114 out_file = (".out/%s.log" % test.name) if not generate else (".expect/%s.txt" % test.path) 115 116 # remove any outputs from the previous tests to prevent side effects 78 out_file = (".out/%s.log" % test) if not generate else (".expect/%s.txt" % test) 79 117 80 sh("rm -f %s" % out_file, dry_run) 118 sh("rm -f %s > /dev/null 2>&1" % test .name, dry_run)81 sh("rm -f %s > /dev/null 2>&1" % test, dry_run) 119 82 120 83 # build, skipping to next test on error 121 make_ret, _ = sh("%s %s 2> %s 1> /dev/null" % (make_cmd, test.name, out_file), dry_run) 122 123 # if the make command succeds continue otherwise skip to diff 84 make_ret, _ = sh("%s %s 2> %s 1> /dev/null" % (make_cmd, test, out_file), dry_run) 85 124 86 if make_ret == 0 : 125 87 # fetch optional input 126 stdinput = "< .in/%s.txt" % test .name if isfile(".in/%s.txt" % test.path) else ""127 128 if fileIsExecutable(test .name) :88 stdinput = "< .in/%s.txt" % test if isfile(".in/%s.txt" % test) else "" 89 90 if fileIsExecutable(test) : 129 91 # run test 130 sh("./%s %s > %s 2>&1" % (test .name, stdinput, out_file), dry_run)92 sh("./%s %s > %s 2>&1" % (test, stdinput, out_file), dry_run) 131 93 else : 132 94 # simply cat the result into the output 133 sh("cat %s > %s" % (test .name, out_file), dry_run)95 sh("cat %s > %s" % (test, out_file), dry_run) 134 96 135 97 retcode = 0 136 98 error = None 137 99 138 # fix output to prevent make depth to cause issues139 100 fix_MakeLevel(out_file) 140 101 141 102 if generate : 142 # if we are ounly generating the output we still need to check that the test actually exists 143 if not dry_run and fileContainsOnly(out_file, "make: *** No rule to make target `%s'. Stop." % test.name) : 103 if not dry_run and fileContainsOnly(out_file, "make: *** No rule to make target `%s'. Stop." % test) : 144 104 retcode = 1; 145 105 error = "\t\tNo make target for test %s!" % test … … 162 122 ".expect/%s.txt .out/%s.log") 163 123 164 # fetch return code and error from the diff command 165 retcode, error = sh(diff_cmd % (test.path, test.name), dry_run, False) 124 retcode, error = sh(diff_cmd % (test, test), dry_run, False) 166 125 167 126 # clean the executable 168 sh("rm -f %s > /dev/null 2>&1" % test .name, dry_run)127 sh("rm -f %s > /dev/null 2>&1" % test, dry_run) 169 128 170 129 return retcode, error 171 130 172 # run the given list of tests with the given parameters 173 def run_tests(tests, generate, dry_run, jobs) : 174 # clean the sandbox from previous commands 131 def run_tests(tests, generate, dry_run) : 175 132 sh("%s clean > /dev/null 2>&1" % make_cmd, dry_run) 176 177 #make sure the required folder are present178 133 sh('mkdir -p .out .expect', dry_run) 179 134 … … 182 137 183 138 failed = False; 184 # for eeach test to run185 139 for t in tests: 186 # print formated name 187 name_txt = "%20s " % t.name 188 189 #run the test instance and collect the result 140 print("%20s " % t, end="") 141 sys.stdout.flush() 190 142 test_failed, error = run_test_instance(t, generate, dry_run) 191 192 # aggregate test suite result193 143 failed = test_failed or failed 194 144 195 # update output based on current action196 145 if generate : 197 146 failed_txt = "ERROR" … … 201 150 success_txt = "PASSED" 202 151 203 #print result with error if needed 204 text = name_txt + (failed_txt if test_failed else success_txt) 205 out = sys.stdout 152 print(failed_txt if test_failed else success_txt) 206 153 if error : 207 text = text + "\n" + error 208 out = sys.stderr 209 210 print(text, file = out); 211 sys.stdout.flush() 212 sys.stderr.flush() 213 214 215 #clean the workspace 154 print(error, file=sys.stderr) 155 216 156 sh("%s clean > /dev/null 2>&1" % make_cmd, dry_run) 217 157 … … 221 161 # main loop 222 162 ################################################################################ 223 # create a parser with the arguments for the tests script224 163 parser = argparse.ArgumentParser(description='Script which runs cforall tests') 225 164 parser.add_argument('--dry-run', help='Don\'t run the tests, only output the commands', action='store_true') … … 227 166 parser.add_argument('--all', help='Run all test available', action='store_true') 228 167 parser.add_argument('--regenerate-expected', help='Regenerate the .expect by running the specified tets, can be used with --all option', action='store_true') 229 parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously', type=int, default='8')230 168 parser.add_argument('tests', metavar='test', type=str, nargs='*', help='a list of tests to run') 231 169 232 # parse the command line arguments233 170 options = parser.parse_args() 234 171 235 # script must have at least some tests to run236 172 if (len(options.tests) > 0 and options.all and not options.list) \ 237 173 or (len(options.tests) == 0 and not options.all and not options.list) : … … 240 176 sys.exit(1) 241 177 242 # fetch the liest of all valid tests243 178 allTests = listTests() 244 179 245 # if user wants all tests than no other treatement of the test list is required246 180 if options.all or options.list : 247 181 tests = allTests 248 182 249 183 else : 250 #otherwise we need to validate that the test list that was entered is valid251 184 tests = [] 252 253 # if we are regenerating the tests we need to find the information of the 254 # already existing tests and create new info for the new tests 255 if options.regenerate_expected : 256 tests = map(filterTests, options.tests) 257 258 else : 259 # otherwise we only need to validate that all tests are present in the complete list 260 for testname in options.tests: 261 test = [t for t in allTests if t.name == testname] 262 263 if len(test) != 0 : 264 tests.append( test[0] ) 265 else : 266 print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr) 267 268 # make sure we have at least some test to run 185 for test in options.tests: 186 if test in allTests or options.regenerate_expected : 187 tests.append(test) 188 else : 189 print('ERROR: No expected file for test %s, ignoring it' % test, file=sys.stderr) 190 269 191 if len(tests) == 0 : 270 192 print('ERROR: No valid test to run', file=sys.stderr) 271 193 sys.exit(1) 272 194 273 # sort the test alphabetically for convenience 274 tests.sort(key=lambda t: t.name) 275 276 # check if the user already passed in a number of jobs for multi-threading 195 tests.sort() 277 196 make_flags = environ.get('MAKEFLAGS') 278 make_has_max_jobs = re.search("(-j|--jobs)\s*([0-9]+)", make_flags) if make_flags else None279 make_max_jobs = make_has_max_jobs.group(2) if make_has_max_jobs else None280 197 make_cmd = "make" if make_flags and "-j" in make_flags else "make -j8" 281 198 282 # make sure we have a valid number of jobs that corresponds to user input283 options.jobs = int(make_max_jobs) if make_max_jobs else options.jobs284 if options.jobs <= 0 :285 print('ERROR: Invalid number of jobs', file=sys.stderr)286 sys.exit(1)287 288 # users may want to simply list the tests289 199 if options.list : 290 print("\n".join( map(lambda t: "%s (%s)" % (t.name, t.path), tests)))200 print("\n".join(tests)) 291 201 292 202 else : 293 # otherwise run all tests and make sure to return the correct error code 294 sys.exit( run_tests(tests, options.regenerate_expected, options.dry_run, options.jobs) ) 203 sys.exit( run_tests(tests, options.regenerate_expected, options.dry_run) )
Note:
See TracChangeset
for help on using the changeset viewer.