-
Notifications
You must be signed in to change notification settings - Fork 563
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: add integration test for build_python_zip (#2045)
This is a more comprehensive regression test for verifying `--build_python_zip` is actually working (#1840) This also creates a small framework to make it easier to write integration tests that need to customize the environment bazel runs in and check the output of bazel itself. I figure this will be helpful for writing simple verification tests for repository/bzlmod phase logic (i.e. set the debug env vars and grep the output). While we should avoid heavy usage of these bazel-in-bazel tests, a bit of grepping logs would go a long way for covering edge cases that examples don't cover.
- Loading branch information
Showing
10 changed files
with
263 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
load("@rules_python//python:py_binary.bzl", "py_binary") | ||
|
||
py_binary( | ||
name = "bin", | ||
srcs = ["bin.py"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
module(name = "module_under_test") | ||
|
||
bazel_dep(name = "rules_python", version = "0.0.0") | ||
local_path_override( | ||
module_name = "rules_python", | ||
path = "../../..", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
local_repository( | ||
name = "rules_python", | ||
path = "../../..", | ||
) | ||
|
||
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") | ||
|
||
py_repositories() | ||
|
||
python_register_toolchains( | ||
name = "python_3_11", | ||
python_version = "3.11", | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
print("Hello, world") | ||
print(__file__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import logging | ||
import unittest | ||
|
||
from tests.integration import runner | ||
|
||
|
||
class CustomCommandsTest(runner.TestCase): | ||
# Regression test for https://github.com/bazelbuild/rules_python/issues/1840 | ||
def test_run_build_python_zip_false(self): | ||
result = self.run_bazel("run", "--build_python_zip=false", "//:bin") | ||
self.assert_result_matches(result, "bazel-out") | ||
|
||
|
||
if __name__ == "__main__": | ||
# Enabling this makes the runner log subprocesses as the test goes along. | ||
# logging.basicConfig(level = "INFO") | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
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" | ||
# Put the global tmp not under the test tmp to better match how a real | ||
# execution has entirely different directories for these. | ||
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), | ||
# For some reason, this is necessary for Bazel 6.4 to work. | ||
# If not present, it can't find some bash helpers in @bazel_tools | ||
"RUNFILES_DIR": os.environ["TEST_SRCDIR"] | ||
} | ||
|
||
def run_bazel(self, *args: str, check: bool = True) -> ExecuteResult: | ||
"""Run a bazel invocation. | ||
Args: | ||
*args: The args to pass to bazel; the leading `bazel` command is | ||
added automatically | ||
check: True if the execution must succeed, False if failure | ||
should raise an error. | ||
Returns: | ||
An `ExecuteResult` from running Bazel | ||
""" | ||
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: | ||
"""Assert stdout/stderr of an invocation matches a regex. | ||
Args: | ||
result: ExecuteResult from `run_bazel` whose stdout/stderr will | ||
be checked. | ||
regex: Pattern to match, using `re.search` semantics. | ||
""" | ||
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()}" | ||
) |