| #!/usr/bin/env python3.8 | |
| # Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| #### CATEGORY=Other | |
| import argparse | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| import textwrap | |
| # Colors and helpers for terminal pretty-printing. | |
| BOLD_BLACK = '\033[1;30m' | |
| BOLD_RED = '\033[1;31m' | |
| NO_COLOR = '\033[0m' | |
| def info_print(s): | |
| print('\n%s%s%s' % (BOLD_BLACK, s, NO_COLOR)) | |
| def error_print(s): | |
| print('\n%s%s%s' % (BOLD_RED, s, NO_COLOR)) | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description=(textwrap.dedent('''\ | |
| Executes a test in the GN graph. | |
| Note that the name of the test is just the name of a binary in the | |
| output folder. | |
| For example, if you have this binary: | |
| out/default/host_x64/my_test | |
| You just specify "my_test" as the test name. | |
| Also note that the binary need to be part of your GN build graph, | |
| even if you are not interested in delivering this binary as part of | |
| the image. This means that, if your test is generated by the | |
| //system/src/my_package/my_test | |
| target, you might need to add this target to your GN build graph by | |
| adjusting your "fx set" arguments like this: | |
| fx set ... --with //system/src/my_package/my_test | |
| ''')), | |
| formatter_class=argparse.RawDescriptionHelpFormatter, | |
| ) | |
| parser.add_argument('--manifest', | |
| help='The path to the manifest of tests', | |
| required=True) | |
| parser.add_argument('--names', | |
| help='The names of the tests to execute', | |
| nargs='*', | |
| required=True) | |
| parser.add_argument('test_args', | |
| help='Arguments to pass to the tests on execution', | |
| nargs='*') | |
| parser.add_argument('--build-dir', | |
| help='The path to the root build directory', | |
| required=True) | |
| parser.add_argument('--ninja', | |
| help='The path to the ninja binary', | |
| required=True) | |
| args = parser.parse_args() | |
| if not args.names: | |
| error_print('no tests provided') | |
| return 1 | |
| with open(args.manifest, 'r') as f: | |
| entries = json.load(f) | |
| tests = [] | |
| unmatched = set(args.names) | |
| for entry in entries: | |
| test = entry['test'] | |
| if test['os'] == 'fuchsia': | |
| continue | |
| # some tests have no "path" property | |
| if 'path' not in test: | |
| continue | |
| path = test['path'] | |
| name = os.path.basename(path) | |
| if name not in args.names: | |
| continue | |
| tests.append(test) | |
| unmatched.remove(name) | |
| if unmatched: | |
| error_print( | |
| 'could not find tests with the following names:\n' + | |
| '\n'.join(unmatched)) | |
| return 1 | |
| # test['path'] gives the path to the test relative build directory, | |
| # which is a valid ninja target. | |
| ret = subprocess.call( | |
| [args.ninja, '-C', args.build_dir] + | |
| [test['path'] for test in tests]) | |
| if ret: | |
| error_print('failed to compile tests') | |
| return 1 | |
| failed = [] | |
| for test in tests: | |
| target = test['name'] | |
| info_print('<< running %s >>' % target) | |
| if 'command' in test and len(test['command']) > 1: | |
| location, extra_args = test['command'][0], test['command'][1:] | |
| else: | |
| location, extra_args = test['path'], [] | |
| ret = subprocess.call( | |
| [os.path.join(args.build_dir, location)] + extra_args + args.test_args) | |
| if ret != 0: | |
| failed.append(target) | |
| num_tests = len(tests) | |
| if not num_tests: | |
| error_print('no tests found with names %s' % ', '.join(args.names)) | |
| return 1 | |
| if failed: | |
| error_print( | |
| '%d of %d test%s failed:' % ( | |
| len(failed), num_tests, 's' if num_tests > 1 else '' | |
| ) + | |
| '\n'.join(failed)) | |
| return 1 | |
| else: | |
| info_print('%d of %d test%s passed' % ( | |
| num_tests, num_tests, 's' if num_tests > 1 else '')) | |
| if __name__ == '__main__': | |
| sys.exit(main()) |