Complete test coverage
This commit is contained in:
parent
0b4da7c5cf
commit
f46348d7a0
|
@ -40,6 +40,8 @@ class CheckResult:
|
|||
return self.severity
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
if not isinstance(other, self.__class__):
|
||||
return False
|
||||
return (self.kind, self.reason, self.check, self.origin) == (
|
||||
other.kind,
|
||||
other.reason,
|
||||
|
|
|
@ -442,12 +442,11 @@ class Operator:
|
|||
)
|
||||
if update_strategy == "semver-mode":
|
||||
return {x: {y} for x, y in zip(all_bundles, all_bundles[1:])}
|
||||
if update_strategy == "semver-skippatch":
|
||||
# TODO: implement semver-skippatch
|
||||
raise NotImplementedError("%s: semver-skippatch is not implemented yet")
|
||||
if update_strategy == "replaces-mode":
|
||||
return self._replaces_graph(channel, all_bundles)
|
||||
raise ValueError(f"{self}: unknown updateGraph value: {update_strategy}")
|
||||
raise NotImplementedError(
|
||||
f"{self}: unsupported updateGraph value: {update_strategy}"
|
||||
)
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
if not isinstance(other, self.__class__):
|
||||
|
|
|
@ -83,26 +83,21 @@ def action_list(repo: Repo, *what: str, recursive: bool = False) -> None:
|
|||
show(target, recursive)
|
||||
|
||||
|
||||
def _walk(
|
||||
target: Union[Repo, Operator, Bundle]
|
||||
) -> Iterator[Union[Repo, Operator, Bundle]]:
|
||||
def _walk(target: Union[Operator, Bundle]) -> Iterator[Union[Operator, Bundle]]:
|
||||
yield target
|
||||
if isinstance(target, Repo):
|
||||
for operator in target:
|
||||
yield from _walk(operator)
|
||||
elif isinstance(target, Operator):
|
||||
if isinstance(target, Operator):
|
||||
yield from target.all_bundles()
|
||||
|
||||
|
||||
def action_check(repo: Repo, suite: str, *what: str, recursive: bool = False) -> None:
|
||||
if what:
|
||||
targets: Iterator[Union[Repo, Operator, Bundle]] = (
|
||||
targets: Iterator[Union[Operator, Bundle]] = (
|
||||
parse_target(repo, x) for x in what
|
||||
)
|
||||
else:
|
||||
targets = repo.all_operators()
|
||||
if recursive:
|
||||
all_targets: Iterator[Union[Repo, Operator, Bundle]] = chain.from_iterable(
|
||||
all_targets: Iterator[Union[Operator, Bundle]] = chain.from_iterable(
|
||||
_walk(x) for x in targets
|
||||
)
|
||||
else:
|
||||
|
@ -119,7 +114,7 @@ def action_check_list(suite: str) -> None:
|
|||
print(f" - {display_name}: {check.__doc__}")
|
||||
|
||||
|
||||
def _get_repo(path: Optional[Path]) -> Repo:
|
||||
def _get_repo(path: Optional[Path] = None) -> Repo:
|
||||
if not path:
|
||||
path = Path.cwd()
|
||||
try:
|
||||
|
@ -201,5 +196,5 @@ def main() -> None:
|
|||
main_parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
|
|
|
@ -15,3 +15,20 @@ def mock_bundle(tmp_path: Path) -> Bundle:
|
|||
create_files(tmp_path, bundle_files("hello", "0.0.1"))
|
||||
repo = Repo(tmp_path)
|
||||
return repo.operator("hello").bundle("0.0.1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_repo(tmp_path: Path) -> Repo:
|
||||
"""
|
||||
Create a dummy file structure for an operator repo with two operators
|
||||
and a total of four bundles and return the corresponding Repo object
|
||||
"""
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.1"),
|
||||
bundle_files("hello", "0.0.2"),
|
||||
bundle_files("world", "0.0.1"),
|
||||
bundle_files("world", "0.0.2"),
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
return repo
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
from pathlib import Path
|
||||
from typing import Iterator
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from _pytest.capture import CaptureFixture
|
||||
|
||||
from operator_repo import Bundle, Operator, Repo
|
||||
from operator_repo.checks import CheckResult
|
||||
from operator_repo.cli import _get_repo, main, parse_target
|
||||
|
||||
|
||||
def test_cli_parse_target(mock_repo: Repo) -> None:
|
||||
assert parse_target(mock_repo, "hello") == mock_repo.operator("hello")
|
||||
assert parse_target(mock_repo, "world/0.0.1") == mock_repo.operator("world").bundle(
|
||||
"0.0.1"
|
||||
)
|
||||
|
||||
|
||||
def test_cli_list(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool", "-r", str(mock_repo.root), "list", "hello"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "hello/0.0.1" in captured.out
|
||||
assert "hello/0.0.2" in captured.out
|
||||
|
||||
|
||||
def test_cli_list_repo(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool", "-r", str(mock_repo.root), "list"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "hello" in captured.out
|
||||
assert "world" in captured.out
|
||||
|
||||
|
||||
def test_cli_list_bundle(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch(
|
||||
"sys.argv", ["optool", "-r", str(mock_repo.root), "list", "hello/0.0.1"]
|
||||
):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "hello/0.0.1" in captured.out
|
||||
assert "hello/0.0.2" not in captured.out
|
||||
|
||||
|
||||
def test_cli_list_recursive(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool", "-r", str(mock_repo.root), "list", "-R"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "hello/0.0.1" in captured.out
|
||||
assert "hello/0.0.2" in captured.out
|
||||
assert "world/0.0.1" in captured.out
|
||||
assert "world/0.0.2" in captured.out
|
||||
|
||||
|
||||
def test_cli_check(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool", "-r", str(mock_repo.root), "check", "hello"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "Channel beta has dangling bundles" in captured.out
|
||||
|
||||
|
||||
def test_cli_check_recursive(mock_repo: Repo, capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool", "-r", str(mock_repo.root), "check", "-R"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "Channel beta has dangling bundles" in captured.out
|
||||
assert "CSV doesn't define .metadata.annotations.containerImage" in captured.out
|
||||
|
||||
|
||||
def test_cli_check_operator_recursive(
|
||||
mock_repo: Repo, capsys: CaptureFixture[str]
|
||||
) -> None:
|
||||
with patch(
|
||||
"sys.argv", ["optool", "-r", str(mock_repo.root), "check", "-R", "hello"]
|
||||
):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "Channel beta has dangling bundles" in captured.out
|
||||
assert "CSV doesn't define .metadata.annotations.containerImage" in captured.out
|
||||
|
||||
|
||||
@patch("operator_repo.cli.get_checks")
|
||||
def test_cli_check_list(mock_checks: MagicMock, capsys: CaptureFixture[str]) -> None:
|
||||
def check_foo(_: Operator) -> Iterator[CheckResult]:
|
||||
"""This is the check_foo description"""
|
||||
raise StopIteration
|
||||
|
||||
def check_bar(_: Bundle) -> Iterator[CheckResult]:
|
||||
"""This is the check_bar description"""
|
||||
raise StopIteration
|
||||
|
||||
mock_checks.return_value = {"operator": [check_foo], "bundle": [check_bar]}
|
||||
with patch("sys.argv", ["optool", "check", "--list"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "This is the check_foo description" in captured.out
|
||||
assert "This is the check_bar description" in captured.out
|
||||
|
||||
|
||||
@patch("operator_repo.cli.Path.cwd")
|
||||
def test_cli_get_repo(mock_cwd: MagicMock, mock_repo: Repo) -> None:
|
||||
mock_cwd.return_value = mock_repo.root
|
||||
assert _get_repo() == mock_repo
|
||||
|
||||
|
||||
@patch("operator_repo.cli.Path.cwd")
|
||||
def test_cli_get_repo_invalid(
|
||||
mock_cwd: MagicMock, tmp_path: Path, capsys: CaptureFixture[str]
|
||||
) -> None:
|
||||
mock_cwd.return_value = tmp_path
|
||||
with pytest.raises(SystemExit):
|
||||
_ = _get_repo()
|
||||
captured = capsys.readouterr()
|
||||
assert "is not a valid operator repository" in captured.out
|
||||
|
||||
|
||||
def test_cli_help(capsys: CaptureFixture[str]) -> None:
|
||||
with patch("sys.argv", ["optool"]):
|
||||
main()
|
||||
captured = capsys.readouterr()
|
||||
assert "usage: optool" in captured.out
|
|
@ -103,3 +103,65 @@ def test_update_graph(tmp_path: Path) -> None:
|
|||
assert update[bundle1] == {bundle2}
|
||||
assert update[bundle2] == {bundle3, bundle4}
|
||||
assert update[bundle3] == {bundle4}
|
||||
|
||||
|
||||
def test_update_graph_invalid_replaces(tmp_path: Path) -> None:
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.1"),
|
||||
bundle_files("hello", "0.0.2", csv={"spec": {"replaces": "other.v0.0.1"}}),
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
operator = repo.operator("hello")
|
||||
with pytest.raises(ValueError, match="replaces a bundle from a different operator"):
|
||||
_ = operator.update_graph("beta")
|
||||
|
||||
|
||||
def test_update_graph_replaces_missing_bundle(tmp_path: Path) -> None:
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.2", csv={"spec": {"replaces": "hello.v0.0.1"}}),
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
operator = repo.operator("hello")
|
||||
_ = operator.update_graph("beta")
|
||||
|
||||
|
||||
def test_update_graph_invalid_operator_name(tmp_path: Path) -> None:
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.1", csv={"metadata": {"name": "other.v0.0.1"}}),
|
||||
bundle_files("hello", "0.0.2", csv={"spec": {"replaces": "hello.v0.0.1"}}),
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
operator = repo.operator("hello")
|
||||
with pytest.raises(ValueError, match="has bundles with different operator names"):
|
||||
_ = operator.update_graph("beta")
|
||||
|
||||
|
||||
def test_update_graph_semver(tmp_path: Path) -> None:
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.1"),
|
||||
bundle_files("hello", "0.0.2"),
|
||||
{"operators/hello/ci.yaml": {"updateGraph": "semver-mode"}},
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
operator = repo.operator("hello")
|
||||
bundle1 = operator.bundle("0.0.1")
|
||||
bundle2 = operator.bundle("0.0.2")
|
||||
update = operator.update_graph("beta")
|
||||
assert update[bundle1] == {bundle2}
|
||||
|
||||
|
||||
def test_update_graph_unsupported(tmp_path: Path) -> None:
|
||||
create_files(
|
||||
tmp_path,
|
||||
bundle_files("hello", "0.0.1"),
|
||||
bundle_files("hello", "0.0.2"),
|
||||
{"operators/hello/ci.yaml": {"updateGraph": "semver-skippatch"}},
|
||||
)
|
||||
repo = Repo(tmp_path)
|
||||
operator = repo.operator("hello")
|
||||
with pytest.raises(NotImplementedError, match="unsupported updateGraph value"):
|
||||
_ = operator.update_graph("beta")
|
||||
|
|
Loading…
Reference in New Issue