Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion tests/tools/private/release/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ load("//tests/support/pytest_test:pytest_test.bzl", "pytest_test")

py_library(
name = "release_test_helper",
srcs = ["release_test_helper.py"],
srcs = [
"conftest.py",
"release_test_helper.py",
],
target_compatible_with = SUPPORTS_BZLMOD,
deps = [
"//tools/private/release:mock_gh",
Expand Down
22 changes: 22 additions & 0 deletions tests/tools/private/release/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest

pytest_plugins = ["tests.tools.private.release.release_test_helper"]


@pytest.fixture(name="auto_patch_cmd_helpers", autouse=True)
def fixture_auto_patch_cmd_helpers(mocker):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional Nit: More idiomatic pytest would be to have a single fixture for each item, and then a 4th fixture to collect them all.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be out of scope, but why use pytest_mock over just plain-ol unittest.mock API? Or pytest's built in monkeypatch API?

"""Automatically patches run_cmd, Git, and GitHub CLI helpers.

This prevents tests from executing command line tools that could have
side-effects.
"""
mock_run_cmd = mocker.patch("tools.private.release.shell.run_cmd")
mocker.patch("tools.private.release.git.run_cmd", mock_run_cmd)
mocker.patch("tools.private.release.gh.run_cmd", mock_run_cmd)
mock_run_git = mocker.patch("tools.private.release.git.Git._run_git")
mock_run_gh = mocker.patch("tools.private.release.gh.GitHub._run_gh")
return {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend returning a dataclass instead of dict - helps with type checking (do we do type checking in this project? 🤣 )

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a mypy test for the runfiles but not more, I think.

"run_cmd": mock_run_cmd,
"run_git": mock_run_git,
"run_gh": mock_run_gh,
}
Comment thread
rickeylev marked this conversation as resolved.
20 changes: 20 additions & 0 deletions tests/tools/private/release/gh_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,23 @@ def test_resolve_pr_number_invalid(mocker, gh):
with pytest.raises(ValueError, match="Could not resolve PR reference"):
gh.resolve_pr_number("invalid-ref")
mock_run_cmd.assert_not_called()


def test_auto_patched_helpers_prevent_real_execution(auto_patch_cmd_helpers):
from tools.private.release.gh import GitHub
from tools.private.release.git import Git
from tools.private.release.shell import run_cmd

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gh_test target needs to be updated to include these as deps, no?


# Calling run_cmd directly hits the mock
run_cmd("echo", "test")
auto_patch_cmd_helpers["run_cmd"].assert_called_with("echo", "test")

# Git._run_git hits the mock
git = Git(".")
git._run_git("status")
auto_patch_cmd_helpers["run_git"].assert_called_with("status")

# GitHub._run_gh hits the mock
gh_obj = GitHub("foo/bar")
gh_obj._run_gh("issue", "list")
auto_patch_cmd_helpers["run_gh"].assert_called_with("issue", "list")
Comment thread
rickeylev marked this conversation as resolved.