Skip to content

Commit d1c1309

Browse files
committed
Add subcommmands to the test runner
1 parent 4bcfd92 commit d1c1309

File tree

2 files changed

+117
-75
lines changed

2 files changed

+117
-75
lines changed

graalpython/com.oracle.graal.python.test/src/runner.py

Lines changed: 114 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -688,8 +688,6 @@ def run_in_subprocess_and_watch(self):
688688
use_pipe = sys.platform != 'win32' and (not IS_GRAALPY or __graalpython__.posix_module_backend() == 'native')
689689
with tempfile.TemporaryDirectory(prefix='graalpytest-') as tmp_dir:
690690
tmp_dir = Path(tmp_dir)
691-
env = os.environ.copy()
692-
env['IN_PROCESS'] = '1'
693691

694692
if use_pipe:
695693
pipe, child_pipe = multiprocessing.Pipe()
@@ -709,6 +707,7 @@ def run_in_subprocess_and_watch(self):
709707
'-u',
710708
*self.runner.subprocess_args,
711709
__file__,
710+
'worker',
712711
'--tests-file', str(tests_file.name),
713712
]
714713
if use_pipe:
@@ -725,7 +724,6 @@ def run_in_subprocess_and_watch(self):
725724
popen_kwargs: dict = dict(
726725
stdout=self.out_file,
727726
stderr=self.out_file,
728-
env=env,
729727
)
730728
if use_pipe:
731729
popen_kwargs.update(pass_fds=[child_pipe.fileno()])
@@ -1143,14 +1141,7 @@ def loadTestsFromModule(self, module, *, pattern=None):
11431141
return test_suite
11441142

11451143

1146-
def in_process():
1147-
parser = argparse.ArgumentParser()
1148-
group = parser.add_mutually_exclusive_group()
1149-
group.add_argument('--pipe-fd', type=int)
1150-
group.add_argument('--result-file', type=Path)
1151-
parser.add_argument('--tests-file', type=Path, required=True)
1152-
parser.add_argument('--failfast', action='store_true')
1153-
args = parser.parse_args()
1144+
def main_worker(args):
11541145
tests = []
11551146
with open(args.tests_file) as f:
11561147
for line in f:
@@ -1184,73 +1175,127 @@ def get_bool_env(name: str):
11841175

