Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tests/test.py

    ra468e1e9 r2cd949b  
    66
    77import argparse
    8 import itertools
    98import re
    109import sys
     
    2423
    2524        def match_test(path):
    26                 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.nast|\.oast)?(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
     25                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2726                if match :
    2827                        test = Test()
    2928                        test.name = match.group(2)
    3029                        test.path = match.group(1)
    31                         test.arch = match.group(4)[1:] if match.group(4) else None
    32 
    33                         astv = match.group(3)[1:] if match.group(3) else None
    34                         if astv == 'oast':
    35                                 test.astv = 'old'
    36                         elif astv == 'nast':
    37                                 test.astv = 'new'
    38                         elif astv:
    39                                 print('ERROR: "%s", expect file has astv but it is not "nast" or "oast"' % testname, file=sys.stderr)
    40                                 sys.exit(1)
    41 
    42                         expected.append(test)
     30                        test.arch = match.group(3)[1:] if match.group(3) else None
     31                        if settings.arch.match(test.arch):
     32                                expected.append(test)
    4333
    4434        path_walk( match_test )
     
    6353                ]
    6454
    65         # sort the test alphabetically for convenience
    66         test_list.sort(key=lambda t: ('~' if t.arch else '') + t.target() + (t.arch if t.arch else ''))
    67 
    6855        return test_list
    6956
     
    7663        if options.regenerate_expected :
    7764                for testname in options.tests :
    78                         testname = os.path.normpath( os.path.join(settings.SRCDIR, testname) )
    79 
    80                         # first check if this is a valid name to regenerate
     65                        testname = canonical_path( testname )
    8166                        if Test.valid_name(testname):
    82                                 # this is a valid name, let's check if it already exists
    8367                                found = [test for test in all_tests if canonical_path( test.target() ) == testname]
    84                                 setup = itertools.product(settings.all_arch if options.arch else [None], settings.all_ast if options.ast else [None])
    85                                 if not found:
    86                                         # it's a new name, create it according to the name and specified architecture/ast version
    87                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
    88                                 elif len(found) == 1 and not found[0].arch:
    89                                         # we found a single test, the user better be wanting to create a cross platform test
    90                                         if options.arch:
    91                                                 print('ERROR: "%s", test has no specified architecture but --arch was specified, ignoring it' % testname, file=sys.stderr)
    92                                         elif options.ast:
    93                                                 print('ERROR: "%s", test has no specified ast version but --ast was specified, ignoring it' % testname, file=sys.stderr)
    94                                         else:
    95                                                 tests.append( found[0] )
    96                                 else:
    97                                         # this test is already cross platform, just add a test for each platform the user asked
    98                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
    99 
    100                                         # print a warning if it users didn't ask for a specific architecture
    101                                         found_arch = [f.arch for f in found if f.arch]
    102                                         if found_arch and not options.arch:
    103                                                 print('WARNING: "%s", test has architecture specific expected files but --arch was not specified, regenerating only for current host' % testname, file=sys.stderr)
    104 
    105 
    106                                         # print a warning if it users didn't ask for a specific ast version
    107                                         found_astv = [f.astv for f in found if f.astv]
    108                                         if found_astv and not options.ast:
    109                                                 print('WARNING: "%s", test has ast version specific expected files but --ast was not specified, regenerating only for current ast' % testname, file=sys.stderr)
    110 
     68                                tests.append( found[0] if len(found) == 1 else Test.from_target(testname) )
    11169                        else :
    11270                                print('ERROR: "%s", tests are not allowed to end with a C/C++/CFA extension, ignoring it' % testname, file=sys.stderr)
     
    11876
    11977                        if test :
    120                                 tests.extend( test )
     78                                tests.append( test[0] )
    12179                        else :
    12280                                print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr)
     
    12886        # create a parser with the arguments for the tests script
    12987        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
    130         parser.add_argument('--ast', help='Test for specific ast', type=comma_separated(str), default=None)
    131         parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None)
    132         parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes')
    133         parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    134         parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    135         parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120)
     88        parser.add_argument('--debug', help='Run all tests in debug or release', type=yes_no, default='yes')
     89        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=yes_no, default='no')
     90        parser.add_argument('--arch', help='Test for specific architecture', type=str, default='')
     91        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=60)
    13692        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
    137         parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
    13893        parser.add_argument('--dry-run', help='Don\'t run the tests, only output the commands', action='store_true')
    13994        parser.add_argument('--list', help='List all test available', action='store_true')
     
    14398        parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously', type=int)
    14499        parser.add_argument('--list-comp', help='List all valide arguments', action='store_true')
    145         parser.add_argument('--list-dist', help='List all tests for distribution', action='store_true')
    146100        parser.add_argument('-I','--include', help='Directory of test to include, can be used multiple time, All  if omitted', action='append')
    147101        parser.add_argument('-E','--exclude', help='Directory of test to exclude, can be used multiple time, None if omitted', action='append')
     
    156110
    157111        # script must have at least some tests to run or be listing
    158         listing    = options.list or options.list_comp or options.list_dist
     112        listing    = options.list or options.list_comp
    159113        all_tests  = options.all
    160114        some_tests = len(options.tests) > 0
     
    191145        test.prepare()
    192146
    193         # ----------
    194         # MAKE
    195         # ----------
    196147        # build, skipping to next test on error
    197148        with Timed() as comp_dur:
    198149                make_ret, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
    199150
    200         # ----------
    201         # RUN
    202         # ----------
     151        run_dur = None
    203152        # run everything in a temp directory to make sure core file are handled properly
    204         run_dur = None
    205153        with tempdir():
    206                 # if the make command succeeds continue otherwise skip to diff
     154                # if the make command succeds continue otherwise skip to diff
    207155                if success(make_ret):
    208156                        with Timed() as run_dur:
     
    218166                if success(retcode):
    219167                        if settings.generating :
    220                                 # if we are only generating the output we still need to check that the test actually exists
     168                                # if we are ounly generating the output we still need to check that the test actually exists
    221169                                if no_rule(out_file, test.target()) :
    222170                                        retcode = 1
     
    230178
    231179                else:
    232                         if os.stat(out_file).st_size < 1048576:
    233                                 with open (out_file, "r", encoding='latin-1') as myfile:  # use latin-1 so all chars mean something.
    234                                         error = myfile.read()
    235                         else:
    236                                 error = "Output log can't be read, file is bigger than 1MB, see {} for actual error\n".format(out_file)
     180                        with open (out_file, "r") as myfile:
     181                                error = myfile.read()
    237182
    238183                        ret, info = core_info(exe_file)
     
    269214        except KeyboardInterrupt:
    270215                return False, ""
    271         # except Exception as ex:
    272         #       print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
    273         #       sys.stderr.flush()
    274         #       return False, ""
     216        except Exception as ex:
     217                print("Unexpected error in worker thread: %s" % ex, file=sys.stderr)
     218                sys.stderr.flush()
     219                return False, ""
    275220
    276221
     
    280225        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    281226
    282         # create the executor for our jobs
    283         pool = multiprocessing.Pool(jobs)
     227        # since python prints stacks by default on a interrupt, redo the interrupt handling to be silent
     228        def worker_init():
     229                def sig_int(signal_num, frame):
     230                        pass
     231
     232                signal.signal(signal.SIGINT, sig_int)
     233
     234        # create the executor for our jobs and handle the signal properly
     235        pool = multiprocessing.Pool(jobs, worker_init)
    284236
    285237        failed = False
     238
     239        def stop(x, y):
     240                print("Tests interrupted by user", file=sys.stderr)
     241                sys.exit(1)
     242        signal.signal(signal.SIGINT, stop)
    286243
    287244        # for each test to run
     
    321278        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    322279
    323         return failed
     280        return 1 if failed else 0
    324281
    325282
     
    335292        settings.init( options )
    336293
    337         # --------------------------------------------------
    338         # list all the test for auto completion programs
    339         # not pretty, single line, with the command line options
    340         if options.list_comp :
    341                 # fetch the liest of all valid tests
    342                 tests = list_tests( None, None )
    343 
    344                 # print the possible options
    345                 print("-h --help --debug --dry-run --list --ast=new --ast=old --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout --timeout-with-gdb -j --jobs -I --include -E --exclude --continue ", end='')
    346                 print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
    347 
    348                 # done
    349                 sys.exit(0)
    350 
    351         # --------------------------------------------------
    352         # list all the test for auto completion programs
    353         if options.list_dist :
    354                 # fetch the liest of all valid tests
    355                 tests = list_tests( None, None )
    356 
    357                 for t in tests:
    358                         print(os.path.relpath(t.expect(), settings.SRCDIR), end=' ')
    359                         print(os.path.relpath(t.input() , settings.SRCDIR), end=' ')
    360                         code, out = make_recon(t.target())
    361 
    362                         if code != 0:
    363                                 print('ERROR: recond failed for test {}'.format(t.target()), file=sys.stderr)
    364                                 sys.exit(1)
    365 
    366                         print(' '.join(re.findall('([^\s]+\.cfa)', out)), end=' ')
    367 
    368                 print('')
    369 
    370                 # done
    371                 sys.exit(0)
    372 
    373 
    374         # --------------------------------------------------
    375         # list all the tests for users, in a pretty format
    376         if options.list :
    377                 # fetch the liest of all valid tests
    378                 tests = list_tests( options.include, options.exclude )
    379 
    380                 # print the available tests
    381                 fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    382 
    383                 # done
    384                 sys.exit(0)
    385 
    386294        # fetch the liest of all valid tests
    387295        all_tests = list_tests( options.include, options.exclude )
    388296
     297
    389298        # if user wants all tests than no other treatement of the test list is required
    390         if options.all or options.include :
     299        if options.all or options.list or options.list_comp or options.include :
    391300                tests = all_tests
    392301
     
    400309                sys.exit(1)
    401310
    402         # prep invariants
    403         settings.prep_output(tests)
    404         failed = 0
    405 
    406         # check if the expected files aren't empty
    407         if not options.regenerate_expected:
    408                 for t in tests:
    409                         if is_empty(t.expect()):
    410                                 print('WARNING: test "{}" has empty .expect file'.format(t.target()), file=sys.stderr)
    411 
    412         # for each build configurations, run the test
    413         with Timed() as total_dur:
    414                 for ast, arch, debug, install in itertools.product(settings.all_ast, settings.all_arch, settings.all_debug, settings.all_install):
    415                         settings.ast     = ast
    416                         settings.arch    = arch
    417                         settings.debug   = debug
    418                         settings.install = install
    419 
    420                         # filter out the tests for a different architecture
    421                         # tests are the same across debug/install
    422                         local_tests = settings.ast.filter( tests )
    423                         local_tests = settings.arch.filter( local_tests )
    424                         options.jobs, forceJobs = job_count( options, local_tests )
    425                         settings.update_make_cmd(forceJobs, options.jobs)
    426 
    427                         # check the build configuration works
    428                         settings.validate()
    429 
    430                         # print configuration
    431                         print('%s %i tests on %i cores (%s:%s - %s)' % (
    432                                 'Regenerating' if settings.generating else 'Running',
    433                                 len(local_tests),
    434                                 options.jobs,
    435                                 settings.ast.string,
    436                                 settings.arch.string,
    437                                 settings.debug.string
    438                         ))
    439                         if not local_tests :
    440                                 print('WARNING: No tests for this configuration')
    441                                 continue
    442 
    443                         # otherwise run all tests and make sure to return the correct error code
    444                         failed = run_tests(local_tests, options.jobs)
    445                         if failed:
    446                                 result = 1
    447                                 if not settings.continue_:
    448                                         break
    449 
    450         print('Tests took %s' % fmtDur( total_dur.duration ))
    451         sys.exit( failed )
     311
     312        # sort the test alphabetically for convenience
     313        tests.sort(key=lambda t: (t.arch if t.arch else '') + t.target())
     314
     315        # users may want to simply list the tests
     316        if options.list_comp :
     317                print("-h --help --debug --dry-run --list --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout -j --jobs ", end='')
     318                print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
     319
     320        elif options.list :
     321                print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
     322                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
     323
     324        else :
     325                # check the build configuration works
     326                settings.prep_output(tests)
     327                settings.validate()
     328
     329                options.jobs, forceJobs = job_count( options, tests )
     330                settings.update_make_cmd(forceJobs, options.jobs)
     331
     332                print('%s %i tests on %i cores (%s:%s)' % (
     333                        'Regenerating' if settings.generating else 'Running',
     334                        len(tests),
     335                        options.jobs,
     336                        settings.arch.string,
     337                        settings.debug.string
     338                ))
     339
     340                # otherwise run all tests and make sure to return the correct error code
     341                sys.exit( run_tests(tests, options.jobs) )
Note: See TracChangeset for help on using the changeset viewer.