2025-02-05 11:32:35 +01:00
|
|
|
# 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.
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Tests for anta.cli.nrfu.commands."""
|
|
|
|
|
2025-02-05 11:32:35 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import json
|
|
|
|
import re
|
|
|
|
from pathlib import Path
|
2025-02-05 11:54:55 +01:00
|
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from unittest.mock import patch
|
2025-02-05 11:32:35 +01:00
|
|
|
|
|
|
|
from anta.cli import anta
|
|
|
|
from anta.cli.utils import ExitCode
|
|
|
|
|
2025-02-05 11:39:09 +01:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from click.testing import CliRunner
|
|
|
|
|
2025-02-05 11:32:35 +01:00
|
|
|
DATA_DIR: Path = Path(__file__).parent.parent.parent.parent.resolve() / "data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_table_help(click_runner: CliRunner) -> None:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu table --help."""
|
2025-02-05 11:32:35 +01:00
|
|
|
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:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu text --help."""
|
2025-02-05 11:32:35 +01:00
|
|
|
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:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu json --help."""
|
2025-02-05 11:32:35 +01:00
|
|
|
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:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu tpl-report --help."""
|
2025-02-05 11:32:35 +01:00
|
|
|
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:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
2025-02-05 11:32:35 +01:00
|
|
|
result = click_runner.invoke(anta, ["nrfu", "table"])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
2025-02-05 11:54:55 +01:00
|
|
|
assert "leaf1 │ VerifyEOSVersion │ success" in result.output
|
2025-02-05 11:32:35 +01:00
|
|
|
|
|
|
|
|
2025-02-05 11:39:50 +01:00
|
|
|
def test_anta_nrfu_table_group_by_device(click_runner: CliRunner) -> None:
|
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "table", "--group-by", "device"])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "Summary per device" in result.output
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_table_group_by_test(click_runner: CliRunner) -> None:
|
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "table", "--group-by", "test"])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "Summary per test" in result.output
|
|
|
|
|
|
|
|
|
2025-02-05 11:32:35 +01:00
|
|
|
def test_anta_nrfu_text(click_runner: CliRunner) -> None:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
2025-02-05 11:32:35 +01:00
|
|
|
result = click_runner.invoke(anta, ["nrfu", "text"])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
2025-02-05 11:54:55 +01:00
|
|
|
assert "leaf1 :: VerifyEOSVersion :: SUCCESS" in result.output
|
2025-02-05 11:32:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_json(click_runner: CliRunner) -> None:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
2025-02-05 11:32:35 +01:00
|
|
|
result = click_runner.invoke(anta, ["nrfu", "json"])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
2025-02-05 11:39:09 +01:00
|
|
|
assert "JSON results" in result.output
|
2025-02-05 11:39:50 +01:00
|
|
|
match = re.search(r"\[\n {2}{[\s\S]+ {2}}\n\]", result.output)
|
2025-02-05 11:39:09 +01:00
|
|
|
assert match is not None
|
|
|
|
result_list = json.loads(match.group())
|
|
|
|
for res in result_list:
|
2025-02-05 11:54:55 +01:00
|
|
|
if res["name"] == "leaf1":
|
2025-02-05 11:39:09 +01:00
|
|
|
assert res["test"] == "VerifyEOSVersion"
|
|
|
|
assert res["result"] == "success"
|
2025-02-05 11:32:35 +01:00
|
|
|
|
|
|
|
|
2025-02-05 11:54:55 +01:00
|
|
|
def test_anta_nrfu_json_output(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu json with output file."""
|
|
|
|
json_output = tmp_path / "test.json"
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "json", "--output", str(json_output)])
|
|
|
|
|
|
|
|
# Making sure the output is not printed to stdout
|
|
|
|
match = re.search(r"\[\n {2}{[\s\S]+ {2}}\n\]", result.output)
|
|
|
|
assert match is None
|
|
|
|
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "JSON results saved to" in result.output
|
|
|
|
assert json_output.exists()
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_json_output_failure(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu json with output file."""
|
|
|
|
json_output = tmp_path / "test.json"
|
|
|
|
|
|
|
|
original_open = Path.open
|
|
|
|
|
|
|
|
def mock_path_open(*args: Any, **kwargs: Any) -> Path: # noqa: ANN401
|
|
|
|
"""Mock Path.open only for the json_output file of this test."""
|
|
|
|
if args[0] == json_output:
|
|
|
|
msg = "Simulated OSError"
|
|
|
|
raise OSError(msg)
|
|
|
|
|
|
|
|
# If not the json_output file, call the original Path.open
|
|
|
|
return original_open(*args, **kwargs)
|
|
|
|
|
|
|
|
with patch("pathlib.Path.open", mock_path_open):
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "json", "--output", str(json_output)])
|
|
|
|
|
|
|
|
assert result.exit_code == ExitCode.USAGE_ERROR
|
|
|
|
assert "Failed to save JSON results to" in result.output
|
|
|
|
assert not json_output.exists()
|
|
|
|
|
|
|
|
|
2025-02-05 11:32:35 +01:00
|
|
|
def test_anta_nrfu_template(click_runner: CliRunner) -> None:
|
2025-02-05 11:39:09 +01:00
|
|
|
"""Test anta nrfu, catalog is given via env."""
|
2025-02-05 11:32:35 +01:00
|
|
|
result = click_runner.invoke(anta, ["nrfu", "tpl-report", "--template", str(DATA_DIR / "template.j2")])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
2025-02-05 11:54:55 +01:00
|
|
|
assert "* VerifyEOSVersion is SUCCESS for leaf1" in result.output
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_csv(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu csv."""
|
|
|
|
csv_output = tmp_path / "test.csv"
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "csv", "--csv-output", str(csv_output)])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "CSV report saved to" in result.output
|
|
|
|
assert csv_output.exists()
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_csv_failure(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu csv."""
|
|
|
|
csv_output = tmp_path / "test.csv"
|
|
|
|
with patch("anta.reporter.csv_reporter.ReportCsv.generate", side_effect=OSError()):
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "csv", "--csv-output", str(csv_output)])
|
|
|
|
assert result.exit_code == ExitCode.USAGE_ERROR
|
|
|
|
assert "Failed to save CSV report to" in result.output
|
|
|
|
assert not csv_output.exists()
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_md_report(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu md-report."""
|
|
|
|
md_output = tmp_path / "test.md"
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "md-report", "--md-output", str(md_output)])
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "Markdown report saved to" in result.output
|
|
|
|
assert md_output.exists()
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_md_report_failure(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu md-report failure."""
|
|
|
|
md_output = tmp_path / "test.md"
|
|
|
|
with patch("anta.reporter.md_reporter.MDReportGenerator.generate", side_effect=OSError()):
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "md-report", "--md-output", str(md_output)])
|
|
|
|
|
|
|
|
assert result.exit_code == ExitCode.USAGE_ERROR
|
|
|
|
assert "Failed to save Markdown report to" in result.output
|
|
|
|
assert not md_output.exists()
|
|
|
|
|
|
|
|
|
|
|
|
def test_anta_nrfu_md_report_with_hide(click_runner: CliRunner, tmp_path: Path) -> None:
|
|
|
|
"""Test anta nrfu md-report with the `--hide` option."""
|
|
|
|
md_output = tmp_path / "test.md"
|
|
|
|
result = click_runner.invoke(anta, ["nrfu", "--hide", "success", "md-report", "--md-output", str(md_output)])
|
|
|
|
|
|
|
|
assert result.exit_code == ExitCode.OK
|
|
|
|
assert "Markdown report saved to" in result.output
|
|
|
|
assert md_output.exists()
|
|
|
|
|
|
|
|
with md_output.open("r", encoding="utf-8") as f:
|
|
|
|
content = f.read()
|
|
|
|
|
|
|
|
# Use regex to find the "Total Tests Success" value
|
|
|
|
match = re.search(r"\| (\d+) \| (\d+) \| \d+ \| \d+ \| \d+ \|", content)
|
|
|
|
|
|
|
|
assert match is not None
|
|
|
|
|
|
|
|
total_tests = int(match.group(1))
|
|
|
|
total_tests_success = int(match.group(2))
|
|
|
|
|
|
|
|
assert total_tests == 0
|
|
|
|
assert total_tests_success == 0
|