sapling/tests/integration/integration_runner.py
Stanislau Hlebik f04a37cca2 mononoke: mononoke -> hg sync job
Summary:
First stab at a job that will keep hg in sync with Mononoke when Mononoke
becomes a source of truth.

Reviewed By: ikostia

Differential Revision: D14018269

fbshipit-source-id: f88c5eba8bf5482f2f162b7807ca8e41a3b4291d
2019-02-21 05:47:31 -08:00

199 lines
6.6 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 subprocess
import sys
import tempfile
import xml.etree.ElementTree as ET
import click
from libfb.py import parutil, pathutils
TESTDIR_PATH = "scm/mononoke/tests/integration"
MONONOKE_BLOBIMPORT_TARGET = "//scm/mononoke:blobimport"
MONONOKE_ADMIN_TARGET = "//scm/mononoke:admin"
MONONOKE_ALIAS_VERIFY_TARGET = "//scm/mononoke:aliasverify"
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"
BINARY_HGPYTHON_TARGET = "//scm/hg:hgpython"
MONONOKE_HGCLI_TARGET = "//scm/mononoke/hgcli:hgcli"
MONONOKE_SERVER_TARGET = "//scm/mononoke:mononoke"
FACEBOOK_HOOKS_TARGET = "//scm/mononoke/facebook/hooks:hooks"
PUSHREBASE_REPLAY_TARGET = "//scm/mononoke/facebook/pushrebase_replay:pushrebase_replay"
VERIFY_INTEGRITY_TARGET = "//security/source_control:verify_integrity"
MONONOKE_HG_SYNC_TARGET = (
"//scm/mononoke/facebook/mononoke_hg_sync_job:mononoke_hg_sync_job"
)
@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,
):
testdir = parutil.get_dir_path(TESTDIR_PATH)
run_tests_dir = os.path.join(
os.path.join(testdir, "third_party"), "hg_run_tests.py"
)
args = [
get_hg_python_binary(),
run_tests_dir,
"--maxdifflines=1000",
"--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_ALIAS_VERIFY", MONONOKE_ALIAS_VERIFY_TARGET)
add_to_environ("MONONOKE_ADMIN", MONONOKE_ADMIN_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)
add_to_environ(
"FACEBOOK_HOOKS", FACEBOOK_HOOKS_TARGET, pathutils.BuildRuleTypes.FILEGROUP
)
add_to_environ("MONONOKE_HG_SYNC", MONONOKE_HG_SYNC_TARGET)
add_to_environ(
"PUSHREBASE_REPLAY",
PUSHREBASE_REPLAY_TARGET,
pathutils.BuildRuleTypes.PYTHON_BINARY,
)
add_to_environ(
"VERIFY_INTEGRITY_TARGET",
VERIFY_INTEGRITY_TARGET,
pathutils.BuildRuleTypes.PYTHON_BINARY,
)
# 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)
# Also add to the system path because the Mercurial run-tests.py does an
# absolute import of killdaemons etc.
env = os.environ.copy()
env["HGPYTHONPATH"] = os.path.join(testdir, "third_party")
p = subprocess.Popen(args, env=env, stderr=sys.stderr, stdout=sys.stdout)
p.communicate("")
ret = p.returncode
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
)
def get_hg_python_binary():
return pathutils.get_build_rule_output_path(
BINARY_HGPYTHON_TARGET, pathutils.BuildRuleTypes.PYTHON_BINARY
)
if __name__ == "__main__":
run()