Skip to content

Commit

Permalink
test: Add coverage for reporter (#448)
Browse files Browse the repository at this point in the history
Test: Add coverage for report
  • Loading branch information
gmuloc authored Nov 10, 2023
1 parent 6a3bf38 commit b75bcc3
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 59 deletions.
48 changes: 0 additions & 48 deletions anta/reporter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from jinja2 import Template
from rich.table import Table
from rich.text import Text

from anta import RICH_COLOR_PALETTE, RICH_COLOR_THEME
from anta.custom_types import TestStatus
Expand All @@ -26,12 +25,6 @@
class ReportTable:
"""TableReport Generate a Table based on TestResult."""

def __init__(self) -> None:
"""
__init__ Class constructor
"""
self.color_manager = ColorManager()

def _split_list_to_txt_list(self, usr_list: list[str], delimiter: Optional[str] = None) -> str:
"""
Split list to multi-lines string
Expand Down Expand Up @@ -253,44 +246,3 @@ def render(self, data: list[dict[str, Any]], trim_blocks: bool = True, lstrip_bl
template = Template(file_.read(), trim_blocks=trim_blocks, lstrip_blocks=lstrip_blocks)

return template.render({"data": data})


class ColorManager:
"""Color management for status report."""

def get_color(self, level: TestStatus) -> str:
"""Return the color attributed to the status in RICH_COLOR_THEME.
Args:
level (TestStatus): The status to colorized
Returns:
str: the colors attributed to this or empty string
"""
return RICH_COLOR_THEME.get(level, "")

def style_rich(self, level: TestStatus) -> Text:
"""
Build a rich Text syntax with color
Args:
level (TestStatus): The status to colorized
Returns:
Text: object with level string and its associated color.
"""
return Text(level, style=self.get_color(level))

def string(self, level: TestStatus) -> str:
"""
Build an str with color code
Args:
level (TestStatus): The status to colorized
Returns:
str: String with level and its associated color
"""
color = self.get_color(level)
return f"[{color}]{level}" if color != "" else str(level)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ render_collapsed = true
filterwarnings = [
"ignore::urllib3.exceptions.InsecureRequestWarning"
]
testpaths = ["tests"]

[tool.coverage.run]
branch = true
Expand Down
6 changes: 6 additions & 0 deletions tests/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@ def default_anta_env() -> dict[str, str]:
"ANTA_INVENTORY": str(Path(__file__).parent.parent / "data" / "test_inventory.yml"),
"ANTA_NRFU_CATALOG": str(Path(__file__).parent.parent / "data" / "test_catalog.yml"),
}


class FakeEAPIException(Exception):
"""
Dummy exception for the tests
"""
11 changes: 2 additions & 9 deletions tests/units/cli/debug/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"""
Tests for anta.cli.debug.commands
"""

from __future__ import annotations

from contextlib import nullcontext
Expand All @@ -18,7 +17,7 @@
from anta.cli.debug.commands import get_device
from anta.device import AntaDevice
from anta.models import AntaCommand
from tests.lib.utils import default_anta_env
from tests.lib.utils import FakeEAPIException, default_anta_env

if TYPE_CHECKING:
from click.testing import CliRunner
Expand Down Expand Up @@ -49,12 +48,6 @@ def test_get_device(test_inventory: AntaInventory, device_name: str, expected_ra
assert isinstance(result, AntaDevice)


class TestEAPIException(Exception):
"""
Dummy exception for the tests
"""


# TODO complete test cases
@pytest.mark.parametrize(
"command, ofmt, version, revision, device, failed",
Expand Down Expand Up @@ -99,7 +92,7 @@ def test_run_cmd(
# failed
expected_failed = None
if failed:
expected_failed = TestEAPIException("Command failed to run")
expected_failed = FakeEAPIException("Command failed to run")

# exit code
expected_exit_code = 1 if failed else 0
Expand Down
112 changes: 112 additions & 0 deletions tests/units/reporter/test__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
"""
from __future__ import annotations

from typing import Callable

import pytest
from rich.table import Table

from anta import RICH_COLOR_PALETTE
from anta.custom_types import TestStatus
from anta.reporter import ReportTable
from anta.result_manager import ResultManager


class Test_ReportTable:
Expand Down Expand Up @@ -79,3 +82,112 @@ def test__color_result(self, status: TestStatus, expected_status: str) -> None:
# pylint: disable=protected-access
report = ReportTable()
assert report._color_result(status) == expected_status

@pytest.mark.parametrize(
"host, testcase, title, number_of_tests, expected_length",
[
pytest.param(None, None, None, 5, 5, id="all results"),
pytest.param("host1", None, None, 5, 0, id="result for host1 when no host1 test"),
pytest.param(None, "VerifyTest3", None, 5, 1, id="result for test VerifyTest3"),
pytest.param(None, None, "Custom title", 5, 5, id="Change table title"),
],
)
def test_report_all(
self,
result_manager_factory: Callable[[int], ResultManager],
host: str | None,
testcase: str | None,
title: str | None,
number_of_tests: int,
expected_length: int,
) -> None:
"""
test report_all
"""
# pylint: disable=too-many-arguments
rm = result_manager_factory(number_of_tests)

report = ReportTable()
kwargs = {"host": host, "testcase": testcase, "title": title}
kwargs = {k: v for k, v in kwargs.items() if v is not None}
res = report.report_all(rm, **kwargs) # type: ignore[arg-type]

assert isinstance(res, Table)
assert res.title == (title or "All tests results")
assert res.row_count == expected_length

@pytest.mark.parametrize(
"testcase, title, number_of_tests, expected_length",
[
pytest.param(None, None, 5, 5, id="all results"),
pytest.param("VerifyTest3", None, 5, 1, id="result for test VerifyTest3"),
pytest.param(None, "Custom title", 5, 5, id="Change table title"),
],
)
def test_report_summary_tests(
self,
result_manager_factory: Callable[[int], ResultManager],
testcase: str | None,
title: str | None,
number_of_tests: int,
expected_length: int,
) -> None:
"""
test report_summary_tests
"""
# pylint: disable=too-many-arguments
# TODO refactor this later... this is injecting double test results by modyfing the device name
# should be a fixture
rm = result_manager_factory(number_of_tests)
new_results = [result.model_copy() for result in rm.get_results()]
for result in new_results:
result.name = "test_device"
result.result = "failure"
rm.add_test_results(new_results)

report = ReportTable()
kwargs = {"testcase": testcase, "title": title}
kwargs = {k: v for k, v in kwargs.items() if v is not None}
res = report.report_summary_tests(rm, **kwargs) # type: ignore[arg-type]

assert isinstance(res, Table)
assert res.title == (title or "Summary per test case")
assert res.row_count == expected_length

@pytest.mark.parametrize(
"host, title, number_of_tests, expected_length",
[
pytest.param(None, None, 5, 2, id="all results"),
pytest.param("host1", None, 5, 1, id="result for host host1"),
pytest.param(None, "Custom title", 5, 2, id="Change table title"),
],
)
def test_report_summary_hosts(
self,
result_manager_factory: Callable[[int], ResultManager],
host: str | None,
title: str | None,
number_of_tests: int,
expected_length: int,
) -> None:
"""
test report_summary_hosts
"""
# pylint: disable=too-many-arguments
# TODO refactor this later... this is injecting double test results by modyfing the device name
# should be a fixture
rm = result_manager_factory(number_of_tests)
new_results = [result.model_copy() for result in rm.get_results()]
for result in new_results:
result.name = host or "test_device"
result.result = "failure"
rm.add_test_results(new_results)

report = ReportTable()
kwargs = {"host": host, "title": title}
kwargs = {k: v for k, v in kwargs.items() if v is not None}
res = report.report_summary_hosts(rm, **kwargs) # type: ignore[arg-type]

assert isinstance(res, Table)
assert res.title == (title or "Summary per host")
assert res.row_count == expected_length
6 changes: 4 additions & 2 deletions tests/units/result_manager/test__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

import json
from contextlib import nullcontext
from typing import Any, Callable
from typing import TYPE_CHECKING, Any, Callable

import pytest

from anta.custom_types import TestStatus
from anta.result_manager import ResultManager
from anta.result_manager.models import TestResult

if TYPE_CHECKING:
from anta.result_manager.models import TestResult


class Test_ResultManager:
Expand Down

0 comments on commit b75bcc3

Please sign in to comment.