mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
153 lines
5.9 KiB
Python
153 lines
5.9 KiB
Python
from __future__ import annotations
|
|
|
|
import io
|
|
import unittest
|
|
import unittest.mock as mock
|
|
from contextlib import redirect_stderr, redirect_stdout
|
|
|
|
from cli.meta.ci import validate
|
|
from utils.github.variant import axes
|
|
|
|
_ROWS = [
|
|
{"name": "web-app-a", "variant": 0, "test_compose": True, "test_swarm": True},
|
|
{"name": "web-app-a", "variant": 1, "test_compose": True, "test_swarm": False},
|
|
{"name": "web-app-b", "variant": 0, "test_compose": False, "test_swarm": True},
|
|
]
|
|
|
|
_VARIANTS = {
|
|
"web-app-a": [{"services": {}}, {"services": {"tor": {"enabled": False}}}],
|
|
"web-app-b": [{"services": {}}],
|
|
}
|
|
|
|
|
|
def _problems(tokens: str, *, tor_mode: str = "auto") -> tuple[list[str], list[str]]:
|
|
with (
|
|
mock.patch.object(validate.query, "discover_rows", return_value=_ROWS),
|
|
mock.patch.object(validate, "get_variants", return_value=_VARIANTS),
|
|
):
|
|
return validate.problems(
|
|
tokens,
|
|
modes=("compose", "swarm", "host"),
|
|
tor_mode=tor_mode,
|
|
distros=axes.DISTROS,
|
|
filesystems=axes.FILESYSTEMS,
|
|
lifecycles="",
|
|
label="priority",
|
|
)
|
|
|
|
|
|
class TestProblems(unittest.TestCase):
|
|
def test_nothing_to_check_is_not_a_problem(self) -> None:
|
|
self.assertEqual(_problems(""), ([], []))
|
|
|
|
def test_a_token_the_branch_can_deploy_passes(self) -> None:
|
|
self.assertEqual(_problems("web-app-a#0@swarm+tor"), ([], []))
|
|
|
|
def test_a_variant_the_role_no_longer_declares_is_an_error(self) -> None:
|
|
errors, warnings = _problems("web-app-a#7@compose+tor")
|
|
self.assertEqual(warnings, [])
|
|
self.assertIn("matches no discovered row", errors[0])
|
|
self.assertIn("2 variant(s)", errors[0])
|
|
|
|
def test_a_bare_role_that_matches_nothing_only_warns(self) -> None:
|
|
errors, warnings = _problems("web-app-gone")
|
|
self.assertEqual(errors, [])
|
|
self.assertIn("web-app-gone", warnings[0])
|
|
|
|
def test_a_pinned_role_the_run_never_discovers_only_warns(self) -> None:
|
|
errors, warnings = _problems("web-app-gone#0,2")
|
|
self.assertEqual(errors, [])
|
|
self.assertIn("web-app-gone", warnings[0])
|
|
|
|
def test_a_bare_role_the_run_discovers_is_silent(self) -> None:
|
|
self.assertEqual(_problems("web-app-a"), ([], []))
|
|
|
|
def test_a_bare_role_is_judged_on_existence_not_on_variant_zero(self) -> None:
|
|
rows = [{"name": "web-app-c", "variant": 4, "test_compose": True}]
|
|
with (
|
|
mock.patch.object(validate.query, "discover_rows", return_value=rows),
|
|
mock.patch.object(
|
|
validate, "get_variants", return_value={"web-app-c": [{"services": {}}]}
|
|
),
|
|
):
|
|
errors, warnings = validate.problems(
|
|
"web-app-c",
|
|
modes=("compose",),
|
|
tor_mode="auto",
|
|
distros=axes.DISTROS,
|
|
filesystems=axes.FILESYSTEMS,
|
|
lifecycles="",
|
|
label="priority",
|
|
)
|
|
self.assertEqual((errors, warnings), ([], []))
|
|
|
|
def test_a_warning_still_separates_a_missing_role_from_a_present_one(self) -> None:
|
|
_errors, warnings = _problems("web-app-a web-app-gone web-app-b")
|
|
self.assertEqual(len(warnings), 1)
|
|
self.assertIn("web-app-gone", warnings[0])
|
|
|
|
def test_a_mode_the_row_does_not_offer_is_an_error(self) -> None:
|
|
errors, _warnings = _problems("web-app-a#1@swarm+clearnet")
|
|
self.assertIn("pinned mode 'swarm' is not available", errors[0])
|
|
|
|
def test_an_onion_state_the_variant_rules_out_is_an_error(self) -> None:
|
|
errors, _warnings = _problems("web-app-a#1@compose+tor")
|
|
self.assertIn("pinned onion state tor is impossible", errors[0])
|
|
|
|
def test_an_onion_state_the_runs_tor_axis_rules_out_is_an_error(self) -> None:
|
|
errors, _warnings = _problems(
|
|
"web-app-a#0@compose+clearnet", tor_mode="enforced"
|
|
)
|
|
self.assertIn("pinned onion state clearnet is impossible", errors[0])
|
|
|
|
def test_every_offender_is_reported_not_just_the_first(self) -> None:
|
|
errors, _warnings = _problems(
|
|
"web-app-a#7@compose+tor web-app-a#1@swarm+tor web-app-b#9@swarm+tor"
|
|
)
|
|
self.assertEqual(len(errors), 3)
|
|
|
|
def test_a_csv_token_is_checked_variant_by_variant(self) -> None:
|
|
errors, _warnings = _problems("web-app-a#0,7@compose+clearnet")
|
|
self.assertEqual(len(errors), 1)
|
|
self.assertIn("matches no discovered row", errors[0])
|
|
|
|
|
|
class TestMain(unittest.TestCase):
|
|
def _main(self, argv: list[str]) -> tuple[int, str, str]:
|
|
out, err = io.StringIO(), io.StringIO()
|
|
with (
|
|
mock.patch.object(validate.query, "discover_rows", return_value=_ROWS),
|
|
mock.patch.object(validate, "get_variants", return_value=_VARIANTS),
|
|
redirect_stdout(out),
|
|
redirect_stderr(err),
|
|
):
|
|
code = validate.main(argv)
|
|
return code, out.getvalue(), err.getvalue()
|
|
|
|
def test_a_valid_selection_exits_zero(self) -> None:
|
|
code, out, _err = self._main(["--priority", "web-app-a#0@swarm+tor"])
|
|
self.assertEqual(code, 0)
|
|
self.assertIn("valid for this branch", out)
|
|
|
|
def test_an_unusable_selection_exits_non_zero(self) -> None:
|
|
code, _out, err = self._main(["--priority", "web-app-a#7"])
|
|
self.assertEqual(code, 1)
|
|
self.assertIn("::error::", err)
|
|
|
|
def test_both_inputs_are_checked_and_named_in_the_message(self) -> None:
|
|
code, _out, err = self._main(
|
|
["--whitelist", "web-app-a#7", "--priority", "web-app-b#9"]
|
|
)
|
|
self.assertEqual(code, 1)
|
|
self.assertIn("whitelist:", err)
|
|
self.assertIn("priority:", err)
|
|
|
|
def test_a_warning_alone_does_not_fail_the_run(self) -> None:
|
|
code, out, _err = self._main(["--whitelist", "web-app-gone"])
|
|
self.assertEqual(code, 0)
|
|
self.assertIn("::warning::", out)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|