diff options
Diffstat (limited to '')
-rw-r--r-- | tests/units/cli/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/check/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/check/test__init__.py | 18 | ||||
-rw-r--r-- | tests/units/cli/check/test_commands.py | 11 | ||||
-rw-r--r-- | tests/units/cli/debug/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/debug/test__init__.py | 18 | ||||
-rw-r--r-- | tests/units/cli/debug/test_commands.py | 19 | ||||
-rw-r--r-- | tests/units/cli/exec/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/exec/test__init__.py | 18 | ||||
-rw-r--r-- | tests/units/cli/exec/test_commands.py | 32 | ||||
-rw-r--r-- | tests/units/cli/exec/test_utils.py | 113 | ||||
-rw-r--r-- | tests/units/cli/get/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/get/test__init__.py | 18 | ||||
-rw-r--r-- | tests/units/cli/get/test_commands.py | 112 | ||||
-rw-r--r-- | tests/units/cli/get/test_utils.py | 57 | ||||
-rw-r--r-- | tests/units/cli/nrfu/__init__.py | 1 | ||||
-rw-r--r-- | tests/units/cli/nrfu/test__init__.py | 39 | ||||
-rw-r--r-- | tests/units/cli/nrfu/test_commands.py | 59 | ||||
-rw-r--r-- | tests/units/cli/test__init__.py | 46 |
19 files changed, 305 insertions, 261 deletions
diff --git a/tests/units/cli/__init__.py b/tests/units/cli/__init__.py index e772bee..1d4cf6c 100644 --- a/tests/units/cli/__init__.py +++ b/tests/units/cli/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli submodule.""" diff --git a/tests/units/cli/check/__init__.py b/tests/units/cli/check/__init__.py index e772bee..a116af4 100644 --- a/tests/units/cli/check/__init__.py +++ b/tests/units/cli/check/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli.check submodule.""" diff --git a/tests/units/cli/check/test__init__.py b/tests/units/cli/check/test__init__.py index a3a770b..2501dc8 100644 --- a/tests/units/cli/check/test__init__.py +++ b/tests/units/cli/check/test__init__.py @@ -1,30 +1,28 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.check -""" +"""Tests for anta.cli.check.""" + from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + def test_anta_check(click_runner: CliRunner) -> None: - """ - Test anta check - """ + """Test anta check.""" result = click_runner.invoke(anta, ["check"]) assert result.exit_code == ExitCode.OK assert "Usage: anta check" in result.output def test_anta_check_help(click_runner: CliRunner) -> None: - """ - Test anta check --help - """ + """Test anta check --help.""" result = click_runner.invoke(anta, ["check", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta check" in result.output diff --git a/tests/units/cli/check/test_commands.py b/tests/units/cli/check/test_commands.py index 746b315..11c2b5f 100644 --- a/tests/units/cli/check/test_commands.py +++ b/tests/units/cli/check/test_commands.py @@ -1,9 +1,8 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.check.commands -""" +"""Tests for anta.cli.check.commands.""" + from __future__ import annotations from pathlib import Path @@ -21,7 +20,7 @@ DATA_DIR: Path = Path(__file__).parents[3].resolve() / "data" @pytest.mark.parametrize( - "catalog_path, expected_exit, expected_output", + ("catalog_path", "expected_exit", "expected_output"), [ pytest.param("ghost_catalog.yml", ExitCode.USAGE_ERROR, "Error: Invalid value for '--catalog'", id="catalog does not exist"), pytest.param("test_catalog_with_undefined_module.yml", ExitCode.USAGE_ERROR, "Test catalog is invalid!", id="catalog is not valid"), @@ -29,9 +28,7 @@ DATA_DIR: Path = Path(__file__).parents[3].resolve() / "data" ], ) def test_catalog(click_runner: CliRunner, catalog_path: Path, expected_exit: int, expected_output: str) -> None: - """ - Test `anta check catalog -c catalog - """ + """Test `anta check catalog -c catalog.""" result = click_runner.invoke(anta, ["check", "catalog", "-c", str(DATA_DIR / catalog_path)]) assert result.exit_code == expected_exit assert expected_output in result.output diff --git a/tests/units/cli/debug/__init__.py b/tests/units/cli/debug/__init__.py index e772bee..ccce49c 100644 --- a/tests/units/cli/debug/__init__.py +++ b/tests/units/cli/debug/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli.debug submodule.""" diff --git a/tests/units/cli/debug/test__init__.py b/tests/units/cli/debug/test__init__.py index 062182d..fd3663f 100644 --- a/tests/units/cli/debug/test__init__.py +++ b/tests/units/cli/debug/test__init__.py @@ -1,30 +1,28 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.debug -""" +"""Tests for anta.cli.debug.""" + from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + def test_anta_debug(click_runner: CliRunner) -> None: - """ - Test anta debug - """ + """Test anta debug.""" result = click_runner.invoke(anta, ["debug"]) assert result.exit_code == ExitCode.OK assert "Usage: anta debug" in result.output def test_anta_debug_help(click_runner: CliRunner) -> None: - """ - Test anta debug --help - """ + """Test anta debug --help.""" result = click_runner.invoke(anta, ["debug", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta debug" in result.output diff --git a/tests/units/cli/debug/test_commands.py b/tests/units/cli/debug/test_commands.py index 6d9ac29..76c3648 100644 --- a/tests/units/cli/debug/test_commands.py +++ b/tests/units/cli/debug/test_commands.py @@ -1,9 +1,8 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.debug.commands -""" +"""Tests for anta.cli.debug.commands.""" + from __future__ import annotations from typing import TYPE_CHECKING, Literal @@ -18,7 +17,7 @@ if TYPE_CHECKING: @pytest.mark.parametrize( - "command, ofmt, version, revision, device, failed", + ("command", "ofmt", "version", "revision", "device", "failed"), [ pytest.param("show version", "json", None, None, "dummy", False, id="json command"), pytest.param("show version", "text", None, None, "dummy", False, id="text command"), @@ -29,11 +28,15 @@ if TYPE_CHECKING: ], ) def test_run_cmd( - click_runner: CliRunner, command: str, ofmt: Literal["json", "text"], version: Literal["1", "latest"] | None, revision: int | None, device: str, failed: bool + click_runner: CliRunner, + command: str, + ofmt: Literal["json", "text"], + version: Literal["1", "latest"] | None, + revision: int | None, + device: str, + failed: bool, ) -> None: - """ - Test `anta debug run-cmd` - """ + """Test `anta debug run-cmd`.""" # pylint: disable=too-many-arguments cli_args = ["-l", "debug", "debug", "run-cmd", "--command", command, "--device", device] diff --git a/tests/units/cli/exec/__init__.py b/tests/units/cli/exec/__init__.py index e772bee..4ed48bc 100644 --- a/tests/units/cli/exec/__init__.py +++ b/tests/units/cli/exec/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli.exec submodule.""" diff --git a/tests/units/cli/exec/test__init__.py b/tests/units/cli/exec/test__init__.py index f8ad365..124d4af 100644 --- a/tests/units/cli/exec/test__init__.py +++ b/tests/units/cli/exec/test__init__.py @@ -1,30 +1,28 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.exec -""" +"""Tests for anta.cli.exec.""" + from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + def test_anta_exec(click_runner: CliRunner) -> None: - """ - Test anta exec - """ + """Test anta exec.""" result = click_runner.invoke(anta, ["exec"]) assert result.exit_code == ExitCode.OK assert "Usage: anta exec" in result.output def test_anta_exec_help(click_runner: CliRunner) -> None: - """ - Test anta exec --help - """ + """Test anta exec --help.""" result = click_runner.invoke(anta, ["exec", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta exec" in result.output diff --git a/tests/units/cli/exec/test_commands.py b/tests/units/cli/exec/test_commands.py index f96d7f6..4a72d63 100644 --- a/tests/units/cli/exec/test_commands.py +++ b/tests/units/cli/exec/test_commands.py @@ -1,9 +1,7 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.exec.commands -""" +"""Tests for anta.cli.exec.commands.""" from __future__ import annotations @@ -21,27 +19,21 @@ if TYPE_CHECKING: def test_clear_counters_help(click_runner: CliRunner) -> None: - """ - Test `anta exec clear-counters --help` - """ + """Test `anta exec clear-counters --help`.""" result = click_runner.invoke(clear_counters, ["--help"]) assert result.exit_code == 0 assert "Usage" in result.output def test_snapshot_help(click_runner: CliRunner) -> None: - """ - Test `anta exec snapshot --help` - """ + """Test `anta exec snapshot --help`.""" result = click_runner.invoke(snapshot, ["--help"]) assert result.exit_code == 0 assert "Usage" in result.output def test_collect_tech_support_help(click_runner: CliRunner) -> None: - """ - Test `anta exec collect-tech-support --help` - """ + """Test `anta exec collect-tech-support --help`.""" result = click_runner.invoke(collect_tech_support, ["--help"]) assert result.exit_code == 0 assert "Usage" in result.output @@ -55,9 +47,7 @@ def test_collect_tech_support_help(click_runner: CliRunner) -> None: ], ) def test_clear_counters(click_runner: CliRunner, tags: str | None) -> None: - """ - Test `anta exec clear-counters` - """ + """Test `anta exec clear-counters`.""" cli_args = ["exec", "clear-counters"] if tags is not None: cli_args.extend(["--tags", tags]) @@ -69,7 +59,7 @@ COMMAND_LIST_PATH_FILE = Path(__file__).parent.parent.parent.parent / "data" / " @pytest.mark.parametrize( - "commands_path, tags", + ("commands_path", "tags"), [ pytest.param(None, None, id="missing command list"), pytest.param(Path("/I/do/not/exist"), None, id="wrong path for command_list"), @@ -78,9 +68,7 @@ COMMAND_LIST_PATH_FILE = Path(__file__).parent.parent.parent.parent / "data" / " ], ) def test_snapshot(tmp_path: Path, click_runner: CliRunner, commands_path: Path | None, tags: str | None) -> None: - """ - Test `anta exec snapshot` - """ + """Test `anta exec snapshot`.""" cli_args = ["exec", "snapshot", "--output", str(tmp_path)] # Need to mock datetetime if commands_path is not None: @@ -99,7 +87,7 @@ def test_snapshot(tmp_path: Path, click_runner: CliRunner, commands_path: Path | @pytest.mark.parametrize( - "output, latest, configure, tags", + ("output", "latest", "configure", "tags"), [ pytest.param(None, None, False, None, id="no params"), pytest.param("/tmp/dummy", None, False, None, id="with output"), @@ -109,9 +97,7 @@ def test_snapshot(tmp_path: Path, click_runner: CliRunner, commands_path: Path | ], ) def test_collect_tech_support(click_runner: CliRunner, output: str | None, latest: str | None, configure: bool | None, tags: str | None) -> None: - """ - Test `anta exec collect-tech-support` - """ + """Test `anta exec collect-tech-support`.""" cli_args = ["exec", "collect-tech-support"] if output is not None: cli_args.extend(["--output", output]) diff --git a/tests/units/cli/exec/test_utils.py b/tests/units/cli/exec/test_utils.py index 6df1c86..455568b 100644 --- a/tests/units/cli/exec/test_utils.py +++ b/tests/units/cli/exec/test_utils.py @@ -1,9 +1,7 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.exec.utils -""" +"""Tests for anta.cli.exec.utils.""" from __future__ import annotations @@ -12,40 +10,59 @@ from unittest.mock import call, patch import pytest -from anta.cli.exec.utils import clear_counters_utils # , collect_commands, collect_scheduled_show_tech -from anta.device import AntaDevice -from anta.inventory import AntaInventory +from anta.cli.exec.utils import ( + clear_counters_utils, +) from anta.models import AntaCommand +# , collect_commands, collect_scheduled_show_tech + if TYPE_CHECKING: - from pytest import LogCaptureFixture + from anta.device import AntaDevice + from anta.inventory import AntaInventory -# TODO complete test cases -@pytest.mark.asyncio +# TODO: complete test cases +@pytest.mark.asyncio() @pytest.mark.parametrize( - "inventory_state, per_device_command_output, tags", + ("inventory_state", "per_device_command_output", "tags"), [ pytest.param( - {"dummy": {"is_online": False}, "dummy2": {"is_online": False}, "dummy3": {"is_online": False}}, + { + "dummy": {"is_online": False}, + "dummy2": {"is_online": False}, + "dummy3": {"is_online": False}, + }, {}, None, id="no_connected_device", ), pytest.param( - {"dummy": {"is_online": True, "hw_model": "cEOSLab"}, "dummy2": {"is_online": True, "hw_model": "vEOS-lab"}, "dummy3": {"is_online": False}}, + { + "dummy": {"is_online": True, "hw_model": "cEOSLab"}, + "dummy2": {"is_online": True, "hw_model": "vEOS-lab"}, + "dummy3": {"is_online": False}, + }, {}, None, id="cEOSLab and vEOS-lab devices", ), pytest.param( - {"dummy": {"is_online": True}, "dummy2": {"is_online": True}, "dummy3": {"is_online": False}}, + { + "dummy": {"is_online": True}, + "dummy2": {"is_online": True}, + "dummy3": {"is_online": False}, + }, {"dummy": None}, # None means the command failed to collect None, id="device with error", ), pytest.param( - {"dummy": {"is_online": True}, "dummy2": {"is_online": True}, "dummy3": {"is_online": True}}, + { + "dummy": {"is_online": True}, + "dummy2": {"is_online": True}, + "dummy3": {"is_online": True}, + }, {}, ["spine"], id="tags", @@ -53,42 +70,38 @@ if TYPE_CHECKING: ], ) async def test_clear_counters_utils( - caplog: LogCaptureFixture, + caplog: pytest.LogCaptureFixture, test_inventory: AntaInventory, inventory_state: dict[str, Any], per_device_command_output: dict[str, Any], - tags: list[str] | None, + tags: set[str] | None, ) -> None: - """ - Test anta.cli.exec.utils.clear_counters_utils - """ + """Test anta.cli.exec.utils.clear_counters_utils.""" async def mock_connect_inventory() -> None: - """ - mocking connect_inventory coroutine - """ + """Mock connect_inventory coroutine.""" for name, device in test_inventory.items(): device.is_online = inventory_state[name].get("is_online", True) device.established = inventory_state[name].get("established", device.is_online) device.hw_model = inventory_state[name].get("hw_model", "dummy") async def dummy_collect(self: AntaDevice, command: AntaCommand) -> None: - """ - mocking collect coroutine - """ + """Mock collect coroutine.""" command.output = per_device_command_output.get(self.name, "") # Need to patch the child device class - with patch("anta.device.AsyncEOSDevice.collect", side_effect=dummy_collect, autospec=True) as mocked_collect, patch( - "anta.inventory.AntaInventory.connect_inventory", - side_effect=mock_connect_inventory, - ) as mocked_connect_inventory: - print(mocked_collect) + with ( + patch("anta.device.AsyncEOSDevice.collect", side_effect=dummy_collect, autospec=True) as mocked_collect, + patch( + "anta.inventory.AntaInventory.connect_inventory", + side_effect=mock_connect_inventory, + ) as mocked_connect_inventory, + ): mocked_collect.side_effect = dummy_collect await clear_counters_utils(test_inventory, tags=tags) mocked_connect_inventory.assert_awaited_once() - devices_established = list(test_inventory.get_inventory(established_only=True, tags=tags).values()) + devices_established = test_inventory.get_inventory(established_only=True, tags=tags).devices if devices_established: # Building the list of calls calls = [] @@ -96,32 +109,28 @@ async def test_clear_counters_utils( calls.append( call( device, - **{ - "command": AntaCommand( - command="clear counters", - version="latest", - revision=None, - ofmt="json", - output=per_device_command_output.get(device.name, ""), - errors=[], - ) - }, - ) + command=AntaCommand( + command="clear counters", + version="latest", + revision=None, + ofmt="json", + output=per_device_command_output.get(device.name, ""), + errors=[], + ), + ), ) if device.hw_model not in ["cEOSLab", "vEOS-lab"]: calls.append( call( device, - **{ - "command": AntaCommand( - command="clear hardware counter drop", - version="latest", - revision=None, - ofmt="json", - output=per_device_command_output.get(device.name, ""), - ) - }, - ) + command=AntaCommand( + command="clear hardware counter drop", + version="latest", + revision=None, + ofmt="json", + output=per_device_command_output.get(device.name, ""), + ), + ), ) mocked_collect.assert_has_awaits(calls) # Check error diff --git a/tests/units/cli/get/__init__.py b/tests/units/cli/get/__init__.py index e772bee..5517ded 100644 --- a/tests/units/cli/get/__init__.py +++ b/tests/units/cli/get/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli.get submodule.""" diff --git a/tests/units/cli/get/test__init__.py b/tests/units/cli/get/test__init__.py index b18ef88..a6a0c3c 100644 --- a/tests/units/cli/get/test__init__.py +++ b/tests/units/cli/get/test__init__.py @@ -1,30 +1,28 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.get -""" +"""Tests for anta.cli.get.""" + from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + def test_anta_get(click_runner: CliRunner) -> None: - """ - Test anta get - """ + """Test anta get.""" result = click_runner.invoke(anta, ["get"]) assert result.exit_code == ExitCode.OK assert "Usage: anta get" in result.output def test_anta_get_help(click_runner: CliRunner) -> None: - """ - Test anta get --help - """ + """Test anta get --help.""" result = click_runner.invoke(anta, ["get", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta get" in result.output diff --git a/tests/units/cli/get/test_commands.py b/tests/units/cli/get/test_commands.py index aa6dc4f..9edc7c3 100644 --- a/tests/units/cli/get/test_commands.py +++ b/tests/units/cli/get/test_commands.py @@ -1,9 +1,8 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.get.commands -""" +"""Tests for anta.cli.get.commands.""" + from __future__ import annotations import filecmp @@ -12,7 +11,6 @@ from typing import TYPE_CHECKING from unittest.mock import ANY, patch import pytest -from cvprac.cvp_client import CvpClient from cvprac.cvp_client_errors import CvpApiError from anta.cli import anta @@ -20,12 +18,13 @@ from anta.cli.utils import ExitCode if TYPE_CHECKING: from click.testing import CliRunner + from cvprac.cvp_client import CvpClient DATA_DIR: Path = Path(__file__).parents[3].resolve() / "data" @pytest.mark.parametrize( - "cvp_container, cvp_connect_failure", + ("cvp_container", "cvp_connect_failure"), [ pytest.param(None, False, id="all devices"), pytest.param("custom_container", False, id="custom container"), @@ -38,28 +37,46 @@ def test_from_cvp( cvp_container: str | None, cvp_connect_failure: bool, ) -> None: - """ - Test `anta get from-cvp` + """Test `anta get from-cvp`. This test verifies that username and password are NOT mandatory to run this command """ output: Path = tmp_path / "output.yml" - cli_args = ["get", "from-cvp", "--output", str(output), "--host", "42.42.42.42", "--username", "anta", "--password", "anta"] + cli_args = [ + "get", + "from-cvp", + "--output", + str(output), + "--host", + "42.42.42.42", + "--username", + "anta", + "--password", + "anta", + ] if cvp_container is not None: cli_args.extend(["--container", cvp_container]) - def mock_cvp_connect(self: CvpClient, *args: str, **kwargs: str) -> None: - # pylint: disable=unused-argument + def mock_cvp_connect(_self: CvpClient, *_args: str, **_kwargs: str) -> None: if cvp_connect_failure: raise CvpApiError(msg="mocked CvpApiError") # always get a token - with patch("anta.cli.get.commands.get_cv_token", return_value="dummy_token"), patch( - "cvprac.cvp_client.CvpClient.connect", autospec=True, side_effect=mock_cvp_connect - ) as mocked_cvp_connect, patch("cvprac.cvp_client.CvpApi.get_inventory", autospec=True, return_value=[]) as mocked_get_inventory, patch( - "cvprac.cvp_client.CvpApi.get_devices_in_container", autospec=True, return_value=[] - ) as mocked_get_devices_in_container: + with ( + patch("anta.cli.get.commands.get_cv_token", return_value="dummy_token"), + patch( + "cvprac.cvp_client.CvpClient.connect", + autospec=True, + side_effect=mock_cvp_connect, + ) as mocked_cvp_connect, + patch("cvprac.cvp_client.CvpApi.get_inventory", autospec=True, return_value=[]) as mocked_get_inventory, + patch( + "cvprac.cvp_client.CvpApi.get_devices_in_container", + autospec=True, + return_value=[], + ) as mocked_get_devices_in_container, + ): result = click_runner.invoke(anta, cli_args) if not cvp_connect_failure: @@ -79,12 +96,24 @@ def test_from_cvp( @pytest.mark.parametrize( - "ansible_inventory, ansible_group, expected_exit, expected_log", + ("ansible_inventory", "ansible_group", "expected_exit", "expected_log"), [ pytest.param("ansible_inventory.yml", None, ExitCode.OK, None, id="no group"), pytest.param("ansible_inventory.yml", "ATD_LEAFS", ExitCode.OK, None, id="group found"), - pytest.param("ansible_inventory.yml", "DUMMY", ExitCode.USAGE_ERROR, "Group DUMMY not found in Ansible inventory", id="group not found"), - pytest.param("empty_ansible_inventory.yml", None, ExitCode.USAGE_ERROR, "is empty", id="empty inventory"), + pytest.param( + "ansible_inventory.yml", + "DUMMY", + ExitCode.USAGE_ERROR, + "Group DUMMY not found in Ansible inventory", + id="group not found", + ), + pytest.param( + "empty_ansible_inventory.yml", + None, + ExitCode.USAGE_ERROR, + "is empty", + id="empty inventory", + ), ], ) def test_from_ansible( @@ -95,8 +124,8 @@ def test_from_ansible( expected_exit: int, expected_log: str | None, ) -> None: - """ - Test `anta get from-ansible` + # pylint: disable=too-many-arguments + """Test `anta get from-ansible`. This test verifies: * the parsing of an ansible-inventory @@ -107,7 +136,14 @@ def test_from_ansible( output: Path = tmp_path / "output.yml" ansible_inventory_path = DATA_DIR / ansible_inventory # Init cli_args - cli_args = ["get", "from-ansible", "--output", str(output), "--ansible-inventory", str(ansible_inventory_path)] + cli_args = [ + "get", + "from-ansible", + "--output", + str(output), + "--ansible-inventory", + str(ansible_inventory_path), + ] # Set --ansible-group if ansible_group is not None: @@ -122,14 +158,30 @@ def test_from_ansible( assert expected_log in result.output else: assert output.exists() - # TODO check size of generated inventory to validate the group functionality! + # TODO: check size of generated inventory to validate the group functionality! @pytest.mark.parametrize( - "env_set, overwrite, is_tty, prompt, expected_exit, expected_log", + ("env_set", "overwrite", "is_tty", "prompt", "expected_exit", "expected_log"), [ - pytest.param(True, False, True, "y", ExitCode.OK, "", id="no-overwrite-tty-init-prompt-yes"), - pytest.param(True, False, True, "N", ExitCode.INTERNAL_ERROR, "Aborted", id="no-overwrite-tty-init-prompt-no"), + pytest.param( + True, + False, + True, + "y", + ExitCode.OK, + "", + id="no-overwrite-tty-init-prompt-yes", + ), + pytest.param( + True, + False, + True, + "N", + ExitCode.INTERNAL_ERROR, + "Aborted", + id="no-overwrite-tty-init-prompt-no", + ), pytest.param( True, False, @@ -159,8 +211,7 @@ def test_from_ansible_overwrite( expected_log: str | None, ) -> None: # pylint: disable=too-many-arguments - """ - Test `anta get from-ansible` overwrite mechanism + """Test `anta get from-ansible` overwrite mechanism. The test uses a static ansible-inventory and output as these are tested in other functions @@ -177,7 +228,12 @@ def test_from_ansible_overwrite( ansible_inventory_path = DATA_DIR / "ansible_inventory.yml" expected_anta_inventory_path = DATA_DIR / "expected_anta_inventory.yml" tmp_output = tmp_path / "output.yml" - cli_args = ["get", "from-ansible", "--ansible-inventory", str(ansible_inventory_path)] + cli_args = [ + "get", + "from-ansible", + "--ansible-inventory", + str(ansible_inventory_path), + ] if env_set: tmp_inv = Path(str(temp_env["ANTA_INVENTORY"])) diff --git a/tests/units/cli/get/test_utils.py b/tests/units/cli/get/test_utils.py index b335880..0dce335 100644 --- a/tests/units/cli/get/test_utils.py +++ b/tests/units/cli/get/test_utils.py @@ -1,12 +1,11 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.get.utils -""" +"""Tests for anta.cli.get.utils.""" + from __future__ import annotations -from contextlib import nullcontext +from contextlib import AbstractContextManager, nullcontext from pathlib import Path from typing import Any from unittest.mock import MagicMock, patch @@ -21,10 +20,8 @@ DATA_DIR: Path = Path(__file__).parents[3].resolve() / "data" def test_get_cv_token() -> None: - """ - Test anta.get.utils.get_cv_token - """ - ip = "42.42.42.42" + """Test anta.get.utils.get_cv_token.""" + ip_addr = "42.42.42.42" username = "ant" password = "formica" @@ -32,7 +29,7 @@ def test_get_cv_token() -> None: mocked_ret = MagicMock(autospec=requests.Response) mocked_ret.json.return_value = {"sessionId": "simple"} patched_request.return_value = mocked_ret - res = get_cv_token(ip, username, password) + res = get_cv_token(ip_addr, username, password) patched_request.assert_called_once_with( "POST", "https://42.42.42.42/cvpservice/login/authenticate.do", @@ -72,9 +69,7 @@ CVP_INVENTORY = [ ], ) def test_create_inventory_from_cvp(tmp_path: Path, inventory: list[dict[str, Any]]) -> None: - """ - Test anta.get.utils.create_inventory_from_cvp - """ + """Test anta.get.utils.create_inventory_from_cvp.""" output = tmp_path / "output.yml" create_inventory_from_cvp(inventory, output) @@ -86,19 +81,41 @@ def test_create_inventory_from_cvp(tmp_path: Path, inventory: list[dict[str, Any @pytest.mark.parametrize( - "inventory_filename, ansible_group, expected_raise, expected_inv_length", + ("inventory_filename", "ansible_group", "expected_raise", "expected_inv_length"), [ pytest.param("ansible_inventory.yml", None, nullcontext(), 7, id="no group"), pytest.param("ansible_inventory.yml", "ATD_LEAFS", nullcontext(), 4, id="group found"), - pytest.param("ansible_inventory.yml", "DUMMY", pytest.raises(ValueError, match="Group DUMMY not found in Ansible inventory"), 0, id="group not found"), - pytest.param("empty_ansible_inventory.yml", None, pytest.raises(ValueError, match="Ansible inventory .* is empty"), 0, id="empty inventory"), - pytest.param("wrong_ansible_inventory.yml", None, pytest.raises(ValueError, match="Could not parse"), 0, id="os error inventory"), + pytest.param( + "ansible_inventory.yml", + "DUMMY", + pytest.raises(ValueError, match="Group DUMMY not found in Ansible inventory"), + 0, + id="group not found", + ), + pytest.param( + "empty_ansible_inventory.yml", + None, + pytest.raises(ValueError, match="Ansible inventory .* is empty"), + 0, + id="empty inventory", + ), + pytest.param( + "wrong_ansible_inventory.yml", + None, + pytest.raises(ValueError, match="Could not parse"), + 0, + id="os error inventory", + ), ], ) -def test_create_inventory_from_ansible(tmp_path: Path, inventory_filename: Path, ansible_group: str | None, expected_raise: Any, expected_inv_length: int) -> None: - """ - Test anta.get.utils.create_inventory_from_ansible - """ +def test_create_inventory_from_ansible( + tmp_path: Path, + inventory_filename: Path, + ansible_group: str | None, + expected_raise: AbstractContextManager[Exception], + expected_inv_length: int, +) -> None: + """Test anta.get.utils.create_inventory_from_ansible.""" target_file = tmp_path / "inventory.yml" inventory_file_path = DATA_DIR / inventory_filename diff --git a/tests/units/cli/nrfu/__init__.py b/tests/units/cli/nrfu/__init__.py index e772bee..db71b4d 100644 --- a/tests/units/cli/nrfu/__init__.py +++ b/tests/units/cli/nrfu/__init__.py @@ -1,3 +1,4 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. +"""Test anta.cli.nrfu submodule.""" diff --git a/tests/units/cli/nrfu/test__init__.py b/tests/units/cli/nrfu/test__init__.py index fea641c..052c7c3 100644 --- a/tests/units/cli/nrfu/test__init__.py +++ b/tests/units/cli/nrfu/test__init__.py @@ -1,33 +1,31 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.nrfu -""" +"""Tests for anta.cli.nrfu.""" + from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode from tests.lib.utils import default_anta_env +if TYPE_CHECKING: + from click.testing import CliRunner + # TODO: write unit tests for ignore-status and ignore-error def test_anta_nrfu_help(click_runner: CliRunner) -> None: - """ - Test anta nrfu --help - """ + """Test anta nrfu --help.""" result = click_runner.invoke(anta, ["nrfu", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta nrfu" in result.output def test_anta_nrfu(click_runner: CliRunner) -> None: - """ - Test anta nrfu, catalog is given via env - """ + """Test anta nrfu, catalog is given via env.""" result = click_runner.invoke(anta, ["nrfu"]) assert result.exit_code == ExitCode.OK assert "ANTA Inventory contains 3 devices" in result.output @@ -35,9 +33,7 @@ def test_anta_nrfu(click_runner: CliRunner) -> None: def test_anta_password_required(click_runner: CliRunner) -> None: - """ - Test that password is provided - """ + """Test that password is provided.""" env = default_anta_env() env["ANTA_PASSWORD"] = None result = click_runner.invoke(anta, ["nrfu"], env=env) @@ -47,9 +43,7 @@ def test_anta_password_required(click_runner: CliRunner) -> None: def test_anta_password(click_runner: CliRunner) -> None: - """ - Test that password can be provided either via --password or --prompt - """ + """Test that password can be provided either via --password or --prompt.""" env = default_anta_env() env["ANTA_PASSWORD"] = None result = click_runner.invoke(anta, ["nrfu", "--password", "secret"], env=env) @@ -59,9 +53,7 @@ def test_anta_password(click_runner: CliRunner) -> None: def test_anta_enable_password(click_runner: CliRunner) -> None: - """ - Test that enable password can be provided either via --enable-password or --prompt - """ + """Test that enable password can be provided either via --enable-password or --prompt.""" # Both enable and enable-password result = click_runner.invoke(anta, ["nrfu", "--enable", "--enable-password", "secret"]) assert result.exit_code == ExitCode.OK @@ -78,7 +70,6 @@ def test_anta_enable_password(click_runner: CliRunner) -> None: assert "Please enter a password to enter EOS privileged EXEC mode" not in result.output assert result.exit_code == ExitCode.OK - # enable and enable-password and prompt (redundant) result = click_runner.invoke(anta, ["nrfu", "--enable", "--enable-password", "blah", "--prompt"], input="y\npassword\npassword\n") assert "Is a password required to enter EOS privileged EXEC mode? [y/N]:" not in result.output assert "Please enter a password to enter EOS privileged EXEC mode" not in result.output @@ -91,17 +82,13 @@ def test_anta_enable_password(click_runner: CliRunner) -> None: def test_anta_enable_alone(click_runner: CliRunner) -> None: - """ - Test that enable can be provided either without enable-password - """ + """Test that enable can be provided either without enable-password.""" result = click_runner.invoke(anta, ["nrfu", "--enable"]) assert result.exit_code == ExitCode.OK def test_disable_cache(click_runner: CliRunner) -> None: - """ - Test that disable_cache is working on inventory - """ + """Test that disable_cache is working on inventory.""" result = click_runner.invoke(anta, ["nrfu", "--disable-cache"]) stdout_lines = result.stdout.split("\n") # All caches should be disabled from the inventory diff --git a/tests/units/cli/nrfu/test_commands.py b/tests/units/cli/nrfu/test_commands.py index 4639671..4ea40b7 100644 --- a/tests/units/cli/nrfu/test_commands.py +++ b/tests/units/cli/nrfu/test_commands.py @@ -1,97 +1,82 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.nrfu.commands -""" +"""Tests for anta.cli.nrfu.commands.""" + from __future__ import annotations import json import re from pathlib import Path - -from click.testing import CliRunner +from typing import TYPE_CHECKING from anta.cli import anta from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + DATA_DIR: Path = Path(__file__).parent.parent.parent.parent.resolve() / "data" def test_anta_nrfu_table_help(click_runner: CliRunner) -> None: - """ - Test anta nrfu table --help - """ + """Test anta nrfu table --help.""" result = click_runner.invoke(anta, ["nrfu", "table", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta nrfu table" in result.output def test_anta_nrfu_text_help(click_runner: CliRunner) -> None: - """ - Test anta nrfu text --help - """ + """Test anta nrfu text --help.""" result = click_runner.invoke(anta, ["nrfu", "text", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta nrfu text" in result.output def test_anta_nrfu_json_help(click_runner: CliRunner) -> None: - """ - Test anta nrfu json --help - """ + """Test anta nrfu json --help.""" result = click_runner.invoke(anta, ["nrfu", "json", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta nrfu json" in result.output def test_anta_nrfu_template_help(click_runner: CliRunner) -> None: - """ - Test anta nrfu tpl-report --help - """ + """Test anta nrfu tpl-report --help.""" result = click_runner.invoke(anta, ["nrfu", "tpl-report", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta nrfu tpl-report" in result.output def test_anta_nrfu_table(click_runner: CliRunner) -> None: - """ - Test anta nrfu, catalog is given via env - """ + """Test anta nrfu, catalog is given via env.""" result = click_runner.invoke(anta, ["nrfu", "table"]) assert result.exit_code == ExitCode.OK assert "dummy │ VerifyEOSVersion │ success" in result.output def test_anta_nrfu_text(click_runner: CliRunner) -> None: - """ - Test anta nrfu, catalog is given via env - """ + """Test anta nrfu, catalog is given via env.""" result = click_runner.invoke(anta, ["nrfu", "text"]) assert result.exit_code == ExitCode.OK assert "dummy :: VerifyEOSVersion :: SUCCESS" in result.output def test_anta_nrfu_json(click_runner: CliRunner) -> None: - """ - Test anta nrfu, catalog is given via env - """ + """Test anta nrfu, catalog is given via env.""" result = click_runner.invoke(anta, ["nrfu", "json"]) assert result.exit_code == ExitCode.OK - assert "JSON results of all tests" in result.output - m = re.search(r"\[\n {[\s\S]+ }\n\]", result.output) - assert m is not None - result_list = json.loads(m.group()) - for r in result_list: - if r["name"] == "dummy": - assert r["test"] == "VerifyEOSVersion" - assert r["result"] == "success" + assert "JSON results" in result.output + match = re.search(r"\[\n {[\s\S]+ }\n\]", result.output) + assert match is not None + result_list = json.loads(match.group()) + for res in result_list: + if res["name"] == "dummy": + assert res["test"] == "VerifyEOSVersion" + assert res["result"] == "success" def test_anta_nrfu_template(click_runner: CliRunner) -> None: - """ - Test anta nrfu, catalog is given via env - """ + """Test anta nrfu, catalog is given via env.""" result = click_runner.invoke(anta, ["nrfu", "tpl-report", "--template", str(DATA_DIR / "template.j2")]) assert result.exit_code == ExitCode.OK assert "* VerifyEOSVersion is SUCCESS for dummy" in result.output diff --git a/tests/units/cli/test__init__.py b/tests/units/cli/test__init__.py index 0e84e14..0701083 100644 --- a/tests/units/cli/test__init__.py +++ b/tests/units/cli/test__init__.py @@ -1,58 +1,64 @@ # Copyright (c) 2023-2024 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the LICENSE file. -""" -Tests for anta.cli.__init__ -""" +"""Tests for anta.cli.__init__.""" from __future__ import annotations -from click.testing import CliRunner +from typing import TYPE_CHECKING +from unittest.mock import patch -from anta.cli import anta +import pytest + +from anta.cli import anta, cli from anta.cli.utils import ExitCode +if TYPE_CHECKING: + from click.testing import CliRunner + def test_anta(click_runner: CliRunner) -> None: - """ - Test anta main entrypoint - """ + """Test anta main entrypoint.""" result = click_runner.invoke(anta) assert result.exit_code == ExitCode.OK assert "Usage" in result.output def test_anta_help(click_runner: CliRunner) -> None: - """ - Test anta --help - """ + """Test anta --help.""" result = click_runner.invoke(anta, ["--help"]) assert result.exit_code == ExitCode.OK assert "Usage" in result.output def test_anta_exec_help(click_runner: CliRunner) -> None: - """ - Test anta exec --help - """ + """Test anta exec --help.""" result = click_runner.invoke(anta, ["exec", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta exec" in result.output def test_anta_debug_help(click_runner: CliRunner) -> None: - """ - Test anta debug --help - """ + """Test anta debug --help.""" result = click_runner.invoke(anta, ["debug", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta debug" in result.output def test_anta_get_help(click_runner: CliRunner) -> None: - """ - Test anta get --help - """ + """Test anta get --help.""" result = click_runner.invoke(anta, ["get", "--help"]) assert result.exit_code == ExitCode.OK assert "Usage: anta get" in result.output + + +def test_uncaught_failure_anta(caplog: pytest.LogCaptureFixture) -> None: + """Test uncaught failure when running ANTA cli.""" + with ( + pytest.raises(SystemExit) as e_info, + patch("anta.cli.anta", side_effect=ZeroDivisionError()), + ): + cli() + assert "CRITICAL" in caplog.text + assert "Uncaught Exception when running ANTA CLI" in caplog.text + assert e_info.value.code == 1 |