11851176
def main():
11861177
is_mx_graalpytest = get_bool_env('MX_GRAALPYTEST')
1187-
parser = argparse.ArgumentParser(
1188-
prog=('mx graalpytest' if is_mx_graalpytest else None),
1189-
formatter_class=argparse.RawTextHelpFormatter,
1190-
)
1178+
parent_parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
1179+
subparsers = parent_parser.add_subparsers()
1180+
1181+
# run command declaration
1182+
run_parser = subparsers.add_parser('run', prog=('mx graalpytest' if is_mx_graalpytest else None))
1183+
run_parser.set_defaults(main=main_run)
11911184
if is_mx_graalpytest:
11921185
# mx graalpytest takes this option, but it forwards --help here, so pretend we take it
1193-
parser.add_argument('--python', help="Run tests with given Python binary")
1194-
parser.add_argument('--svm', action='store_true', help="Use SVM standalone")
1195-
parser.add_argument('-t', '--tagged', action='store_true',
1196-
help="Interpret test file names relative to tagged test directory")
1197-
parser.add_argument('-n', '--num-processes', type=int,
1198-
help="Run tests in N subprocess workers. Adds crash recovery, output capture and timeout handling")
1199-
parser.add_argument('--separate-workers', action='store_true',
1200-
help="Create a new worker process for each test file (when -n is specified). Default for tagged unit tests")
1201-
parser.add_argument('--ignore', type=Path, action='append', default=[],
1202-
help="Ignore path during collection (multi-allowed)")
1203-
parser.add_argument('--no-excludes', action='store_true',
1204-
help="Don't apply configuration exclusions")
1205-
parser.add_argument('-f', '--failfast', action='store_true',
1206-
help="Exit immediately after the first failure")
1207-
parser.add_argument('--all', action='store_true',
1208-
help="Run tests that are normally not enabled due to tags. Implies --tagged")
1209-
parser.add_argument('--retag', dest='retag_mode', action='store_const', const='replace',
1210-
help="Run tests and regenerate tags based on the results. Implies --all, --tagged and -n")
1211-
parser.add_argument('--retag-append', dest='retag_mode', action='store_const', const='append',
1212-
help="Like --retag, but doesn't remove existing tags. Useful for regtagging subsets of tests")
1213-
parser.add_argument('--collect-only', action='store_true',
1214-
help="Print found tests IDs without running tests")
1215-
parser.add_argument('--continue-on-collection-errors', action='store_true',
1216-
help="Collection errors are not fatal")
1217-
parser.add_argument('--durations', type=int, default=0,
1218-
help="Show durations of N slowest tests (-1 to show all)")
1219-
parser.add_argument('--mx-report',
1220-
help="Produce a json report file in format expected by mx_gate.make_test_report")
1221-
parser.add_argument('--untag-unmatched', action='store_true',
1222-
help="Remove tests that were not collected from tags. Useful for pruning removed tests")
1223-
parser.add_argument('--timeout-factor', type=float, default=1.0,
1224-
help="Multiply all timeouts by this number")
1225-
parser.add_argument('--exit-success-on-failures', action='store_true',
1226-
help=dedent("""\
1227-
Exit successfully regardless of the test results. Useful to distinguish test failures
1228-
from runner crashes in jobs like retagger or coverage where failures are expected.
1229-
"""))
1230-
parser.add_argument(
1186+
run_parser.add_argument('--python', help="Run tests with given Python binary")
1187+
run_parser.add_argument('--svm', action='store_true', help="Use SVM standalone")
1188+
run_parser.add_argument(
1189+
'-t', '--tagged', action='store_true',
1190+
help="Interpret test file names relative to tagged test directory",
1191+
)
1192+
run_parser.add_argument(
1193+
'-n', '--num-processes', type=int,
1194+
help="Run tests in N subprocess workers. Adds crash recovery, output capture and timeout handling",
1195+
)
1196+
run_parser.add_argument(
1197+
'--separate-workers', action='store_true',
1198+
help="Create a new worker process for each test file (when -n is specified). Default for tagged unit tests",
1199+
)
1200+
run_parser.add_argument(
1201+
'--ignore', type=Path, action='append', default=[],
1202+
help="Ignore path during collection (multi-allowed)",
1203+
)
1204+
run_parser.add_argument(
1205+
'--no-excludes', action='store_true',
1206+
help="Don't apply configuration exclusions",
1207+
)
1208+
run_parser.add_argument(
1209+
'-f', '--failfast', action='store_true',
1210+
help="Exit immediately after the first failure",
1211+
)
1212+
run_parser.add_argument(
1213+
'--all', action='store_true',
1214+
help="Run tests that are normally not enabled due to tags. Implies --tagged",
1215+
)
1216+
run_parser.add_argument(
1217+
'--retag', dest='retag_mode', action='store_const', const='replace',
1218+
help="Run tests and regenerate tags based on the results. Implies --all, --tagged and -n",
1219+
)
1220+
run_parser.add_argument(
1221+
'--retag-append', dest='retag_mode', action='store_const', const='append',
1222+
help="Like --retag, but doesn't remove existing tags. Useful for regtagging subsets of tests",
1223+
)
1224+
run_parser.add_argument(
1225+
'--collect-only', action='store_true',
1226+
help="Print found tests IDs without running tests",
1227+
)
1228+
run_parser.add_argument(
1229+
'--continue-on-collection-errors', action='store_true',
1230+
help="Collection errors are not fatal",
1231+
)
1232+
run_parser.add_argument(
1233+
'--durations', type=int, default=0,
1234+
help="Show durations of N slowest tests (-1 to show all)",
1235+
)
1236+
run_parser.add_argument(
1237+
'--mx-report',
1238+
help="Produce a json report file in format expected by mx_gate.make_test_report",
1239+
)
1240+
run_parser.add_argument(
1241+
'--untag-unmatched', action='store_true',
1242+
help="Remove tests that were not collected from tags. Useful for pruning removed tests",
1243+
)
1244+
run_parser.add_argument(
1245+
'--timeout-factor', type=float, default=1.0,
1246+
help="Multiply all timeouts by this number",
1247+
)
1248+
run_parser.add_argument(
1249+
'--exit-success-on-failures', action='store_true',
1250+
help=dedent(
1251+
"""\
1252+
Exit successfully regardless of the test results. Useful to distinguish test failures
1253+
from runner crashes in jobs like retagger or coverage where failures are expected.
1254+
"""
1255+
),
1256+
)
1257+
run_parser.add_argument(
12311258
'--subprocess-args',
12321259
type=shlex.split,
12331260
default=[
12341261
"--vm.ea",
12351262
"--experimental-options=true",
12361263
"--python.EnableDebuggingBuiltins",
12371264
] if IS_GRAALPY else [],
1238-
help="Interpreter arguments to pass for subprocess invocation (when using -n)")
1239-
parser.add_argument('tests', nargs='+', type=TestSpecifier.from_str,
1240-
help=dedent("""\
1241-
List of test specifiers. A specifier can be:
1242-
- A test file name. It will be looked up in our unittests or, if you pass --tagged, in tagged tests. Example: test_int
1243-
- A test file path. Example: graalpython/lib-python/3/test/test_int.py. Note you do not need to pass --tagged to refer to a tagged test by path
1244-
- A test directory name or path. Example: cpyext
1245-
- A test file name/path with a selector for a specific test. Example: test_int::tests.test_int.ToBytesTests.test_WrongTypes
1246-
- A test file name/path with a selector for multiple tests. Example: test_int::tests.test_int.ToBytesTests
1247-
- You can use wildcards in tests paths and selectors. Example: 'test_int::test_create*'
1248-
1249-
Tip: the test IDs printed in test results directly work as specifiers here.
1250-
"""))
1251-
1252-
args = parser.parse_args()
1265+
help="Interpreter arguments to pass for subprocess invocation (when using -n)",
1266+
)
1267+
run_parser.add_argument(
1268+
'tests', nargs='+', type=TestSpecifier.from_str,
1269+
help=dedent(
1270+
"""\
1271+
List of test specifiers. A specifier can be:
1272+
- A test file name. It will be looked up in our unittests or, if you pass --tagged, in tagged tests. Example: test_int
1273+
- A test file path. Example: graalpython/lib-python/3/test/test_int.py. Note you do not need to pass --tagged to refer to a tagged test by path
1274+
- A test directory name or path. Example: cpyext
1275+
- A test file name/path with a selector for a specific test. Example: test_int::tests.test_int.ToBytesTests.test_WrongTypes
1276+
- A test file name/path with a selector for multiple tests. Example: test_int::tests.test_int.ToBytesTests
1277+
- You can use wildcards in tests paths and selectors. Example: 'test_int::test_create*'
1278+
1279+
Tip: the test IDs printed in test results directly work as specifiers here.
1280+
"""
1281+
),
1282+
)
1283+
1284+
# worker command declaration
1285+
worker_parser = subparsers.add_parser('worker')
1286+
worker_parser.set_defaults(main=main_worker)
1287+
group = worker_parser.add_mutually_exclusive_group()
1288+
group.add_argument('--pipe-fd', type=int)
1289+
group.add_argument('--result-file', type=Path)
1290+
worker_parser.add_argument('--tests-file', type=Path, required=True)
1291+
worker_parser.add_argument('--failfast', action='store_true')
12531292

