From 1f63fa9fbedfd118782f5e1ca1220d06cfea3fc0 Mon Sep 17 00:00:00 2001 From: JonasQuin42 <67019404+JonasQuin42@users.noreply.github.com> Date: Mon, 21 Sep 2026 12:32:28 -0400 Subject: [PATCH 1/2] Pass clear option through in unlink_template_from_host --- CHANGELOG | 6 ++- tests/commands/test_template.py | 68 +++++++++++++++++++++++++++++++++ zabbix_cli/commands/template.py | 2 +- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 tests/commands/test_template.py diff --git a/CHANGELOG b/CHANGELOG index bd73e65c..09e83aeb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,7 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - +## Unreleased + +### Fixed + +- `unlink_template_from_host --no-clear` clearing items and triggers from hosts instead of only unlinking the templates. ## [3.7.0](https://github.com/unioslo/zabbix-cli/tree/3.7.0) - 2026-06-17 diff --git a/tests/commands/test_template.py b/tests/commands/test_template.py new file mode 100644 index 00000000..1d3005c2 --- /dev/null +++ b/tests/commands/test_template.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +from unittest.mock import Mock + +import pytest +import typer +from typer.testing import CliRunner +from zabbix_cli.commands import template +from zabbix_cli.pyzabbix.types import Host +from zabbix_cli.pyzabbix.types import Template +from zabbix_cli.state import State + +HOST = Host(hostid="456", host="foo.example.com") +TEMPLATE = Template(templateid="123", host="Apache by HTTP", hosts=[HOST]) + + +def invoke_unlink( + state: State, monkeypatch: pytest.MonkeyPatch, flags: list[str] +) -> Mock: + """Invoke `unlink_template_from_host` and return the mocked API request. + + Only the transport is mocked, so the test covers the path from the + command through `ZabbixAPI.unlink_templates_from_hosts` to the API call. + """ + do_request = Mock() + monkeypatch.setattr(state.client, "do_request", do_request) + monkeypatch.setattr(template, "parse_templates_arg", lambda *a, **kw: [TEMPLATE]) + monkeypatch.setattr(template, "parse_hosts_arg", lambda *a, **kw: [HOST]) + + cli = typer.Typer() + _ = cli.command()(template.unlink_template_from_host) + result = CliRunner().invoke(cli, [*flags, "123", "456"]) + assert result.exit_code == 0, result.output + return do_request + + +@pytest.mark.parametrize( + "flags, expected", + [ + pytest.param([], {"templateids_clear": ["123"]}, id="default"), + pytest.param(["--clear"], {"templateids_clear": ["123"]}, id="clear"), + pytest.param(["--no-clear"], {"templateids": ["123"]}, id="no-clear"), + ], +) +def test_unlink_template_from_host_clear( + state: State, + monkeypatch: pytest.MonkeyPatch, + flags: list[str], + expected: dict[str, list[str]], +) -> None: + do_request = invoke_unlink(state, monkeypatch, flags) + do_request.assert_called_once_with( + "host.massremove", {"hostids": ["456"], **expected} + ) + + +@pytest.mark.parametrize( + "flags", + [ + pytest.param(["--dryrun"], id="default"), + pytest.param(["--dryrun", "--clear"], id="clear"), + pytest.param(["--dryrun", "--no-clear"], id="no-clear"), + ], +) +def test_unlink_template_from_host_dryrun( + state: State, monkeypatch: pytest.MonkeyPatch, flags: list[str] +) -> None: + invoke_unlink(state, monkeypatch, flags).assert_not_called() diff --git a/zabbix_cli/commands/template.py b/zabbix_cli/commands/template.py index 170f460a..fce1a2e3 100644 --- a/zabbix_cli/commands/template.py +++ b/zabbix_cli/commands/template.py @@ -286,7 +286,7 @@ def unlink_template_from_host( action = "Unlink and clear" if clear else "Unlink" if not dryrun: with app.state.console.status("Unlinking templates..."): - app.state.client.unlink_templates_from_hosts(templates, hosts) + app.state.client.unlink_templates_from_hosts(templates, hosts, clear=clear) # Only show hosts with matching templates to unlink result: list[UnlinkTemplateFromHostResult] = [] From fc951d35a285010f49a000978bc6dbebcf679fe3 Mon Sep 17 00:00:00 2001 From: JonasQuin42 <67019404+JonasQuin42@users.noreply.github.com> Date: Mon, 21 Sep 2026 12:38:27 -0400 Subject: [PATCH 2/2] Shorten test docstring --- tests/commands/test_template.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/commands/test_template.py b/tests/commands/test_template.py index 1d3005c2..297ad73d 100644 --- a/tests/commands/test_template.py +++ b/tests/commands/test_template.py @@ -17,11 +17,7 @@ def invoke_unlink( state: State, monkeypatch: pytest.MonkeyPatch, flags: list[str] ) -> Mock: - """Invoke `unlink_template_from_host` and return the mocked API request. - - Only the transport is mocked, so the test covers the path from the - command through `ZabbixAPI.unlink_templates_from_hosts` to the API call. - """ + """Run `unlink_template_from_host` and return the mocked `do_request`.""" do_request = Mock() monkeypatch.setattr(state.client, "do_request", do_request) monkeypatch.setattr(template, "parse_templates_arg", lambda *a, **kw: [TEMPLATE])