Adding upstream version 1.1.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f13b7abbd8
commit
77504588ab
196 changed files with 10121 additions and 3780 deletions
|
@ -1,4 +1,33 @@
|
|||
# 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 for anta.tests submodule."""
|
||||
"""Tests for anta.tests module."""
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from anta.device import AntaDevice
|
||||
|
||||
|
||||
def test(device: AntaDevice, data: dict[str, Any]) -> None:
|
||||
"""Generic test function for AntaTest subclass.
|
||||
|
||||
Generate unit tests for each AntaTest subclass.
|
||||
|
||||
See `tests/units/anta_tests/README.md` for more information on how to use it.
|
||||
"""
|
||||
# Instantiate the AntaTest subclass
|
||||
test_instance = data["test"](device, inputs=data["inputs"], eos_data=data["eos_data"])
|
||||
# Run the test() method
|
||||
asyncio.run(test_instance.test())
|
||||
# Assert expected result
|
||||
assert test_instance.result.result == data["expected"]["result"], f"Expected '{data['expected']['result']}' result, got '{test_instance.result.result}'"
|
||||
if "messages" in data["expected"]:
|
||||
# We expect messages in test result
|
||||
assert len(test_instance.result.messages) == len(data["expected"]["messages"])
|
||||
# Test will pass if the expected message is included in the test result message
|
||||
for message, expected in zip(test_instance.result.messages, data["expected"]["messages"]): # NOTE: zip(strict=True) has been added in Python 3.10
|
||||
assert expected in message
|
||||
else:
|
||||
# Test result should not have messages
|
||||
assert test_instance.result.messages == []
|
||||
|
|
35
tests/units/anta_tests/conftest.py
Normal file
35
tests/units/anta_tests/conftest.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# 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.
|
||||
"""See https://docs.pytest.org/en/stable/reference/fixtures.html#conftest-py-sharing-fixtures-across-multiple-files."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def build_test_id(val: dict[str, Any]) -> str:
|
||||
"""Build id for a unit test of an AntaTest subclass.
|
||||
|
||||
{
|
||||
"name": "meaniful test name",
|
||||
"test": <AntaTest instance>,
|
||||
...
|
||||
}
|
||||
"""
|
||||
return f"{val['test'].__module__}.{val['test'].__name__}-{val['name']}"
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
|
||||
"""Generate ANTA testts unit tests dynamically during test collection.
|
||||
|
||||
It will parametrize test cases based on the `DATA` data structure defined in `tests.units.anta_tests` modules.
|
||||
See `tests/units/anta_tests/README.md` for more information on how to use it.
|
||||
Test IDs are generated using the `build_test_id` function above.
|
||||
|
||||
Checking that only the function "test" is parametrized with data to allow for writing tests for helper functions
|
||||
in each module.
|
||||
"""
|
||||
if "tests.units.anta_tests" in metafunc.module.__package__ and metafunc.function.__name__ == "test":
|
||||
# This is a unit test for an AntaTest subclass
|
||||
metafunc.parametrize("data", metafunc.module.DATA, ids=build_test_id)
|
File diff suppressed because it is too large
Load diff
|
@ -5,10 +5,14 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from anta.tests.routing.generic import VerifyRoutingProtocolModel, VerifyRoutingTableEntry, VerifyRoutingTableSize
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -66,16 +70,6 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": {"minimum": 42, "maximum": 666},
|
||||
"expected": {"result": "failure", "messages": ["routing-table has 1000 routes and not between min (42) and maximum (666)"]},
|
||||
},
|
||||
{
|
||||
"name": "error-max-smaller-than-min",
|
||||
"test": VerifyRoutingTableSize,
|
||||
"eos_data": [{}],
|
||||
"inputs": {"minimum": 666, "maximum": 42},
|
||||
"expected": {
|
||||
"result": "error",
|
||||
"messages": ["Minimum 666 is greater than maximum 42"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyRoutingTableEntry,
|
||||
|
@ -130,6 +124,48 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"]},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-collect-all",
|
||||
"test": VerifyRoutingTableEntry,
|
||||
"eos_data": [
|
||||
{
|
||||
"vrfs": {
|
||||
"default": {
|
||||
"routingDisabled": False,
|
||||
"allRoutesProgrammedHardware": True,
|
||||
"allRoutesProgrammedKernel": True,
|
||||
"defaultRouteState": "notSet",
|
||||
"routes": {
|
||||
"10.1.0.1/32": {
|
||||
"hardwareProgrammed": True,
|
||||
"routeType": "eBGP",
|
||||
"routeLeaked": False,
|
||||
"kernelProgrammed": True,
|
||||
"routeAction": "forward",
|
||||
"directlyConnected": False,
|
||||
"preference": 20,
|
||||
"metric": 0,
|
||||
"vias": [{"nexthopAddr": "10.1.255.4", "interface": "Ethernet1"}],
|
||||
},
|
||||
"10.1.0.2/32": {
|
||||
"hardwareProgrammed": True,
|
||||
"routeType": "eBGP",
|
||||
"routeLeaked": False,
|
||||
"kernelProgrammed": True,
|
||||
"routeAction": "forward",
|
||||
"directlyConnected": False,
|
||||
"preference": 20,
|
||||
"metric": 0,
|
||||
"vias": [{"nexthopAddr": "10.1.255.6", "interface": "Ethernet2"}],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"], "collect": "all"},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-missing-route",
|
||||
"test": VerifyRoutingTableEntry,
|
||||
|
@ -226,4 +262,75 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"]},
|
||||
"expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.2']"]},
|
||||
},
|
||||
{
|
||||
"name": "failure-wrong-route-collect-all",
|
||||
"test": VerifyRoutingTableEntry,
|
||||
"eos_data": [
|
||||
{
|
||||
"vrfs": {
|
||||
"default": {
|
||||
"routingDisabled": False,
|
||||
"allRoutesProgrammedHardware": True,
|
||||
"allRoutesProgrammedKernel": True,
|
||||
"defaultRouteState": "notSet",
|
||||
"routes": {
|
||||
"10.1.0.1/32": {
|
||||
"hardwareProgrammed": True,
|
||||
"routeType": "eBGP",
|
||||
"routeLeaked": False,
|
||||
"kernelProgrammed": True,
|
||||
"routeAction": "forward",
|
||||
"directlyConnected": False,
|
||||
"preference": 20,
|
||||
"metric": 0,
|
||||
"vias": [{"nexthopAddr": "10.1.255.4", "interface": "Ethernet1"}],
|
||||
},
|
||||
"10.1.0.55/32": {
|
||||
"hardwareProgrammed": True,
|
||||
"routeType": "eBGP",
|
||||
"routeLeaked": False,
|
||||
"kernelProgrammed": True,
|
||||
"routeAction": "forward",
|
||||
"directlyConnected": False,
|
||||
"preference": 20,
|
||||
"metric": 0,
|
||||
"vias": [{"nexthopAddr": "10.1.255.6", "interface": "Ethernet2"}],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"], "collect": "all"},
|
||||
"expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.2']"]},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class TestVerifyRoutingTableSizeInputs:
|
||||
"""Test anta.tests.routing.generic.VerifyRoutingTableSize.Input."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("minimum", "maximum"),
|
||||
[
|
||||
pytest.param(0, 0, id="zero"),
|
||||
pytest.param(1, 2, id="1<2"),
|
||||
pytest.param(0, sys.maxsize, id="max"),
|
||||
],
|
||||
)
|
||||
def test_valid(self, minimum: int, maximum: int) -> None:
|
||||
"""Test VerifyRoutingTableSize valid inputs."""
|
||||
VerifyRoutingTableSize.Input(minimum=minimum, maximum=maximum)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("minimum", "maximum"),
|
||||
[
|
||||
pytest.param(-2, -1, id="negative"),
|
||||
pytest.param(2, 1, id="2<1"),
|
||||
pytest.param(sys.maxsize, 0, id="max"),
|
||||
],
|
||||
)
|
||||
def test_invalid(self, minimum: int, maximum: int) -> None:
|
||||
"""Test VerifyRoutingTableSize invalid inputs."""
|
||||
with pytest.raises(ValidationError):
|
||||
VerifyRoutingTableSize.Input(minimum=minimum, maximum=maximum)
|
||||
|
|
|
@ -20,7 +20,7 @@ from anta.tests.routing.isis import (
|
|||
VerifyISISSegmentRoutingTunnels,
|
||||
_get_interface_data,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.routing.ospf import VerifyOSPFMaxLSA, VerifyOSPFNeighborCount, VerifyOSPFNeighborState
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ from anta.tests.aaa import (
|
|||
VerifyTacacsServers,
|
||||
VerifyTacacsSourceIntf,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.avt import VerifyAVTPathHealth, VerifyAVTRole, VerifyAVTSpecificPath
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,10 +8,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
# pylint: disable=C0413
|
||||
# because of the patch above
|
||||
from anta.tests.bfd import VerifyBFDPeersHealth, VerifyBFDPeersIntervals, VerifyBFDSpecificPeers
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from anta.tests.bfd import VerifyBFDPeersHealth, VerifyBFDPeersIntervals, VerifyBFDPeersRegProtocols, VerifyBFDSpecificPeers
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -163,8 +161,8 @@ DATA: list[dict[str, Any]] = [
|
|||
"result": "failure",
|
||||
"messages": [
|
||||
"Following BFD peers are not configured or timers are not correct:\n"
|
||||
"{'192.0.255.7': {'default': {'tx_interval': 1300000, 'rx_interval': 1200000, 'multiplier': 4}}, "
|
||||
"'192.0.255.70': {'MGMT': {'tx_interval': 120000, 'rx_interval': 120000, 'multiplier': 5}}}"
|
||||
"{'192.0.255.7': {'default': {'tx_interval': 1300, 'rx_interval': 1200, 'multiplier': 4}}, "
|
||||
"'192.0.255.70': {'MGMT': {'tx_interval': 120, 'rx_interval': 120, 'multiplier': 5}}}"
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -519,4 +517,133 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyBFDPeersRegProtocols,
|
||||
"eos_data": [
|
||||
{
|
||||
"vrfs": {
|
||||
"default": {
|
||||
"ipv4Neighbors": {
|
||||
"192.0.255.7": {
|
||||
"peerStats": {
|
||||
"": {
|
||||
"status": "up",
|
||||
"remoteDisc": 108328132,
|
||||
"peerStatsDetail": {
|
||||
"role": "active",
|
||||
"apps": ["ospf"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"MGMT": {
|
||||
"ipv4Neighbors": {
|
||||
"192.0.255.70": {
|
||||
"peerStats": {
|
||||
"": {
|
||||
"status": "up",
|
||||
"remoteDisc": 108328132,
|
||||
"peerStatsDetail": {
|
||||
"role": "active",
|
||||
"apps": ["bgp"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"bfd_peers": [
|
||||
{"peer_address": "192.0.255.7", "vrf": "default", "protocols": ["ospf"]},
|
||||
{"peer_address": "192.0.255.70", "vrf": "MGMT", "protocols": ["bgp"]},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"test": VerifyBFDPeersRegProtocols,
|
||||
"eos_data": [
|
||||
{
|
||||
"vrfs": {
|
||||
"default": {
|
||||
"ipv4Neighbors": {
|
||||
"192.0.255.7": {
|
||||
"peerStats": {
|
||||
"": {
|
||||
"status": "up",
|
||||
"peerStatsDetail": {
|
||||
"role": "active",
|
||||
"apps": ["ospf"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"MGMT": {
|
||||
"ipv4Neighbors": {
|
||||
"192.0.255.70": {
|
||||
"peerStats": {
|
||||
"": {
|
||||
"status": "up",
|
||||
"remoteDisc": 0,
|
||||
"peerStatsDetail": {
|
||||
"role": "active",
|
||||
"apps": ["bgp"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"bfd_peers": [
|
||||
{"peer_address": "192.0.255.7", "vrf": "default", "protocols": ["isis"]},
|
||||
{"peer_address": "192.0.255.70", "vrf": "MGMT", "protocols": ["isis"]},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"The following BFD peers are not configured or have non-registered protocol(s):\n"
|
||||
"{'192.0.255.7': {'default': ['isis']}, "
|
||||
"'192.0.255.70': {'MGMT': ['isis']}}"
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-not-found",
|
||||
"test": VerifyBFDPeersRegProtocols,
|
||||
"eos_data": [
|
||||
{
|
||||
"vrfs": {
|
||||
"default": {},
|
||||
"MGMT": {},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"bfd_peers": [
|
||||
{"peer_address": "192.0.255.7", "vrf": "default", "protocols": ["isis"]},
|
||||
{"peer_address": "192.0.255.70", "vrf": "MGMT", "protocols": ["isis"]},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"The following BFD peers are not configured or have non-registered protocol(s):\n"
|
||||
"{'192.0.255.7': {'default': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}"
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.configuration import VerifyRunningConfigDiffs, VerifyRunningConfigLines, VerifyZeroTouch
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -60,14 +60,4 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": {"regex_patterns": ["bla", "bleh"]},
|
||||
"expected": {"result": "failure", "messages": ["Following patterns were not found: 'bla','bleh'"]},
|
||||
},
|
||||
{
|
||||
"name": "failure-invalid-regex",
|
||||
"test": VerifyRunningConfigLines,
|
||||
"eos_data": ["enable password something\nsome other line"],
|
||||
"inputs": {"regex_patterns": ["["]},
|
||||
"expected": {
|
||||
"result": "error",
|
||||
"messages": ["1 validation error for Input\nregex_patterns.0\n Value error, Invalid regex: unterminated character set at position 0"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.connectivity import VerifyLLDPNeighbors, VerifyReachability
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -99,6 +99,28 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-df-bit-size",
|
||||
"test": VerifyReachability,
|
||||
"inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0", "repeat": 5, "size": 1500, "df_bit": True}]},
|
||||
"eos_data": [
|
||||
{
|
||||
"messages": [
|
||||
"""PING 10.0.0.1 (10.0.0.1) from 172.20.20.6 : 1472(1500) bytes of data.
|
||||
1480 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.085 ms
|
||||
1480 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.020 ms
|
||||
1480 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.019 ms
|
||||
1480 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=0.018 ms
|
||||
1480 bytes from 10.0.0.1: icmp_seq=5 ttl=64 time=0.017 ms
|
||||
|
||||
--- 10.0.0.1 ping statistics ---
|
||||
5 packets transmitted, 5 received, 0% packet loss, time 0ms
|
||||
rtt min/avg/max/mdev = 0.017/0.031/0.085/0.026 ms, ipg/ewma 0.061/0.057 ms""",
|
||||
],
|
||||
},
|
||||
],
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-ip",
|
||||
"test": VerifyReachability,
|
||||
|
@ -167,6 +189,28 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
"expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('Management0', '10.0.0.11')]"]},
|
||||
},
|
||||
{
|
||||
"name": "failure-size",
|
||||
"test": VerifyReachability,
|
||||
"inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0", "repeat": 5, "size": 1501, "df_bit": True}]},
|
||||
"eos_data": [
|
||||
{
|
||||
"messages": [
|
||||
"""PING 10.0.0.1 (10.0.0.1) from 172.20.20.6 : 1473(1501) bytes of data.
|
||||
ping: local error: message too long, mtu=1500
|
||||
ping: local error: message too long, mtu=1500
|
||||
ping: local error: message too long, mtu=1500
|
||||
ping: local error: message too long, mtu=1500
|
||||
ping: local error: message too long, mtu=1500
|
||||
|
||||
--- 10.0.0.1 ping statistics ---
|
||||
5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 40ms
|
||||
""",
|
||||
],
|
||||
},
|
||||
],
|
||||
"expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('Management0', '10.0.0.1')]"]},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyLLDPNeighbors,
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.field_notices import VerifyFieldNotice44Resolution, VerifyFieldNotice72Resolution
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -358,8 +358,8 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
"inputs": None,
|
||||
"expected": {
|
||||
"result": "error",
|
||||
"messages": ["Error in running test - FixedSystemvrm1 not found"],
|
||||
"result": "failure",
|
||||
"messages": ["Error in running test - Component FixedSystemvrm1 not found in 'show version'"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
391
tests/units/anta_tests/test_flow_tracking.py
Normal file
391
tests/units/anta_tests/test_flow_tracking.py
Normal file
|
@ -0,0 +1,391 @@
|
|||
# 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 inputs for anta.tests.flow_tracking."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from anta.tests.flow_tracking import VerifyHardwareFlowTrackerStatus
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {"trackers": [{"name": "FLOW-TRACKER"}, {"name": "HARDWARE-TRACKER"}]},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-with-optional-field",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {
|
||||
"trackers": [
|
||||
{
|
||||
"name": "FLOW-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
"exporters": [{"name": "CV-TELEMETRY", "local_interface": "Loopback0", "template_interval": 3600000}],
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
"exporters": [{"name": "CVP-TELEMETRY", "local_interface": "Loopback10", "template_interval": 3600000}],
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-flow-tracking-not-running",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [{"trackers": {}, "running": False}],
|
||||
"inputs": {"trackers": [{"name": "FLOW-TRACKER"}]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["Hardware flow tracking is not running."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-tracker-not-configured",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
}
|
||||
],
|
||||
"inputs": {"trackers": [{"name": "FLOW-Sample"}]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["Hardware flow tracker `FLOW-Sample` is not configured."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-tracker-not-active",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER": {
|
||||
"active": False,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": False,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {
|
||||
"trackers": [
|
||||
{
|
||||
"name": "FLOW-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
"exporters": [{"name": "CV-TELEMETRY", "local_interface": "Loopback0", "template_interval": 3600000}],
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
"exporters": [{"name": "CVP-TELEMETRY", "local_interface": "Loopback10", "template_interval": 3600000}],
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["Hardware flow tracker `FLOW-TRACKER` is not active.", "Hardware flow tracker `HARDWARE-TRACKER` is not active."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-incorrect-record-export",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 6000,
|
||||
"activeInterval": 30000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {
|
||||
"trackers": [
|
||||
{
|
||||
"name": "FLOW-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 6000, "on_interval": 30000},
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-TRACKER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"FLOW-TRACKER: \n"
|
||||
"Expected `6000` as the inactive timeout, but found `60000` instead.\nExpected `30000` as the interval, but found `300000` instead.\n",
|
||||
"HARDWARE-TRACKER: \n"
|
||||
"Expected `60000` as the inactive timeout, but found `6000` instead.\nExpected `300000` as the interval, but found `30000` instead.\n",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-incorrect-exporters",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {
|
||||
"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000},
|
||||
"CVP-FLOW": {"localIntf": "Loopback0", "templateInterval": 3600000},
|
||||
},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 6000,
|
||||
"activeInterval": 30000,
|
||||
"exporters": {
|
||||
"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000},
|
||||
"Hardware-flow": {"localIntf": "Loopback10", "templateInterval": 3600000},
|
||||
},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {
|
||||
"trackers": [
|
||||
{
|
||||
"name": "FLOW-TRACKER",
|
||||
"exporters": [
|
||||
{"name": "CV-TELEMETRY", "local_interface": "Loopback0", "template_interval": 3600000},
|
||||
{"name": "CVP-FLOW", "local_interface": "Loopback10", "template_interval": 3500000},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-TRACKER",
|
||||
"exporters": [
|
||||
{"name": "Hardware-flow", "local_interface": "Loopback99", "template_interval": 3000000},
|
||||
{"name": "Reverse-flow", "local_interface": "Loopback101", "template_interval": 3000000},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"FLOW-TRACKER: \n"
|
||||
"Exporter `CVP-FLOW`: \n"
|
||||
"Expected `Loopback10` as the local interface, but found `Loopback0` instead.\n"
|
||||
"Expected `3500000` as the template interval, but found `3600000` instead.\n",
|
||||
"HARDWARE-TRACKER: \n"
|
||||
"Exporter `Hardware-flow`: \n"
|
||||
"Expected `Loopback99` as the local interface, but found `Loopback10` instead.\n"
|
||||
"Expected `3000000` as the template interval, but found `3600000` instead.\n"
|
||||
"Exporter `Reverse-flow` is not configured.\n",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-all-type",
|
||||
"test": VerifyHardwareFlowTrackerStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRIGGER": {
|
||||
"active": False,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-FLOW": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 6000,
|
||||
"activeInterval": 30000,
|
||||
"exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"FLOW-TRACKER2": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 60000,
|
||||
"activeInterval": 300000,
|
||||
"exporters": {
|
||||
"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000},
|
||||
"CVP-FLOW": {"localIntf": "Loopback0", "templateInterval": 3600000},
|
||||
},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
{
|
||||
"trackers": {
|
||||
"HARDWARE-TRACKER2": {
|
||||
"active": True,
|
||||
"inactiveTimeout": 6000,
|
||||
"activeInterval": 30000,
|
||||
"exporters": {
|
||||
"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000},
|
||||
"Hardware-flow": {"localIntf": "Loopback10", "templateInterval": 3600000},
|
||||
},
|
||||
}
|
||||
},
|
||||
"running": True,
|
||||
},
|
||||
],
|
||||
"inputs": {
|
||||
"trackers": [
|
||||
{"name": "FLOW-Sample"},
|
||||
{
|
||||
"name": "FLOW-TRIGGER",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
"exporters": [{"name": "CV-TELEMETRY", "local_interface": "Loopback0", "template_interval": 3600000}],
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-FLOW",
|
||||
"record_export": {"on_inactive_timeout": 60000, "on_interval": 300000},
|
||||
},
|
||||
{
|
||||
"name": "FLOW-TRACKER2",
|
||||
"exporters": [
|
||||
{"name": "CV-TELEMETRY", "local_interface": "Loopback0", "template_interval": 3600000},
|
||||
{"name": "CVP-FLOW", "local_interface": "Loopback10", "template_interval": 3500000},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HARDWARE-TRACKER2",
|
||||
"exporters": [
|
||||
{"name": "Hardware-flow", "local_interface": "Loopback99", "template_interval": 3000000},
|
||||
{"name": "Reverse-flow", "local_interface": "Loopback101", "template_interval": 3000000},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"Hardware flow tracker `FLOW-Sample` is not configured.",
|
||||
"Hardware flow tracker `FLOW-TRIGGER` is not active.",
|
||||
"HARDWARE-FLOW: \n"
|
||||
"Expected `60000` as the inactive timeout, but found `6000` instead.\nExpected `300000` as the interval, but found `30000` instead.\n",
|
||||
"FLOW-TRACKER2: \nExporter `CVP-FLOW`: \n"
|
||||
"Expected `Loopback10` as the local interface, but found `Loopback0` instead.\n"
|
||||
"Expected `3500000` as the template interval, but found `3600000` instead.\n",
|
||||
"HARDWARE-TRACKER2: \nExporter `Hardware-flow`: \n"
|
||||
"Expected `Loopback99` as the local interface, but found `Loopback10` instead.\n"
|
||||
"Expected `3000000` as the template interval, but found `3600000` instead.\n"
|
||||
"Exporter `Reverse-flow` is not configured.\n",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.greent import VerifyGreenT, VerifyGreenTCounters
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ from anta.tests.hardware import (
|
|||
VerifyTransceiversManufacturers,
|
||||
VerifyTransceiversTemperature,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -21,12 +21,13 @@ from anta.tests.interfaces import (
|
|||
VerifyIpVirtualRouterMac,
|
||||
VerifyL2MTU,
|
||||
VerifyL3MTU,
|
||||
VerifyLACPInterfacesStatus,
|
||||
VerifyLoopbackCount,
|
||||
VerifyPortChannels,
|
||||
VerifyStormControlDrops,
|
||||
VerifySVI,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -651,7 +652,7 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
"inputs": {"threshold": 70.0},
|
||||
"expected": {
|
||||
"result": "error",
|
||||
"result": "failure",
|
||||
"messages": ["Interface Ethernet1/1 or one of its member interfaces is not Full-Duplex. VerifyInterfaceUtilization has not been implemented."],
|
||||
},
|
||||
},
|
||||
|
@ -796,7 +797,7 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
"inputs": {"threshold": 70.0},
|
||||
"expected": {
|
||||
"result": "error",
|
||||
"result": "failure",
|
||||
"messages": ["Interface Port-Channel31 or one of its member interfaces is not Full-Duplex. VerifyInterfaceUtilization has not been implemented."],
|
||||
},
|
||||
},
|
||||
|
@ -2441,4 +2442,127 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyLACPInterfacesStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"portChannels": {
|
||||
"Port-Channel5": {
|
||||
"interfaces": {
|
||||
"Ethernet5": {
|
||||
"actorPortStatus": "bundled",
|
||||
"partnerPortState": {
|
||||
"activity": True,
|
||||
"timeout": False,
|
||||
"aggregation": True,
|
||||
"synchronization": True,
|
||||
"collecting": True,
|
||||
"distributing": True,
|
||||
},
|
||||
"actorPortState": {
|
||||
"activity": True,
|
||||
"timeout": False,
|
||||
"aggregation": True,
|
||||
"synchronization": True,
|
||||
"collecting": True,
|
||||
"distributing": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface": "Ethernet5",
|
||||
"orphanPorts": {},
|
||||
}
|
||||
],
|
||||
"inputs": {"interfaces": [{"name": "Ethernet5", "portchannel": "Port-Channel5"}]},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-not-bundled",
|
||||
"test": VerifyLACPInterfacesStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"portChannels": {
|
||||
"Port-Channel5": {
|
||||
"interfaces": {
|
||||
"Ethernet5": {
|
||||
"actorPortStatus": "No Aggregate",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface": "Ethernet5",
|
||||
"orphanPorts": {},
|
||||
}
|
||||
],
|
||||
"inputs": {"interfaces": [{"name": "Ethernet5", "portchannel": "Po5"}]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["For Interface Ethernet5:\nExpected `bundled` as the local port status, but found `No Aggregate` instead.\n"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-no-details-found",
|
||||
"test": VerifyLACPInterfacesStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"portChannels": {"Port-Channel5": {"interfaces": {}}},
|
||||
}
|
||||
],
|
||||
"inputs": {"interfaces": [{"name": "Ethernet5", "portchannel": "Po 5"}]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["Interface 'Ethernet5' is not configured to be a member of LACP 'Port-Channel5'."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-lacp-params",
|
||||
"test": VerifyLACPInterfacesStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
"portChannels": {
|
||||
"Port-Channel5": {
|
||||
"interfaces": {
|
||||
"Ethernet5": {
|
||||
"actorPortStatus": "bundled",
|
||||
"partnerPortState": {
|
||||
"activity": False,
|
||||
"timeout": False,
|
||||
"aggregation": False,
|
||||
"synchronization": False,
|
||||
"collecting": True,
|
||||
"distributing": True,
|
||||
},
|
||||
"actorPortState": {
|
||||
"activity": False,
|
||||
"timeout": False,
|
||||
"aggregation": False,
|
||||
"synchronization": False,
|
||||
"collecting": True,
|
||||
"distributing": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface": "Ethernet5",
|
||||
"orphanPorts": {},
|
||||
}
|
||||
],
|
||||
"inputs": {"interfaces": [{"name": "Ethernet5", "portchannel": "port-channel 5"}]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"For Interface Ethernet5:\n"
|
||||
"Actor port details:\nExpected `True` as the activity, but found `False` instead."
|
||||
"\nExpected `True` as the aggregation, but found `False` instead."
|
||||
"\nExpected `True` as the synchronization, but found `False` instead."
|
||||
"\nPartner port details:\nExpected `True` as the activity, but found `False` instead.\n"
|
||||
"Expected `True` as the aggregation, but found `False` instead.\n"
|
||||
"Expected `True` as the synchronization, but found `False` instead.\n"
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.lanz import VerifyLANZ
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ from anta.tests.logging import (
|
|||
VerifyLoggingSourceIntf,
|
||||
VerifyLoggingTimestamp,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -201,7 +201,7 @@ DATA: list[dict[str, Any]] = [
|
|||
"expected": {"result": "failure", "messages": ["Logs are not generated with the device FQDN"]},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"name": "success-negative-offset",
|
||||
"test": VerifyLoggingTimestamp,
|
||||
"eos_data": [
|
||||
"",
|
||||
|
@ -213,6 +213,19 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": None,
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-positive-offset",
|
||||
"test": VerifyLoggingTimestamp,
|
||||
"eos_data": [
|
||||
"",
|
||||
"2023-05-10T15:41:44.680813+05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: "
|
||||
"Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingTimestamp validation\n"
|
||||
"2023-05-10T15:42:44.680813+05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: "
|
||||
"Other log\n",
|
||||
],
|
||||
"inputs": None,
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"test": VerifyLoggingTimestamp,
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.mlag import VerifyMlagConfigSanity, VerifyMlagDualPrimary, VerifyMlagInterfaces, VerifyMlagPrimaryPriority, VerifyMlagReloadDelay, VerifyMlagStatus
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -110,17 +110,6 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": None,
|
||||
"expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"test": VerifyMlagConfigSanity,
|
||||
"eos_data": [
|
||||
{
|
||||
"dummy": False,
|
||||
},
|
||||
],
|
||||
"inputs": None,
|
||||
"expected": {"result": "error", "messages": ["Incorrect JSON response - 'mlagActive' state was not found"]},
|
||||
},
|
||||
{
|
||||
"name": "failure-global",
|
||||
"test": VerifyMlagConfigSanity,
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.multicast import VerifyIGMPSnoopingGlobal, VerifyIGMPSnoopingVlans
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.path_selection import VerifyPathsHealth, VerifySpecificPath
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.profiles import VerifyTcamProfile, VerifyUnifiedForwardingTableMode
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.ptp import VerifyPtpGMStatus, VerifyPtpLockStatus, VerifyPtpModeStatus, VerifyPtpOffset, VerifyPtpPortModeStatus
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -295,14 +295,14 @@ DATA: list[dict[str, Any]] = [
|
|||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"name": "failure-no-interfaces",
|
||||
"test": VerifyPtpPortModeStatus,
|
||||
"eos_data": [{"ptpIntfSummaries": {}}],
|
||||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["No interfaces are PTP enabled"]},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"name": "failure-invalid-state",
|
||||
"test": VerifyPtpPortModeStatus,
|
||||
"eos_data": [
|
||||
{
|
||||
|
|
|
@ -7,6 +7,9 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from anta.tests.security import (
|
||||
VerifyAPIHttpsSSL,
|
||||
VerifyAPIHttpStatus,
|
||||
|
@ -15,6 +18,7 @@ from anta.tests.security import (
|
|||
VerifyAPISSLCertificate,
|
||||
VerifyBannerLogin,
|
||||
VerifyBannerMotd,
|
||||
VerifyHardwareEntropy,
|
||||
VerifyIPSecConnHealth,
|
||||
VerifyIPv4ACL,
|
||||
VerifySpecificIPSecConn,
|
||||
|
@ -23,7 +27,7 @@ from anta.tests.security import (
|
|||
VerifySSHStatus,
|
||||
VerifyTelnetStatus,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -38,15 +42,35 @@ DATA: list[dict[str, Any]] = [
|
|||
"test": VerifySSHStatus,
|
||||
"eos_data": ["SSH per host connection limit is 20\nFIPS status: disabled\n\n"],
|
||||
"inputs": None,
|
||||
"expected": {"result": "error", "messages": ["Could not find SSH status in returned output."]},
|
||||
"expected": {"result": "failure", "messages": ["Could not find SSH status in returned output."]},
|
||||
},
|
||||
{
|
||||
"name": "failure-ssh-disabled",
|
||||
"name": "failure-ssh-enabled",
|
||||
"test": VerifySSHStatus,
|
||||
"eos_data": ["SSHD status for Default VRF is enabled\nSSH connection limit is 50\nSSH per host connection limit is 20\nFIPS status: disabled\n\n"],
|
||||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["SSHD status for Default VRF is enabled"]},
|
||||
},
|
||||
{
|
||||
"name": "success-4.32",
|
||||
"test": VerifySSHStatus,
|
||||
"eos_data": [
|
||||
"User certificate authentication methods: none (neither trusted CA nor SSL profile configured)\n"
|
||||
"SSHD status for Default VRF: disabled\nSSH connection limit: 50\nSSH per host connection limit: 20\nFIPS status: disabled\n\n"
|
||||
],
|
||||
"inputs": None,
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-ssh-enabled-4.32",
|
||||
"test": VerifySSHStatus,
|
||||
"eos_data": [
|
||||
"User certificate authentication methods: none (neither trusted CA nor SSL profile configured)\n"
|
||||
"SSHD status for Default VRF: enabled\nSSH connection limit: 50\nSSH per host connection limit: 20\nFIPS status: disabled\n\n"
|
||||
],
|
||||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["SSHD status for Default VRF: enabled"]},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifySSHIPv4Acl,
|
||||
|
@ -580,40 +604,6 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "error-wrong-input-rsa",
|
||||
"test": VerifyAPISSLCertificate,
|
||||
"eos_data": [],
|
||||
"inputs": {
|
||||
"certificates": [
|
||||
{
|
||||
"certificate_name": "ARISTA_ROOT_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "Arista Networks Internal IT Root Cert Authority",
|
||||
"encryption_algorithm": "RSA",
|
||||
"key_size": 256,
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "error", "messages": ["Allowed sizes are (2048, 3072, 4096)."]},
|
||||
},
|
||||
{
|
||||
"name": "error-wrong-input-ecdsa",
|
||||
"test": VerifyAPISSLCertificate,
|
||||
"eos_data": [],
|
||||
"inputs": {
|
||||
"certificates": [
|
||||
{
|
||||
"certificate_name": "ARISTA_SIGNING_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
|
||||
"encryption_algorithm": "ECDSA",
|
||||
"key_size": 2048,
|
||||
},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "error", "messages": ["Allowed sizes are (256, 384, 512)."]},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyBannerLogin,
|
||||
|
@ -1213,4 +1203,84 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyHardwareEntropy,
|
||||
"eos_data": [{"cpuModel": "2.20GHz", "cryptoModule": "Crypto Module v3.0", "hardwareEntropyEnabled": True, "blockedNetworkProtocols": []}],
|
||||
"inputs": {},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"test": VerifyHardwareEntropy,
|
||||
"eos_data": [{"cpuModel": "2.20GHz", "cryptoModule": "Crypto Module v3.0", "hardwareEntropyEnabled": False, "blockedNetworkProtocols": []}],
|
||||
"inputs": {},
|
||||
"expected": {"result": "failure", "messages": ["Hardware entropy generation is disabled."]},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class TestAPISSLCertificate:
|
||||
"""Test anta.tests.security.VerifyAPISSLCertificate.Input.APISSLCertificate."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model_params", "error"),
|
||||
[
|
||||
pytest.param(
|
||||
{
|
||||
"certificate_name": "ARISTA_ROOT_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "Arista Networks Internal IT Root Cert Authority",
|
||||
"encryption_algorithm": "RSA",
|
||||
"key_size": 256,
|
||||
},
|
||||
"Value error, `ARISTA_ROOT_CA.crt` key size 256 is invalid for RSA encryption. Allowed sizes are (2048, 3072, 4096).",
|
||||
id="RSA_wrong_size",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"certificate_name": "ARISTA_SIGNING_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
|
||||
"encryption_algorithm": "ECDSA",
|
||||
"key_size": 2048,
|
||||
},
|
||||
"Value error, `ARISTA_SIGNING_CA.crt` key size 2048 is invalid for ECDSA encryption. Allowed sizes are (256, 384, 512).",
|
||||
id="ECDSA_wrong_size",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid(self, model_params: dict[str, Any], error: str) -> None:
|
||||
"""Test invalid inputs for anta.tests.security.VerifyAPISSLCertificate.Input.APISSLCertificate."""
|
||||
with pytest.raises(ValidationError) as exec_info:
|
||||
VerifyAPISSLCertificate.Input.APISSLCertificate.model_validate(model_params)
|
||||
assert error == exec_info.value.errors()[0]["msg"]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model_params",
|
||||
[
|
||||
pytest.param(
|
||||
{
|
||||
"certificate_name": "ARISTA_SIGNING_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
|
||||
"encryption_algorithm": "ECDSA",
|
||||
"key_size": 256,
|
||||
},
|
||||
id="ECDSA",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"certificate_name": "ARISTA_ROOT_CA.crt",
|
||||
"expiry_threshold": 30,
|
||||
"common_name": "Arista Networks Internal IT Root Cert Authority",
|
||||
"encryption_algorithm": "RSA",
|
||||
"key_size": 4096,
|
||||
},
|
||||
id="RSA",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_valid(self, model_params: dict[str, Any]) -> None:
|
||||
"""Test valid inputs for anta.tests.security.VerifyAPISSLCertificate.Input.APISSLCertificate."""
|
||||
VerifyAPISSLCertificate.Input.APISSLCertificate.model_validate(model_params)
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.services import VerifyDNSLookup, VerifyDNSServers, VerifyErrdisableRecovery, VerifyHostname
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -7,8 +7,16 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
from anta.tests.snmp import VerifySnmpContact, VerifySnmpIPv4Acl, VerifySnmpIPv6Acl, VerifySnmpLocation, VerifySnmpStatus
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from anta.tests.snmp import (
|
||||
VerifySnmpContact,
|
||||
VerifySnmpErrorCounters,
|
||||
VerifySnmpIPv4Acl,
|
||||
VerifySnmpIPv6Acl,
|
||||
VerifySnmpLocation,
|
||||
VerifySnmpPDUCounters,
|
||||
VerifySnmpStatus,
|
||||
)
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -99,6 +107,20 @@ DATA: list[dict[str, Any]] = [
|
|||
"messages": ["Expected `New York` as the location, but found `Europe` instead."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-details-not-configured",
|
||||
"test": VerifySnmpLocation,
|
||||
"eos_data": [
|
||||
{
|
||||
"location": {"location": ""},
|
||||
}
|
||||
],
|
||||
"inputs": {"location": "New York"},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["SNMP location is not configured."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifySnmpContact,
|
||||
|
@ -124,4 +146,177 @@ DATA: list[dict[str, Any]] = [
|
|||
"messages": ["Expected `Bob@example.com` as the contact, but found `Jon@example.com` instead."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-details-not-configured",
|
||||
"test": VerifySnmpContact,
|
||||
"eos_data": [
|
||||
{
|
||||
"contact": {"contact": ""},
|
||||
}
|
||||
],
|
||||
"inputs": {"contact": "Bob@example.com"},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["SNMP contact is not configured."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifySnmpPDUCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inGetPdus": 3,
|
||||
"inGetNextPdus": 2,
|
||||
"inSetPdus": 3,
|
||||
"outGetResponsePdus": 3,
|
||||
"outTrapPdus": 9,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-specific-pdus",
|
||||
"test": VerifySnmpPDUCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inGetPdus": 3,
|
||||
"inGetNextPdus": 0,
|
||||
"inSetPdus": 0,
|
||||
"outGetResponsePdus": 0,
|
||||
"outTrapPdus": 9,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {"pdus": ["inGetPdus", "outTrapPdus"]},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-counters-not-found",
|
||||
"test": VerifySnmpPDUCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {"result": "failure", "messages": ["SNMP counters not found."]},
|
||||
},
|
||||
{
|
||||
"name": "failure-incorrect-counters",
|
||||
"test": VerifySnmpPDUCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inGetPdus": 0,
|
||||
"inGetNextPdus": 2,
|
||||
"inSetPdus": 0,
|
||||
"outGetResponsePdus": 3,
|
||||
"outTrapPdus": 9,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["The following SNMP PDU counters are not found or have zero PDU counters:\n{'inGetPdus': 0, 'inSetPdus': 0}"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-pdu-not-found",
|
||||
"test": VerifySnmpPDUCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inGetNextPdus": 0,
|
||||
"inSetPdus": 0,
|
||||
"outGetResponsePdus": 0,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {"pdus": ["inGetPdus", "outTrapPdus"]},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["The following SNMP PDU counters are not found or have zero PDU counters:\n{'inGetPdus': 'Not Found', 'outTrapPdus': 'Not Found'}"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifySnmpErrorCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inVersionErrs": 0,
|
||||
"inBadCommunityNames": 0,
|
||||
"inBadCommunityUses": 0,
|
||||
"inParseErrs": 0,
|
||||
"outTooBigErrs": 0,
|
||||
"outNoSuchNameErrs": 0,
|
||||
"outBadValueErrs": 0,
|
||||
"outGeneralErrs": 0,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-specific-counters",
|
||||
"test": VerifySnmpErrorCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inVersionErrs": 0,
|
||||
"inBadCommunityNames": 0,
|
||||
"inBadCommunityUses": 0,
|
||||
"inParseErrs": 0,
|
||||
"outTooBigErrs": 5,
|
||||
"outNoSuchNameErrs": 0,
|
||||
"outBadValueErrs": 10,
|
||||
"outGeneralErrs": 1,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {"error_counters": ["inVersionErrs", "inParseErrs"]},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-counters-not-found",
|
||||
"test": VerifySnmpErrorCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {"result": "failure", "messages": ["SNMP counters not found."]},
|
||||
},
|
||||
{
|
||||
"name": "failure-incorrect-counters",
|
||||
"test": VerifySnmpErrorCounters,
|
||||
"eos_data": [
|
||||
{
|
||||
"counters": {
|
||||
"inVersionErrs": 1,
|
||||
"inBadCommunityNames": 0,
|
||||
"inBadCommunityUses": 0,
|
||||
"inParseErrs": 2,
|
||||
"outTooBigErrs": 0,
|
||||
"outNoSuchNameErrs": 0,
|
||||
"outBadValueErrs": 2,
|
||||
"outGeneralErrs": 0,
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"The following SNMP error counters are not found or have non-zero error counters:\n{'inVersionErrs': 1, 'inParseErrs': 2, 'outBadValueErrs': 2}"
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.software import VerifyEOSExtensions, VerifyEOSVersion, VerifyTerminAttrVersion
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
from anta.tests.stp import VerifySTPBlockedPorts, VerifySTPCounters, VerifySTPForwardingPorts, VerifySTPMode, VerifySTPRootPriority
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from anta.tests.stp import VerifySTPBlockedPorts, VerifySTPCounters, VerifySTPForwardingPorts, VerifySTPMode, VerifySTPRootPriority, VerifyStpTopologyChanges
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -324,4 +324,166 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": {"priority": 32768, "instances": [10, 20, 30]},
|
||||
"expected": {"result": "failure", "messages": ["The following instance(s) have the wrong STP root priority configured: ['VL20', 'VL30']"]},
|
||||
},
|
||||
{
|
||||
"name": "success-mstp",
|
||||
"test": VerifyStpTopologyChanges,
|
||||
"eos_data": [
|
||||
{
|
||||
"unmappedVlans": [],
|
||||
"topologies": {
|
||||
"Cist": {
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.735365},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
},
|
||||
"NoStp": {
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.735365},
|
||||
"Ethernet1": {"state": "forwarding", "numChanges": 15, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"threshold": 10},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-rstp",
|
||||
"test": VerifyStpTopologyChanges,
|
||||
"eos_data": [
|
||||
{
|
||||
"unmappedVlans": [],
|
||||
"topologies": {
|
||||
"Cist": {
|
||||
"interfaces": {
|
||||
"Vxlan1": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.735365},
|
||||
"PeerEthernet3": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
},
|
||||
"NoStp": {
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.735365},
|
||||
"Ethernet1": {"state": "forwarding", "numChanges": 15, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"threshold": 10},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-rapid-pvst",
|
||||
"test": VerifyStpTopologyChanges,
|
||||
"eos_data": [
|
||||
{
|
||||
"unmappedVlans": [],
|
||||
"topologies": {
|
||||
"NoStp": {
|
||||
"vlans": [4094, 4093, 1006],
|
||||
"interfaces": {
|
||||
"PeerEthernet2": {"state": "forwarding", "numChanges": 1, "lastChange": 1727151356.1330667},
|
||||
},
|
||||
},
|
||||
"Vl1": {"vlans": [1], "interfaces": {"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0615358}}},
|
||||
"Vl10": {
|
||||
"vlans": [10],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0673406},
|
||||
"Vxlan1": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0677001},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0728855},
|
||||
"Ethernet3": {"state": "forwarding", "numChanges": 3, "lastChange": 1727326730.255137},
|
||||
},
|
||||
},
|
||||
"Vl1198": {
|
||||
"vlans": [1198],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.074386},
|
||||
"Vxlan1": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0743902},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0743942},
|
||||
},
|
||||
},
|
||||
"Vl1199": {
|
||||
"vlans": [1199],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0744},
|
||||
"Vxlan1": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.07453},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.074535},
|
||||
},
|
||||
},
|
||||
"Vl20": {
|
||||
"vlans": [20],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.073489},
|
||||
"Vxlan1": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0743747},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0743794},
|
||||
"Ethernet3": {"state": "forwarding", "numChanges": 3, "lastChange": 1727326730.2551405},
|
||||
},
|
||||
},
|
||||
"Vl3009": {
|
||||
"vlans": [3009],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.074541},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0745454},
|
||||
},
|
||||
},
|
||||
"Vl3019": {
|
||||
"vlans": [3019],
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0745502},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 1, "lastChange": 1727326710.0745537},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"threshold": 10},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-unstable-topology",
|
||||
"test": VerifyStpTopologyChanges,
|
||||
"eos_data": [
|
||||
{
|
||||
"unmappedVlans": [],
|
||||
"topologies": {
|
||||
"Cist": {
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 15, "lastChange": 1723990624.735365},
|
||||
"Port-Channel5": {"state": "forwarding", "numChanges": 15, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"threshold": 10},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"The following STP topologies are not configured or number of changes not within the threshold:\n"
|
||||
"{'topologies': {'Cist': {'Cpu': {'Number of changes': 15}, 'Port-Channel5': {'Number of changes': 15}}}}"
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-topologies-not-configured",
|
||||
"test": VerifyStpTopologyChanges,
|
||||
"eos_data": [
|
||||
{
|
||||
"unmappedVlans": [],
|
||||
"topologies": {
|
||||
"NoStp": {
|
||||
"interfaces": {
|
||||
"Cpu": {"state": "forwarding", "numChanges": 1, "lastChange": 1723990624.735365},
|
||||
"Ethernet1": {"state": "forwarding", "numChanges": 15, "lastChange": 1723990624.7353542},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
"inputs": {"threshold": 10},
|
||||
"expected": {"result": "failure", "messages": ["STP is not configured."]},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
from anta.tests.stun import VerifyStunClient
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from anta.tests.stun import VerifyStunClient, VerifyStunServer
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -173,4 +173,61 @@ DATA: list[dict[str, Any]] = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyStunServer,
|
||||
"eos_data": [
|
||||
{
|
||||
"enabled": True,
|
||||
"pid": 1895,
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure-disabled",
|
||||
"test": VerifyStunServer,
|
||||
"eos_data": [
|
||||
{
|
||||
"enabled": False,
|
||||
"pid": 1895,
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["STUN server status is disabled."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-not-running",
|
||||
"test": VerifyStunServer,
|
||||
"eos_data": [
|
||||
{
|
||||
"enabled": True,
|
||||
"pid": 0,
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["STUN server is not running."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-not-running-disabled",
|
||||
"test": VerifyStunServer,
|
||||
"eos_data": [
|
||||
{
|
||||
"enabled": False,
|
||||
"pid": 0,
|
||||
}
|
||||
],
|
||||
"inputs": {},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["STUN server status is disabled and not running."],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -14,10 +14,11 @@ from anta.tests.system import (
|
|||
VerifyFileSystemUtilization,
|
||||
VerifyMemoryUtilization,
|
||||
VerifyNTP,
|
||||
VerifyNTPAssociations,
|
||||
VerifyReloadCause,
|
||||
VerifyUptime,
|
||||
)
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -75,13 +76,6 @@ DATA: list[dict[str, Any]] = [
|
|||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["Reload cause is: 'Reload after crash.'"]},
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"test": VerifyReloadCause,
|
||||
"eos_data": [{}],
|
||||
"inputs": None,
|
||||
"expected": {"result": "error", "messages": ["No reload causes available"]},
|
||||
},
|
||||
{
|
||||
"name": "success-without-minidump",
|
||||
"test": VerifyCoredump,
|
||||
|
@ -286,4 +280,186 @@ poll interval unknown
|
|||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["The device is not synchronized with the configured NTP server(s): 'unsynchronised'"]},
|
||||
},
|
||||
{
|
||||
"name": "success",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [
|
||||
{
|
||||
"peers": {
|
||||
"1.1.1.1": {
|
||||
"condition": "sys.peer",
|
||||
"peerIpAddr": "1.1.1.1",
|
||||
"stratumLevel": 1,
|
||||
},
|
||||
"2.2.2.2": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "2.2.2.2",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
"3.3.3.3": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "3.3.3.3",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.1.1.1", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.2.2.2", "stratum": 2},
|
||||
{"server_address": "3.3.3.3", "stratum": 2},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "success-pool-name",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [
|
||||
{
|
||||
"peers": {
|
||||
"1.ntp.networks.com": {
|
||||
"condition": "sys.peer",
|
||||
"peerIpAddr": "1.1.1.1",
|
||||
"stratumLevel": 1,
|
||||
},
|
||||
"2.ntp.networks.com": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "2.2.2.2",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
"3.ntp.networks.com": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "3.3.3.3",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.ntp.networks.com", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.ntp.networks.com", "stratum": 2},
|
||||
{"server_address": "3.ntp.networks.com", "stratum": 2},
|
||||
]
|
||||
},
|
||||
"expected": {"result": "success"},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [
|
||||
{
|
||||
"peers": {
|
||||
"1.1.1.1": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "1.1.1.1",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
"2.2.2.2": {
|
||||
"condition": "sys.peer",
|
||||
"peerIpAddr": "2.2.2.2",
|
||||
"stratumLevel": 2,
|
||||
},
|
||||
"3.3.3.3": {
|
||||
"condition": "sys.peer",
|
||||
"peerIpAddr": "3.3.3.3",
|
||||
"stratumLevel": 3,
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.1.1.1", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.2.2.2", "stratum": 2},
|
||||
{"server_address": "3.3.3.3", "stratum": 2},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"For NTP peer 1.1.1.1:\nExpected `sys.peer` as the condition, but found `candidate` instead.\nExpected `1` as the stratum, but found `2` instead.\n"
|
||||
"For NTP peer 2.2.2.2:\nExpected `candidate` as the condition, but found `sys.peer` instead.\n"
|
||||
"For NTP peer 3.3.3.3:\nExpected `candidate` as the condition, but found `sys.peer` instead.\nExpected `2` as the stratum, but found `3` instead."
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-no-peers",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [{"peers": {}}],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.1.1.1", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.2.2.2", "stratum": 1},
|
||||
{"server_address": "3.3.3.3", "stratum": 1},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["None of NTP peers are not configured."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-one-peer-not-found",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [
|
||||
{
|
||||
"peers": {
|
||||
"1.1.1.1": {
|
||||
"condition": "sys.peer",
|
||||
"peerIpAddr": "1.1.1.1",
|
||||
"stratumLevel": 1,
|
||||
},
|
||||
"2.2.2.2": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "2.2.2.2",
|
||||
"stratumLevel": 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.1.1.1", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.2.2.2", "stratum": 1},
|
||||
{"server_address": "3.3.3.3", "stratum": 1},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": ["NTP peer 3.3.3.3 is not configured."],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "failure-with-two-peers-not-found",
|
||||
"test": VerifyNTPAssociations,
|
||||
"eos_data": [
|
||||
{
|
||||
"peers": {
|
||||
"1.1.1.1": {
|
||||
"condition": "candidate",
|
||||
"peerIpAddr": "1.1.1.1",
|
||||
"stratumLevel": 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"ntp_servers": [
|
||||
{"server_address": "1.1.1.1", "preferred": True, "stratum": 1},
|
||||
{"server_address": "2.2.2.2", "stratum": 1},
|
||||
{"server_address": "3.3.3.3", "stratum": 1},
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"result": "failure",
|
||||
"messages": [
|
||||
"For NTP peer 1.1.1.1:\nExpected `sys.peer` as the condition, but found `candidate` instead.\n"
|
||||
"NTP peer 2.2.2.2 is not configured.\nNTP peer 3.3.3.3 is not configured."
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.vlan import VerifyVlanInternalPolicy
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from anta.tests.vxlan import VerifyVxlan1ConnSettings, VerifyVxlan1Interface, VerifyVxlanConfigSanity, VerifyVxlanVniBinding, VerifyVxlanVtep
|
||||
from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
|
||||
from tests.units.anta_tests import test
|
||||
|
||||
DATA: list[dict[str, Any]] = [
|
||||
{
|
||||
|
@ -26,21 +26,21 @@ DATA: list[dict[str, Any]] = [
|
|||
"expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"name": "failure-down-up",
|
||||
"test": VerifyVxlan1Interface,
|
||||
"eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "up"}}}],
|
||||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["Vxlan1 interface is down/up"]},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"name": "failure-up-down",
|
||||
"test": VerifyVxlan1Interface,
|
||||
"eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "up", "interfaceStatus": "down"}}}],
|
||||
"inputs": None,
|
||||
"expected": {"result": "failure", "messages": ["Vxlan1 interface is up/down"]},
|
||||
},
|
||||
{
|
||||
"name": "failure",
|
||||
"name": "failure-down-down",
|
||||
"test": VerifyVxlan1Interface,
|
||||
"eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "down"}}}],
|
||||
"inputs": None,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue