mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 17:27:53 +03:00
2b4c0f14a1
Summary: ugh, yet another case of a hidden dependency. Reviewed By: StanislavGlebik Differential Revision: D9318498 fbshipit-source-id: 5fcd25081b5033cbef9c5f137e616348c5d6ced9
170 lines
5.3 KiB
Python
170 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) 2004-present, Facebook, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
"""Runner for Mononoke/Mercurial integration tests."""
|
|
|
|
import contextlib
|
|
import multiprocessing
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import xml.etree.ElementTree as ET
|
|
|
|
import click
|
|
|
|
from libfb.py import parutil, pathutils
|
|
|
|
from .third_party import hg_run_tests
|
|
|
|
TESTDIR_PATH = 'scm/mononoke/tests/integration'
|
|
|
|
MONONOKE_BLOBIMPORT_TARGET = '//scm/mononoke:blobimport'
|
|
MONONOKE_BONSAI_VERIFY_TARGET = '//scm/mononoke:bonsai_verify'
|
|
MONONOKE_APISERVER_TARGET = '//scm/mononoke/apiserver:apiserver'
|
|
DUMMYSSH_TARGET = '//scm/mononoke/tests/integration:dummyssh'
|
|
BINARY_HG_TARGET = '//scm/hg:hg'
|
|
MONONOKE_HGCLI_TARGET = '//scm/mononoke/hgcli:hgcli'
|
|
MONONOKE_SERVER_TARGET = '//scm/mononoke:mononoke'
|
|
|
|
|
|
@click.command()
|
|
@click.option('--dry-run', default=False, is_flag=True, help='list tests')
|
|
@click.option(
|
|
'--interactive',
|
|
default=False,
|
|
is_flag=True,
|
|
help='prompt to accept changed output'
|
|
)
|
|
@click.option('--output', default='', help='output directory')
|
|
@click.option(
|
|
'--verbose', default=False, is_flag=True, help='output verbose messages'
|
|
)
|
|
@click.option(
|
|
'--debug',
|
|
default=False,
|
|
is_flag=True,
|
|
help='debug mode: write output of test scripts to console rather than '
|
|
'capturing and diffing it (disables timeout)'
|
|
)
|
|
@click.option(
|
|
'--keep-tmpdir',
|
|
default=False,
|
|
is_flag=True,
|
|
help='keep temporary directory after running tests'
|
|
)
|
|
@click.option(
|
|
'--simple-test-selector',
|
|
default=None,
|
|
help='select an individual test to run',
|
|
)
|
|
@click.argument(
|
|
'tests',
|
|
nargs=-1,
|
|
type=click.Path(),
|
|
)
|
|
@click.pass_context
|
|
def run(
|
|
ctx, tests, dry_run, interactive, output, verbose, debug,
|
|
simple_test_selector, keep_tmpdir
|
|
):
|
|
runner = hg_run_tests.TestRunner()
|
|
|
|
testdir = parutil.get_dir_path(TESTDIR_PATH)
|
|
# Also add to the system path because the Mercurial run-tests.py does an
|
|
# absolute import of killdaemons etc.
|
|
sys.path.insert(0, os.path.join(testdir, 'third_party'))
|
|
|
|
# Use hg.real to avoid going through the wrapper and incurring slowdown
|
|
# from subprocesses.
|
|
# XXX is this the right thing to do?
|
|
args = ['--with-hg', get_hg_binary()]
|
|
if dry_run:
|
|
args.append('--list-tests')
|
|
if interactive:
|
|
args.append('-i')
|
|
if verbose:
|
|
args.append('--verbose')
|
|
if debug:
|
|
args.append('--debug')
|
|
if keep_tmpdir:
|
|
args.append('--keep-tmpdir')
|
|
args.extend(['-j', '%d' % multiprocessing.cpu_count()])
|
|
if simple_test_selector is not None:
|
|
suite, test = simple_test_selector.split(',', 1)
|
|
if suite != 'run-tests':
|
|
raise click.BadParameter(
|
|
'suite should always be "run-tests"', ctx,
|
|
param_hint='simple_test_selector'
|
|
)
|
|
args.append(test)
|
|
if tests:
|
|
args.extend(tests)
|
|
|
|
# In --dry-run mode, the xunit output has to be written to stdout.
|
|
# In regular (run-tests) mode, the output has to be written to the specified
|
|
# output directory.
|
|
if output == '':
|
|
output = None
|
|
_fp, xunit_output = tempfile.mkstemp(dir=output)
|
|
|
|
add_to_environ('MONONOKE_BLOBIMPORT', MONONOKE_BLOBIMPORT_TARGET)
|
|
add_to_environ('MONONOKE_BONSAI_VERIFY', MONONOKE_BONSAI_VERIFY_TARGET)
|
|
add_to_environ(
|
|
'DUMMYSSH', DUMMYSSH_TARGET, pathutils.BuildRuleTypes.PYTHON_BINARY
|
|
)
|
|
add_to_environ('MONONOKE_APISERVER', MONONOKE_APISERVER_TARGET)
|
|
add_to_environ('MONONOKE_HGCLI', MONONOKE_HGCLI_TARGET)
|
|
add_to_environ('MONONOKE_SERVER', MONONOKE_SERVER_TARGET)
|
|
|
|
# Provide an output directory so that we don't write to a xar's read-only
|
|
# filesystem.
|
|
output_dir = tempfile.mkdtemp()
|
|
try:
|
|
args.extend(['--xunit', xunit_output, '--outputdir', output_dir])
|
|
with contextlib.redirect_stdout(sys.stderr):
|
|
# Do this here to influence as little code as possible -- in
|
|
# particular, add_to_environ depends on getcwd always being inside
|
|
# fbcode
|
|
os.chdir(testdir)
|
|
ret = runner.run(args)
|
|
|
|
if dry_run:
|
|
# The output must go to stdout. Set simple_test_selector to make
|
|
# execution runs simpler.
|
|
with open(xunit_output, 'rb') as f:
|
|
xunit_xml = ET.parse(f)
|
|
xunit_xml.getroot().set(
|
|
'runner_capabilities', 'simple_test_selector'
|
|
)
|
|
xunit_xml.write(sys.stdout.buffer, xml_declaration=True)
|
|
|
|
ctx.exit(ret)
|
|
finally:
|
|
try:
|
|
# If an output was specified, xunit_output is owned by the caller
|
|
# and is the caller's responsibility to clean up.
|
|
if output is None:
|
|
os.unlink(xunit_output)
|
|
except OSError:
|
|
pass
|
|
shutil.rmtree(output_dir, ignore_errors=True)
|
|
|
|
|
|
def add_to_environ(var, target, rule_type=pathutils.BuildRuleTypes.RUST_BINARY):
|
|
os.environ[var] = pathutils.get_build_rule_output_path(target, rule_type)
|
|
|
|
|
|
def get_hg_binary():
|
|
return pathutils.get_build_rule_output_path(
|
|
BINARY_HG_TARGET, pathutils.BuildRuleTypes.PYTHON_BINARY
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
run()
|