blob: cab9730bb88c3c26283ee3ede0cad38ff11f6b57 [file]
import logging
import os
import os.path
import pathlib
import re
import shlex
import subprocess
import unittest
_logger = logging.getLogger(__name__)
class ExecuteError(Exception):
def __init__(self, result):
self.result = result
def __str__(self):
return self.result.describe()
class ExecuteResult:
def __init__(
self,
args: list[str],
env: dict[str, str],
cwd: pathlib.Path,
proc_result: subprocess.CompletedProcess,
):
self.args = args
self.env = env
self.cwd = cwd
self.exit_code = proc_result.returncode
self.stdout = proc_result.stdout
self.stderr = proc_result.stderr
def describe(self) -> str:
env_lines = [
" " + shlex.quote(f"{key}={value}")
for key, value in sorted(self.env.items())
]
env = " \\\n".join(env_lines)
args = shlex.join(self.args)
maybe_stdout_nl = "" if self.stdout.endswith("\n") else "\n"
maybe_stderr_nl = "" if self.stderr.endswith("\n") else "\n"
return f"""\
COMMAND:
cd {self.cwd} && \\
env \\
{env} \\
{args}
RESULT: exit_code: {self.exit_code}
===== STDOUT START =====
{self.stdout}{maybe_stdout_nl}===== STDOUT END =====
===== STDERR START =====
{self.stderr}{maybe_stderr_nl}===== STDERR END =====
"""
class TestCase(unittest.TestCase):
def setUp(self):
super().setUp()
self.repo_root = pathlib.Path(os.environ["BIT_WORKSPACE_DIR"])
self.bazel = pathlib.Path(os.environ["BIT_BAZEL_BINARY"])
outer_test_tmpdir = pathlib.Path(os.environ["TEST_TMPDIR"])
self.test_tmp_dir = outer_test_tmpdir / "bit_test_tmp"
self.tmp_dir = outer_test_tmpdir / "bit_tmp"
self.bazel_env = {
"PATH": os.environ["PATH"],
"TEST_TMPDIR": str(self.test_tmp_dir),
"TMP": str(self.tmp_dir),
"RUNFILES_DIR": os.environ["TEST_SRCDIR"],
}
def run_bazel(self, *args: str, check: bool = True) -> ExecuteResult:
args = [str(self.bazel), *args]
env = self.bazel_env
_logger.info("executing: %s", shlex.join(args))
cwd = self.repo_root
proc_result = subprocess.run(
args=args,
text=True,
capture_output=True,
cwd=cwd,
env=env,
check=False,
)
exec_result = ExecuteResult(args, env, cwd, proc_result)
if check and exec_result.exit_code:
raise ExecuteError(exec_result)
else:
return exec_result
def assert_result_matches(self, result: ExecuteResult, regex: str) -> None:
if not re.search(regex, result.stdout + result.stderr):
self.fail(
"Bazel output did not match expected pattern\n"
+ f"expected pattern: {regex}\n"
+ f"invocation details:\n{result.describe()}"
)