1293+
# run the appropriate command
1294+
args = parent_parser.parse_args()
1295+
args.main(args)
1296+
1297+
1298+
def main_run(args):
12541299
if args.retag_mode:
12551300
args.all = True
12561301
args.tagged = True
@@ -1345,7 +1390,4 @@ def main():
13451390

13461391

13471392
if __name__ == '__main__':
1348-
if os.environ.get('IN_PROCESS') == '1':
1349-
in_process()
1350-
else:
1351-
main()
1393+
main()

mx.graalpython/mx_graalpython.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ def graalpytest(args):
10671067
mx.log(f"Executable seems to be GraalPy, prepending arguments: {gp_args}")
10681068
python_args += gp_args
10691069
runner_args.append(f'--subprocess-args={shlex.join(python_args)}')
1070-
cmd_args = [*python_args, _python_test_runner(), *runner_args]
1070+
cmd_args = [*python_args, _python_test_runner(), 'run', *runner_args]
10711071
delete_bad_env_keys(env)
10721072
if is_graalpy:
10731073
pythonpath = [os.path.join(_dev_pythonhome(), 'lib-python', '3')]
@@ -1145,7 +1145,7 @@ def run_python_unittests(python_binary, args=None, paths=None, exclude=None, env
11451145
if use_pytest:
11461146
args += ["-m", "pytest", "-v", "--assert=plain", "--tb=native"]
11471147
else:
1148-
args += [_python_test_runner(), "--durations", "10", "-n", str(min(os.cpu_count(), parallel)), f"--subprocess-args={shlex.join(args)}"]
1148+
args += [_python_test_runner(), "run", "--durations", "10", "-n", str(min(os.cpu_count(), parallel)), f"--subprocess-args={shlex.join(args)}"]
11491149

11501150
if runner_args:
11511151
args += runner_args
@@ -1388,7 +1388,7 @@ def graalpython_gate_runner(args, tasks):
13881388
with Task('GraalPython Python unittests with CPython', tasks, tags=[GraalPythonTags.unittest_cpython]) as task:
13891389
if task:
13901390
env = extend_os_env(PYTHONHASHSEED='0')
1391-
test_args = [get_cpython(), _python_test_runner(), "-n", "6", "graalpython/com.oracle.graal.python.test/src/tests"]
1391+
test_args = [get_cpython(), _python_test_runner(), "run", "-n", "6", "graalpython/com.oracle.graal.python.test/src/tests"]
13921392
mx.run(test_args, nonZeroIsFatal=True, env=env)
13931393

13941394
with Task('GraalPython sandboxed tests', tasks, tags=[GraalPythonTags.unittest_sandboxed]) as task:

0 commit comments

Comments
 (0)