summaryrefslogtreecommitdiffstats
path: root/tests/units/anta_tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-28 06:11:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-28 06:11:39 +0000
commit1fd6a618b60d7168fd8f37585d5d39d22d775afd (patch)
treefbc6d0c213b8acdd0a31deafe5c5fc0d05a3a312 /tests/units/anta_tests
parentInitial commit. (diff)
downloadanta-1fd6a618b60d7168fd8f37585d5d39d22d775afd.tar.xz
anta-1fd6a618b60d7168fd8f37585d5d39d22d775afd.zip
Adding upstream version 0.13.0.upstream/0.13.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--tests/units/anta_tests/README.md7
-rw-r--r--tests/units/anta_tests/__init__.py3
-rw-r--r--tests/units/anta_tests/routing/__init__.py3
-rw-r--r--tests/units/anta_tests/routing/test_bgp.py3385
-rw-r--r--tests/units/anta_tests/routing/test_generic.py230
-rw-r--r--tests/units/anta_tests/routing/test_ospf.py298
-rw-r--r--tests/units/anta_tests/test_aaa.py516
-rw-r--r--tests/units/anta_tests/test_bfd.py523
-rw-r--r--tests/units/anta_tests/test_configuration.py35
-rw-r--r--tests/units/anta_tests/test_connectivity.py369
-rw-r--r--tests/units/anta_tests/test_field_notices.py291
-rw-r--r--tests/units/anta_tests/test_greent.py47
-rw-r--r--tests/units/anta_tests/test_hardware.py918
-rw-r--r--tests/units/anta_tests/test_interfaces.py1411
-rw-r--r--tests/units/anta_tests/test_lanz.py27
-rw-r--r--tests/units/anta_tests/test_logging.py254
-rw-r--r--tests/units/anta_tests/test_mlag.py343
-rw-r--r--tests/units/anta_tests/test_multicast.py175
-rw-r--r--tests/units/anta_tests/test_profiles.py47
-rw-r--r--tests/units/anta_tests/test_ptp.py42
-rw-r--r--tests/units/anta_tests/test_security.py900
-rw-r--r--tests/units/anta_tests/test_services.py218
-rw-r--r--tests/units/anta_tests/test_snmp.py128
-rw-r--r--tests/units/anta_tests/test_software.py101
-rw-r--r--tests/units/anta_tests/test_stp.py328
-rw-r--r--tests/units/anta_tests/test_system.py283
-rw-r--r--tests/units/anta_tests/test_vlan.py37
-rw-r--r--tests/units/anta_tests/test_vxlan.py365
28 files changed, 11284 insertions, 0 deletions
diff --git a/tests/units/anta_tests/README.md b/tests/units/anta_tests/README.md
new file mode 100644
index 0000000..6e4c5f0
--- /dev/null
+++ b/tests/units/anta_tests/README.md
@@ -0,0 +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.
+ -->
+
+A guide explaining how to write the unit test can be found in the [contribution guide](../../../docs/contribution.md#unit-tests)
diff --git a/tests/units/anta_tests/__init__.py b/tests/units/anta_tests/__init__.py
new file mode 100644
index 0000000..e772bee
--- /dev/null
+++ b/tests/units/anta_tests/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/tests/units/anta_tests/routing/__init__.py b/tests/units/anta_tests/routing/__init__.py
new file mode 100644
index 0000000..e772bee
--- /dev/null
+++ b/tests/units/anta_tests/routing/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/tests/units/anta_tests/routing/test_bgp.py b/tests/units/anta_tests/routing/test_bgp.py
new file mode 100644
index 0000000..799f058
--- /dev/null
+++ b/tests/units/anta_tests/routing/test_bgp.py
@@ -0,0 +1,3385 @@
+# 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.tests.routing.bgp.py
+"""
+# pylint: disable=C0302
+from __future__ import annotations
+
+from typing import Any
+
+# pylint: disable=C0413
+# because of the patch above
+from anta.tests.routing.bgp import ( # noqa: E402
+ VerifyBGPAdvCommunities,
+ VerifyBGPExchangedRoutes,
+ VerifyBGPPeerASNCap,
+ VerifyBGPPeerCount,
+ VerifyBGPPeerMD5Auth,
+ VerifyBGPPeerMPCaps,
+ VerifyBGPPeerRouteRefreshCap,
+ VerifyBGPPeersHealth,
+ VerifyBGPSpecificPeers,
+ VerifyBGPTimers,
+ VerifyEVPNType2Route,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "num_peers": 2}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-count",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "num_peers": 3}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': 'Expected: 3, Actual: 2'}}]"]},
+ },
+ {
+ "name": "failure-no-peers",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}],
+ "inputs": {"address_families": [{"afi": "ipv6", "safi": "unicast", "vrf": "default", "num_peers": 3}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Expected: 3, Actual: 0'}}]"]},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [{"vrfs": {}}],
+ "inputs": {"address_families": [{"afi": "ipv6", "safi": "multicast", "vrf": "DEV", "num_peers": 3}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv6', 'safi': 'multicast', 'vrfs': {'DEV': 'Not Configured'}}]"]},
+ },
+ {
+ "name": "success-vrf-all",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all", "num_peers": 3}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-vrf-all",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all", "num_peers": 5}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'all': 'Expected: 5, Actual: 3'}}]"]},
+ },
+ {
+ "name": "success-multiple-afi",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "num_peers": 2},
+ {"afi": "evpn", "num_peers": 2},
+ ]
+ },
+ "expected": {
+ "result": "success",
+ },
+ },
+ {
+ "name": "failure-multiple-afi",
+ "test": VerifyBGPPeerCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {"vrfs": {}},
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "num_peers": 3},
+ {"afi": "evpn", "num_peers": 3},
+ {"afi": "ipv6", "safi": "unicast", "vrf": "default", "num_peers": 3},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'PROD': 'Expected: 3, Actual: 2'}}, "
+ "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, "
+ "{'afi': 'evpn', 'vrfs': {'default': 'Expected: 3, Actual: 2'}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-issues",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Idle",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}}]"
+ ],
+ },
+ },
+ {
+ "name": "success-vrf-all",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all"}]},
+ "expected": {
+ "result": "success",
+ },
+ },
+ {
+ "name": "failure-issues-vrf-all",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Idle",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 100,
+ "outMsgQueue": 200,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ },
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}, "
+ "'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 100, 'outMsgQueue': 200}}}}]"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [{"vrfs": {}}],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "DEV"}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'DEV': 'Not Configured'}}]"]},
+ },
+ {
+ "name": "failure-no-peers",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "multicast"}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'multicast', 'vrfs': {'default': 'No Peers'}}]"]},
+ },
+ {
+ "name": "success-multiple-afi",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD"},
+ {"afi": "evpn"},
+ ]
+ },
+ "expected": {
+ "result": "success",
+ },
+ },
+ {
+ "name": "failure-multiple-afi",
+ "test": VerifyBGPPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 10,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {"vrfs": {}},
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Idle",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD"},
+ {"afi": "evpn"},
+ {"afi": "ipv6", "safi": "unicast", "vrf": "default"},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': "
+ "{'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 10, 'outMsgQueue': 0}}}}, "
+ "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, "
+ "{'afi': 'evpn', 'vrfs': {'default': {'10.1.0.2': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "peers": ["10.1.255.0", "10.1.255.2"]}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-issues",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.255.0": {
+ "description": "DC1-SPINE1_Ethernet1",
+ "version": 4,
+ "msgReceived": 0,
+ "msgSent": 0,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266295.098931,
+ "underMaintenance": False,
+ "peerState": "Idle",
+ },
+ "10.1.255.2": {
+ "description": "DC1-SPINE2_Ethernet1",
+ "version": 4,
+ "msgReceived": 3759,
+ "msgSent": 3757,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 14,
+ "prefixReceived": 14,
+ "upDownTime": 1694266296.367261,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ }
+ ],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "peers": ["10.1.255.0", "10.1.255.2"]}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}}]"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [{"vrfs": {}}],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "DEV", "peers": ["10.1.255.0"]}]},
+ "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'DEV': 'Not Configured'}}]"]},
+ },
+ {
+ "name": "failure-no-peers",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}],
+ "inputs": {"address_families": [{"afi": "ipv4", "safi": "multicast", "peers": ["10.1.255.0"]}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'multicast', 'vrfs': {'default': {'10.1.255.0': {'peerNotFound': True}}}}]"],
+ },
+ },
+ {
+ "name": "success-multiple-afi",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "peers": ["10.1.254.1", "192.168.1.11"]},
+ {"afi": "evpn", "peers": ["10.1.0.1", "10.1.0.2"]},
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-multiple-afi",
+ "test": VerifyBGPSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "PROD": {
+ "vrf": "PROD",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.254.1": {
+ "description": "DC1-LEAF1B",
+ "version": 4,
+ "msgReceived": 3777,
+ "msgSent": 3764,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65120",
+ "prefixAccepted": 2,
+ "prefixReceived": 2,
+ "upDownTime": 1694266296.659891,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "192.168.1.11": {
+ "description": "K8S-CLUSTER1",
+ "version": 4,
+ "msgReceived": 6417,
+ "msgSent": 7546,
+ "inMsgQueue": 10,
+ "outMsgQueue": 0,
+ "asn": "65000",
+ "prefixAccepted": 1,
+ "prefixReceived": 1,
+ "upDownTime": 1694266329.978035,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ },
+ }
+ }
+ },
+ {"vrfs": {}},
+ {
+ "vrfs": {
+ "default": {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": "65120",
+ "peers": {
+ "10.1.0.1": {
+ "description": "DC1-SPINE1",
+ "version": 4,
+ "msgReceived": 3894,
+ "msgSent": 3897,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266296.584472,
+ "underMaintenance": False,
+ "peerState": "Established",
+ },
+ "10.1.0.2": {
+ "description": "DC1-SPINE2",
+ "version": 4,
+ "msgReceived": 3893,
+ "msgSent": 3902,
+ "inMsgQueue": 0,
+ "outMsgQueue": 0,
+ "asn": "65100",
+ "prefixAccepted": 0,
+ "prefixReceived": 0,
+ "upDownTime": 1694266297.433896,
+ "underMaintenance": False,
+ "peerState": "Idle",
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "address_families": [
+ {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "peers": ["10.1.254.1", "192.168.1.11"]},
+ {"afi": "evpn", "peers": ["10.1.0.1", "10.1.0.2"]},
+ {"afi": "ipv6", "safi": "unicast", "vrf": "default", "peers": ["10.1.0.1", "10.1.0.2"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': "
+ "{'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 10, 'outMsgQueue': 0}}}}, "
+ "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, "
+ "{'afi': 'evpn', 'vrfs': {'default': {'10.1.0.2': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPExchangedRoutes,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.5/32", "192.0.254.3/32"],
+ "received_routes": ["192.0.254.3/32", "192.0.255.4/32"],
+ },
+ {
+ "peer_address": "172.30.11.5",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.3/32", "192.0.254.5/32"],
+ "received_routes": ["192.0.254.3/32", "192.0.255.4/32"],
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-routes",
+ "test": VerifyBGPExchangedRoutes,
+ "eos_data": [
+ {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}},
+ {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}},
+ {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}},
+ {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}},
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.3/32"],
+ "received_routes": ["192.0.255.3/32"],
+ },
+ {
+ "peer_address": "172.30.11.12",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.31/32"],
+ "received_routes": ["192.0.255.31/32"],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not found or routes are not exchanged properly:\n"
+ "{'bgp_peers': {'172.30.11.11': {'default': 'Not configured'}, '172.30.11.12': {'default': 'Not configured'}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPExchangedRoutes,
+ "eos_data": [
+ {"vrfs": {}},
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {"vrfs": {}},
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "MGMT",
+ "advertised_routes": ["192.0.254.3/32"],
+ "received_routes": ["192.0.255.3/32"],
+ },
+ {
+ "peer_address": "172.30.11.5",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.3/32", "192.0.254.5/32"],
+ "received_routes": ["192.0.254.3/32", "192.0.255.4/32"],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': {'172.30.11.11': {'MGMT': 'Not configured'}}}"],
+ },
+ },
+ {
+ "name": "failure-missing-routes",
+ "test": VerifyBGPExchangedRoutes,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": True,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.3/32", "192.0.254.51/32"],
+ "received_routes": ["192.0.254.31/32", "192.0.255.4/32"],
+ },
+ {
+ "peer_address": "172.30.11.5",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.31/32", "192.0.254.5/32"],
+ "received_routes": ["192.0.254.3/32", "192.0.255.41/32"],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': "
+ "{'172.30.11.1': {'default': {'advertised_routes': {'192.0.254.51/32': 'Not found'}, 'received_routes': {'192.0.254.31/32': 'Not found'}}}, "
+ "'172.30.11.5': {'default': {'advertised_routes': {'192.0.254.31/32': 'Not found'}, 'received_routes': {'192.0.255.41/32': 'Not found'}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-invalid-or-inactive-routes",
+ "test": VerifyBGPExchangedRoutes,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": False,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": False,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": False,
+ "active": True,
+ },
+ }
+ ]
+ },
+ "192.0.254.5/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": False,
+ "active": True,
+ },
+ }
+ ]
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": False,
+ "active": False,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": False,
+ "active": False,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "bgpRouteEntries": {
+ "192.0.254.3/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": False,
+ },
+ }
+ ],
+ },
+ "192.0.255.4/32": {
+ "bgpRoutePaths": [
+ {
+ "routeType": {
+ "valid": True,
+ "active": False,
+ },
+ }
+ ],
+ },
+ },
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.3/32", "192.0.254.51/32"],
+ "received_routes": ["192.0.254.31/32", "192.0.255.4/32"],
+ },
+ {
+ "peer_address": "172.30.11.5",
+ "vrf": "default",
+ "advertised_routes": ["192.0.254.31/32", "192.0.254.5/32"],
+ "received_routes": ["192.0.254.3/32", "192.0.255.41/32"],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': "
+ "{'172.30.11.1': {'default': {'advertised_routes': {'192.0.254.3/32': {'valid': True, 'active': False}, '192.0.254.51/32': 'Not found'}, "
+ "'received_routes': {'192.0.254.31/32': 'Not found', '192.0.255.4/32': {'valid': False, 'active': False}}}}, "
+ "'172.30.11.5': {'default': {'advertised_routes': {'192.0.254.31/32': 'Not found', '192.0.254.5/32': {'valid': True, 'active': False}}, "
+ "'received_routes': {'192.0.254.3/32': {'valid': False, 'active': True}, '192.0.255.41/32': 'Not found'}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPPeerMPCaps,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "ipv4Unicast": {"advertised": True, "received": True, "enabled": True},
+ "ipv4MplsLabels": {"advertised": True, "received": True, "enabled": True},
+ }
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "ipv4Unicast": {"advertised": True, "received": True, "enabled": True},
+ "ipv4MplsVpn": {"advertised": True, "received": True, "enabled": True},
+ }
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "capabilities": ["Ipv4 Unicast", "ipv4 Mpls labels"],
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "MGMT",
+ "capabilities": ["ipv4 Unicast", "ipv4 MplsVpn"],
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-vrf",
+ "test": VerifyBGPPeerMPCaps,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "ipv4Unicast": {"advertised": True, "received": True, "enabled": True},
+ "ipv4MplsVpn": {"advertised": True, "received": True, "enabled": True},
+ }
+ },
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ "capabilities": ["ipv4 Unicast", "ipv4mplslabels"],
+ }
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer multiprotocol capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPPeerMPCaps,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "default",
+ "capabilities": ["ipv4Unicast", "L2 Vpn EVPN"],
+ },
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ "capabilities": ["ipv4Unicast", "L2 Vpn EVPN"],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer multiprotocol capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-missing-capabilities",
+ "test": VerifyBGPPeerMPCaps,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default", "capabilities": ["ipv4 Unicast", "L2VpnEVPN"]}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer multiprotocol capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'default': {'l2VpnEvpn': 'not found'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-incorrect-capabilities",
+ "test": VerifyBGPPeerMPCaps,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "ipv4Unicast": {"advertised": False, "received": False, "enabled": False},
+ "ipv4MplsVpn": {"advertised": False, "received": True, "enabled": False},
+ },
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "l2VpnEvpn": {"advertised": True, "received": False, "enabled": False},
+ "ipv4MplsVpn": {"advertised": False, "received": False, "enabled": True},
+ },
+ },
+ },
+ {
+ "peerAddress": "172.30.11.11",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {
+ "ipv4Unicast": {"advertised": False, "received": False, "enabled": False},
+ "ipv4MplsVpn": {"advertised": False, "received": False, "enabled": False},
+ },
+ },
+ },
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {"peer_address": "172.30.11.1", "vrf": "default", "capabilities": ["ipv4 unicast", "ipv4 mpls vpn", "L2 vpn EVPN"]},
+ {"peer_address": "172.30.11.10", "vrf": "MGMT", "capabilities": ["ipv4unicast", "ipv4 mplsvpn", "L2vpnEVPN"]},
+ {"peer_address": "172.30.11.11", "vrf": "MGMT", "capabilities": ["Ipv4 Unicast", "ipv4 MPLSVPN", "L2 vpnEVPN"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer multiprotocol capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'ipv4Unicast': {'advertised': False, 'received': False, 'enabled': False}, "
+ "'ipv4MplsVpn': {'advertised': False, 'received': True, 'enabled': False}, 'l2VpnEvpn': 'not found'}}, "
+ "'172.30.11.10': {'MGMT': {'ipv4Unicast': 'not found', 'ipv4MplsVpn': {'advertised': False, 'received': False, 'enabled': True}, "
+ "'l2VpnEvpn': {'advertised': True, 'received': False, 'enabled': False}}}, "
+ "'172.30.11.11': {'MGMT': {'ipv4Unicast': {'advertised': False, 'received': False, 'enabled': False}, "
+ "'ipv4MplsVpn': {'advertised': False, 'received': False, 'enabled': False}, 'l2VpnEvpn': 'not found'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPPeerASNCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "MGMT",
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-vrf",
+ "test": VerifyBGPPeerASNCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ }
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "default",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer four octet asn capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}, '172.30.11.10': {'default': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPPeerASNCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ },
+ ]
+ }
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "default",
+ }
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer four octet asn capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-missing-capabilities",
+ "test": VerifyBGPPeerASNCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4MplsLabels": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.10", "vrf": "MGMT"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer four octet asn capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'fourOctetAsnCap': 'not found'}}, '172.30.11.10': {'MGMT': {'fourOctetAsnCap': 'not found'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-incorrect-capabilities",
+ "test": VerifyBGPPeerASNCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": False, "received": False, "enabled": False},
+ },
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "neighborCapabilities": {
+ "fourOctetAsnCap": {"advertised": True, "received": False, "enabled": True},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.10", "vrf": "MGMT"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer four octet asn capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'fourOctetAsnCap': {'advertised': False, 'received': False, 'enabled': False}}}, "
+ "'172.30.11.10': {'MGMT': {'fourOctetAsnCap': {'advertised': True, 'received': False, 'enabled': True}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPPeerRouteRefreshCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "routeRefreshCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "neighborCapabilities": {
+ "routeRefreshCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "CS",
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-vrf",
+ "test": VerifyBGPPeerRouteRefreshCap,
+ "eos_data": [{"vrfs": {}}],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ }
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer route refresh capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPPeerRouteRefreshCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ip4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.12",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ip4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.12",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "CS",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer route refresh capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.12': {'default': {'status': 'Not configured'}}, '172.30.11.1': {'CS': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-missing-capabilities",
+ "test": VerifyBGPPeerRouteRefreshCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "neighborCapabilities": {
+ "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.11", "vrf": "CS"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer route refresh capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'routeRefreshCap': 'not found'}}, '172.30.11.11': {'CS': {'routeRefreshCap': 'not found'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-incorrect-capabilities",
+ "test": VerifyBGPPeerRouteRefreshCap,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "neighborCapabilities": {
+ "routeRefreshCap": {"advertised": False, "received": False, "enabled": False},
+ },
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "neighborCapabilities": {
+ "routeRefreshCap": {"advertised": True, "received": True, "enabled": True},
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.11", "vrf": "CS"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peer route refresh capabilities are not found or not ok:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'routeRefreshCap': {'advertised': False, 'received': False, 'enabled': False}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPPeerMD5Auth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "state": "Established",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "state": "Established",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "CS",
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-vrf",
+ "test": VerifyBGPPeerMD5Auth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "state": "Established",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ }
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n"
+ "{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPPeerMD5Auth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "state": "Established",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "state": "Established",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "default",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n"
+ "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.11': {'default': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-established-peer",
+ "test": VerifyBGPPeerMD5Auth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "state": "Idle",
+ "md5AuthEnabled": True,
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "state": "Idle",
+ "md5AuthEnabled": False,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "MGMT",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'state': 'Idle', 'md5_auth_enabled': True}}, "
+ "'172.30.11.10': {'MGMT': {'state': 'Idle', 'md5_auth_enabled': False}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-md5-peer",
+ "test": VerifyBGPPeerMD5Auth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "state": "Established",
+ },
+ {"peerAddress": "172.30.11.10", "state": "Established", "md5AuthEnabled": False},
+ ]
+ },
+ "MGMT": {"peerList": [{"peerAddress": "172.30.11.11", "state": "Established", "md5AuthEnabled": False}]},
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "MGMT",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'state': 'Established', 'md5_auth_enabled': None}}, "
+ "'172.30.11.11': {'MGMT': {'state': 'Established', 'md5_auth_enabled': False}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ }
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiple-endpoints",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}, {"address": "aac1.ab5d.b41e", "vni": 10010}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiple-routes-ip",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiple-routes-mac",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiple-routes-multiple-paths-ip",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ "ecmp": True,
+ "ecmpContributor": True,
+ "ecmpHead": True,
+ },
+ },
+ {
+ "routeType": {
+ "active": False,
+ "valid": True,
+ "ecmp": True,
+ "ecmpContributor": True,
+ "ecmpHead": False,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiple-routes-multiple-paths-mac",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ "ecmp": True,
+ "ecmpContributor": True,
+ "ecmpHead": True,
+ },
+ },
+ {
+ "routeType": {
+ "active": False,
+ "valid": True,
+ "ecmp": True,
+ "ecmpContributor": True,
+ "ecmpHead": False,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-routes",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [{"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}}],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following VXLAN endpoint do not have any EVPN Type-2 route: [('192.168.20.102', 10020)]"],
+ },
+ },
+ {
+ "name": "failure-path-not-active",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following EVPN Type-2 routes do not have at least one valid and active path: ['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']"
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-routes-not-active",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following EVPN Type-2 routes do not have at least one valid and active path: "
+ "['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102', "
+ "'RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']"
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-routes-multiple-paths-not-active",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": True,
+ "valid": True,
+ },
+ },
+ {
+ "routeType": {
+ "active": False,
+ "valid": True,
+ },
+ },
+ ]
+ },
+ "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following EVPN Type-2 routes do not have at least one valid and active path: ['RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']"
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-endpoints",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ ]
+ },
+ },
+ },
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}, {"address": "aac1.ab5d.b41e", "vni": 10010}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following EVPN Type-2 routes do not have at least one valid and active path: "
+ "['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102', "
+ "'RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e']"
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-endpoints-one-no-routes",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}},
+ {
+ "vrf": "default",
+ "routerId": "10.1.0.3",
+ "asn": 65120,
+ "evpnRoutes": {
+ "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e 192.168.10.101": {
+ "evpnRoutePaths": [
+ {
+ "routeType": {
+ "active": False,
+ "valid": False,
+ },
+ },
+ ]
+ },
+ },
+ },
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}, {"address": "192.168.10.101", "vni": 10010}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following VXLAN endpoint do not have any EVPN Type-2 route: [('aa:c1:ab:4e:be:c2', 10020)]",
+ "The following EVPN Type-2 routes do not have at least one valid and active path: "
+ "['RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e 192.168.10.101']",
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-endpoints-no-routes",
+ "test": VerifyEVPNType2Route,
+ "eos_data": [
+ {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}},
+ {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}},
+ ],
+ "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}, {"address": "192.168.10.101", "vni": 10010}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following VXLAN endpoint do not have any EVPN Type-2 route: [('aa:c1:ab:4e:be:c2', 10020), ('192.168.10.101', 10010)]"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPAdvCommunities,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": True},
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": True},
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "MGMT",
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-vrf",
+ "test": VerifyBGPAdvCommunities,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": True},
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.17",
+ "vrf": "MGMT",
+ }
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n"
+ "{'bgp_peers': {'172.30.11.17': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPAdvCommunities,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": True},
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": True},
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.12",
+ "vrf": "MGMT",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n"
+ "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.12': {'MGMT': {'status': 'Not configured'}}}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-correct-communities",
+ "test": VerifyBGPAdvCommunities,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "advertisedCommunities": {"standard": False, "extended": False, "large": False},
+ }
+ ]
+ },
+ "CS": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.10",
+ "advertisedCommunities": {"standard": True, "extended": True, "large": False},
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ },
+ {
+ "peer_address": "172.30.11.10",
+ "vrf": "CS",
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n"
+ "{'bgp_peers': {'172.30.11.1': {'default': {'advertised_communities': {'standard': False, 'extended': False, 'large': False}}}, "
+ "'172.30.11.10': {'CS': {'advertised_communities': {'standard': True, 'extended': True, 'large': False}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBGPTimers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "holdTime": 180,
+ "keepaliveTime": 60,
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "holdTime": 180,
+ "keepaliveTime": 60,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "MGMT",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBGPTimers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "holdTime": 180,
+ "keepaliveTime": 60,
+ }
+ ]
+ },
+ "MGMT": {"peerList": []},
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "MGMT",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "MGMT",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured or hold and keep-alive timers are not correct:\n"
+ "{'172.30.11.1': {'MGMT': 'Not configured'}, '172.30.11.11': {'MGMT': 'Not configured'}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-not-correct-timers",
+ "test": VerifyBGPTimers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.1",
+ "holdTime": 160,
+ "keepaliveTime": 60,
+ }
+ ]
+ },
+ "MGMT": {
+ "peerList": [
+ {
+ "peerAddress": "172.30.11.11",
+ "holdTime": 120,
+ "keepaliveTime": 40,
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bgp_peers": [
+ {
+ "peer_address": "172.30.11.1",
+ "vrf": "default",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ {
+ "peer_address": "172.30.11.11",
+ "vrf": "MGMT",
+ "hold_time": 180,
+ "keep_alive_time": 60,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BGP peers are not configured or hold and keep-alive timers are not correct:\n"
+ "{'172.30.11.1': {'default': {'hold_time': 160, 'keep_alive_time': 60}}, "
+ "'172.30.11.11': {'MGMT': {'hold_time': 120, 'keep_alive_time': 40}}}"
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/routing/test_generic.py b/tests/units/anta_tests/routing/test_generic.py
new file mode 100644
index 0000000..90e70f8
--- /dev/null
+++ b/tests/units/anta_tests/routing/test_generic.py
@@ -0,0 +1,230 @@
+# 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.tests.routing.generic.py
+"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.routing.generic import VerifyRoutingProtocolModel, VerifyRoutingTableEntry, VerifyRoutingTableSize
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyRoutingProtocolModel,
+ "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "multi-agent", "operatingProtoModel": "multi-agent"}}],
+ "inputs": {"model": "multi-agent"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-configured-model",
+ "test": VerifyRoutingProtocolModel,
+ "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "ribd", "operatingProtoModel": "ribd"}}],
+ "inputs": {"model": "multi-agent"},
+ "expected": {"result": "failure", "messages": ["routing model is misconfigured: configured: ribd - operating: ribd - expected: multi-agent"]},
+ },
+ {
+ "name": "failure-mismatch-operating-model",
+ "test": VerifyRoutingProtocolModel,
+ "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "multi-agent", "operatingProtoModel": "ribd"}}],
+ "inputs": {"model": "multi-agent"},
+ "expected": {"result": "failure", "messages": ["routing model is misconfigured: configured: multi-agent - operating: ribd - expected: multi-agent"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyRoutingTableSize,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ # Output truncated
+ "maskLen": {"8": 2},
+ "totalRoutes": 123,
+ }
+ },
+ }
+ ],
+ "inputs": {"minimum": 42, "maximum": 666},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyRoutingTableSize,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ # Output truncated
+ "maskLen": {"8": 2},
+ "totalRoutes": 1000,
+ }
+ },
+ }
+ ],
+ "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,
+ "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"}],
+ }
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "routingDisabled": False,
+ "allRoutesProgrammedHardware": True,
+ "allRoutesProgrammedKernel": True,
+ "defaultRouteState": "notSet",
+ "routes": {
+ "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"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-missing-route",
+ "test": VerifyRoutingTableEntry,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "routingDisabled": False,
+ "allRoutesProgrammedHardware": True,
+ "allRoutesProgrammedKernel": True,
+ "defaultRouteState": "notSet",
+ "routes": {},
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "routingDisabled": False,
+ "allRoutesProgrammedHardware": True,
+ "allRoutesProgrammedKernel": True,
+ "defaultRouteState": "notSet",
+ "routes": {
+ "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"]},
+ "expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.1']"]},
+ },
+ {
+ "name": "failure-wrong-route",
+ "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"}],
+ }
+ },
+ }
+ }
+ },
+ {
+ "vrfs": {
+ "default": {
+ "routingDisabled": False,
+ "allRoutesProgrammedHardware": True,
+ "allRoutesProgrammedKernel": True,
+ "defaultRouteState": "notSet",
+ "routes": {
+ "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"]},
+ "expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.2']"]},
+ },
+]
diff --git a/tests/units/anta_tests/routing/test_ospf.py b/tests/units/anta_tests/routing/test_ospf.py
new file mode 100644
index 0000000..fbabee9
--- /dev/null
+++ b/tests/units/anta_tests/routing/test_ospf.py
@@ -0,0 +1,298 @@
+# 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.tests.routing.ospf.py
+"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.routing.ospf import VerifyOSPFNeighborCount, VerifyOSPFNeighborState
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyOSPFNeighborState,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "instList": {
+ "666": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "7.7.7.7",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ {
+ "routerId": "9.9.9.9",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ ]
+ }
+ }
+ },
+ "BLAH": {
+ "instList": {
+ "777": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "8.8.8.8",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyOSPFNeighborState,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "instList": {
+ "666": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "7.7.7.7",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "2-way",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ {
+ "routerId": "9.9.9.9",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ ]
+ }
+ }
+ },
+ "BLAH": {
+ "instList": {
+ "777": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "8.8.8.8",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "down",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Some neighbors are not correctly configured: [{'vrf': 'default', 'instance': '666', 'neighbor': '7.7.7.7', 'state': '2-way'},"
+ " {'vrf': 'BLAH', 'instance': '777', 'neighbor': '8.8.8.8', 'state': 'down'}]."
+ ],
+ },
+ },
+ {
+ "name": "skipped",
+ "test": VerifyOSPFNeighborState,
+ "eos_data": [
+ {
+ "vrfs": {},
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["no OSPF neighbor found"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyOSPFNeighborCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "instList": {
+ "666": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "7.7.7.7",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ {
+ "routerId": "9.9.9.9",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ ]
+ }
+ }
+ },
+ "BLAH": {
+ "instList": {
+ "777": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "8.8.8.8",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"number": 3},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifyOSPFNeighborCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "instList": {
+ "666": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "7.7.7.7",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ ],
+ "inputs": {"number": 3},
+ "expected": {"result": "failure", "messages": ["device has 1 neighbors (expected 3)"]},
+ },
+ {
+ "name": "failure-good-number-wrong-state",
+ "test": VerifyOSPFNeighborCount,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "instList": {
+ "666": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "7.7.7.7",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "2-way",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ {
+ "routerId": "9.9.9.9",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "full",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ },
+ ]
+ }
+ }
+ },
+ "BLAH": {
+ "instList": {
+ "777": {
+ "ospfNeighborEntries": [
+ {
+ "routerId": "8.8.8.8",
+ "priority": 1,
+ "drState": "DR",
+ "interfaceName": "Ethernet1",
+ "adjacencyState": "down",
+ "inactivity": 1683298014.844345,
+ "interfaceAddress": "10.3.0.1",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"number": 3},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Some neighbors are not correctly configured: [{'vrf': 'default', 'instance': '666', 'neighbor': '7.7.7.7', 'state': '2-way'},"
+ " {'vrf': 'BLAH', 'instance': '777', 'neighbor': '8.8.8.8', 'state': 'down'}]."
+ ],
+ },
+ },
+ {
+ "name": "skipped",
+ "test": VerifyOSPFNeighborCount,
+ "eos_data": [
+ {
+ "vrfs": {},
+ }
+ ],
+ "inputs": {"number": 3},
+ "expected": {"result": "skipped", "messages": ["no OSPF neighbor found"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_aaa.py b/tests/units/anta_tests/test_aaa.py
new file mode 100644
index 0000000..2992290
--- /dev/null
+++ b/tests/units/anta_tests/test_aaa.py
@@ -0,0 +1,516 @@
+# 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.tests.aaa.py
+"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.aaa import (
+ VerifyAcctConsoleMethods,
+ VerifyAcctDefaultMethods,
+ VerifyAuthenMethods,
+ VerifyAuthzMethods,
+ VerifyTacacsServerGroups,
+ VerifyTacacsServers,
+ VerifyTacacsSourceIntf,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyTacacsSourceIntf,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"intf": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyTacacsSourceIntf,
+ "eos_data": [
+ {
+ "tacacsServers": [],
+ "groups": {},
+ "srcIntf": {},
+ }
+ ],
+ "inputs": {"intf": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Source-interface Management0 is not configured in VRF MGMT"]},
+ },
+ {
+ "name": "failure-wrong-intf",
+ "test": VerifyTacacsSourceIntf,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management1"},
+ }
+ ],
+ "inputs": {"intf": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Wrong source-interface configured in VRF MGMT"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifyTacacsSourceIntf,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"PROD": "Management0"},
+ }
+ ],
+ "inputs": {"intf": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Source-interface Management0 is not configured in VRF MGMT"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTacacsServers,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-servers",
+ "test": VerifyTacacsServers,
+ "eos_data": [
+ {
+ "tacacsServers": [],
+ "groups": {},
+ "srcIntf": {},
+ }
+ ],
+ "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["No TACACS servers are configured"]},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyTacacsServers,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"servers": ["10.22.10.91", "10.22.10.92"], "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["TACACS servers ['10.22.10.92'] are not configured in VRF MGMT"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifyTacacsServers,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "PROD"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["TACACS servers ['10.22.10.91'] are not configured in VRF MGMT"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTacacsServerGroups,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"groups": ["GROUP1"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-server-groups",
+ "test": VerifyTacacsServerGroups,
+ "eos_data": [
+ {
+ "tacacsServers": [],
+ "groups": {},
+ "srcIntf": {},
+ }
+ ],
+ "inputs": {"groups": ["GROUP1"]},
+ "expected": {"result": "failure", "messages": ["No TACACS server group(s) are configured"]},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyTacacsServerGroups,
+ "eos_data": [
+ {
+ "tacacsServers": [
+ {
+ "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"},
+ }
+ ],
+ "groups": {"GROUP2": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}},
+ "srcIntf": {"MGMT": "Management0"},
+ }
+ ],
+ "inputs": {"groups": ["GROUP1"]},
+ "expected": {"result": "failure", "messages": ["TACACS server group(s) ['GROUP1'] are not configured"]},
+ },
+ {
+ "name": "success-login-enable",
+ "test": VerifyAuthenMethods,
+ "eos_data": [
+ {
+ "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group tacacs+", "local"]}},
+ "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-dot1x",
+ "test": VerifyAuthenMethods,
+ "eos_data": [
+ {
+ "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group tacacs+", "local"]}},
+ "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}},
+ }
+ ],
+ "inputs": {"methods": ["radius"], "types": ["dot1x"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-login-console",
+ "test": VerifyAuthenMethods,
+ "eos_data": [
+ {
+ "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]},
+ "expected": {"result": "failure", "messages": ["AAA authentication methods are not configured for login console"]},
+ },
+ {
+ "name": "failure-login-console",
+ "test": VerifyAuthenMethods,
+ "eos_data": [
+ {
+ "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group radius", "local"]}},
+ "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]},
+ "expected": {"result": "failure", "messages": ["AAA authentication methods ['group tacacs+', 'local'] are not matching for login console"]},
+ },
+ {
+ "name": "failure-login-default",
+ "test": VerifyAuthenMethods,
+ "eos_data": [
+ {
+ "loginAuthenMethods": {"default": {"methods": ["group radius", "local"]}, "login": {"methods": ["group tacacs+", "local"]}},
+ "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}},
+ "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]},
+ "expected": {"result": "failure", "messages": ["AAA authentication methods ['group tacacs+', 'local'] are not matching for ['login']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAuthzMethods,
+ "eos_data": [
+ {
+ "commandsAuthzMethods": {"privilege0-15": {"methods": ["group tacacs+", "local"]}},
+ "execAuthzMethods": {"exec": {"methods": ["group tacacs+", "local"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-commands",
+ "test": VerifyAuthzMethods,
+ "eos_data": [
+ {
+ "commandsAuthzMethods": {"privilege0-15": {"methods": ["group radius", "local"]}},
+ "execAuthzMethods": {"exec": {"methods": ["group tacacs+", "local"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]},
+ "expected": {"result": "failure", "messages": ["AAA authorization methods ['group tacacs+', 'local'] are not matching for ['commands']"]},
+ },
+ {
+ "name": "failure-exec",
+ "test": VerifyAuthzMethods,
+ "eos_data": [
+ {
+ "commandsAuthzMethods": {"privilege0-15": {"methods": ["group tacacs+", "local"]}},
+ "execAuthzMethods": {"exec": {"methods": ["group radius", "local"]}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]},
+ "expected": {"result": "failure", "messages": ["AAA authorization methods ['group tacacs+', 'local'] are not matching for ['exec']"]},
+ },
+ {
+ "name": "success-commands-exec-system",
+ "test": VerifyAcctDefaultMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-dot1x",
+ "test": VerifyAcctDefaultMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultAction": "startStop", "defaultMethods": ["group radius", "logging"], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["radius", "logging"], "types": ["dot1x"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyAcctDefaultMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA default accounting is not configured for ['commands']"]},
+ },
+ {
+ "name": "failure-not-configured-empty",
+ "test": VerifyAcctDefaultMethods,
+ "eos_data": [
+ {
+ "systemAcctMethods": {"system": {"defaultMethods": [], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultMethods": [], "consoleMethods": []}},
+ "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA default accounting is not configured for ['system', 'exec', 'commands']"]},
+ },
+ {
+ "name": "failure-not-matching",
+ "test": VerifyAcctDefaultMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group radius", "logging"], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA accounting default methods ['group tacacs+', 'logging'] are not matching for ['commands']"]},
+ },
+ {
+ "name": "success-commands-exec-system",
+ "test": VerifyAcctConsoleMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {
+ "privilege0-15": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "execAcctMethods": {
+ "exec": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "systemAcctMethods": {
+ "system": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-dot1x",
+ "test": VerifyAcctConsoleMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {
+ "privilege0-15": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "execAcctMethods": {
+ "exec": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "systemAcctMethods": {
+ "system": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "dot1xAcctMethods": {
+ "dot1x": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["dot1x"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyAcctConsoleMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {
+ "privilege0-15": {
+ "defaultMethods": [],
+ "consoleMethods": [],
+ }
+ },
+ "execAcctMethods": {
+ "exec": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "systemAcctMethods": {
+ "system": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA console accounting is not configured for ['commands']"]},
+ },
+ {
+ "name": "failure-not-configured-empty",
+ "test": VerifyAcctConsoleMethods,
+ "eos_data": [
+ {
+ "systemAcctMethods": {"system": {"defaultMethods": [], "consoleMethods": []}},
+ "execAcctMethods": {"exec": {"defaultMethods": [], "consoleMethods": []}},
+ "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}},
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA console accounting is not configured for ['system', 'exec', 'commands']"]},
+ },
+ {
+ "name": "failure-not-matching",
+ "test": VerifyAcctConsoleMethods,
+ "eos_data": [
+ {
+ "commandsAcctMethods": {
+ "privilege0-15": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group radius", "logging"],
+ }
+ },
+ "execAcctMethods": {
+ "exec": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "systemAcctMethods": {
+ "system": {
+ "defaultMethods": [],
+ "consoleAction": "startStop",
+ "consoleMethods": ["group tacacs+", "logging"],
+ }
+ },
+ "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}},
+ }
+ ],
+ "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]},
+ "expected": {"result": "failure", "messages": ["AAA accounting console methods ['group tacacs+', 'logging'] are not matching for ['commands']"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_bfd.py b/tests/units/anta_tests/test_bfd.py
new file mode 100644
index 0000000..67bb0b4
--- /dev/null
+++ b/tests/units/anta_tests/test_bfd.py
@@ -0,0 +1,523 @@
+# 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.tests.bfd.py
+"""
+# pylint: disable=C0302
+from __future__ import annotations
+
+from typing import Any
+
+# pylint: disable=C0413
+# because of the patch above
+from anta.tests.bfd import VerifyBFDPeersHealth, VerifyBFDPeersIntervals, VerifyBFDSpecificPeers # noqa: E402
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyBFDPeersIntervals,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 1200000,
+ "operRxInterval": 1200000,
+ "detectMult": 3,
+ }
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.70": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 1200000,
+ "operRxInterval": 1200000,
+ "detectMult": 3,
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bfd_peers": [
+ {"peer_address": "192.0.255.7", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBFDPeersIntervals,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 1200000,
+ "operRxInterval": 1200000,
+ "detectMult": 3,
+ }
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 1200000,
+ "operRxInterval": 1200000,
+ "detectMult": 3,
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bfd_peers": [
+ {"peer_address": "192.0.255.7", "vrf": "CS", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BFD peers are not configured or timers are not correct:\n"
+ "{'192.0.255.7': {'CS': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-incorrect-timers",
+ "test": VerifyBFDPeersIntervals,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 1300000,
+ "operRxInterval": 1200000,
+ "detectMult": 4,
+ }
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.70": {
+ "peerStats": {
+ "": {
+ "peerStatsDetail": {
+ "operTxInterval": 120000,
+ "operRxInterval": 120000,
+ "detectMult": 5,
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {
+ "bfd_peers": [
+ {"peer_address": "192.0.255.7", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3},
+ ]
+ },
+ "expected": {
+ "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}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBFDSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 108328132,
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.70": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 108328132,
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "default"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBFDSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 108328132,
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 108328132,
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "CS"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BFD peers are not configured, status is not up or remote disc is zero:\n"
+ "{'192.0.255.7': {'CS': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-session-down",
+ "test": VerifyBFDSpecificPeers,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "Down",
+ "remoteDisc": 108328132,
+ }
+ }
+ }
+ }
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.70": {
+ "peerStats": {
+ "": {
+ "status": "Down",
+ "remoteDisc": 0,
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "default"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BFD peers are not configured, status is not up or remote disc is zero:\n"
+ "{'192.0.255.7': {'default': {'status': 'Down', 'remote_disc': 108328132}}, "
+ "'192.0.255.70': {'MGMT': {'status': 'Down', 'remote_disc': 0}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBFDPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ },
+ }
+ },
+ {
+ "utcTime": 1703667348.111288,
+ },
+ ],
+ "inputs": {"down_threshold": 2},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-peer",
+ "test": VerifyBFDPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "MGMT": {
+ "ipv6Neighbors": {},
+ "ipv4Neighbors": {},
+ },
+ "default": {
+ "ipv6Neighbors": {},
+ "ipv4Neighbors": {},
+ },
+ }
+ },
+ {
+ "utcTime": 1703658481.8778424,
+ },
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": ["No IPv4 BFD peers are configured for any VRF."],
+ },
+ },
+ {
+ "name": "failure-session-down",
+ "test": VerifyBFDPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "down",
+ "remoteDisc": 0,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ "192.0.255.70": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ },
+ "MGMT": {
+ "ipv4Neighbors": {
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "status": "down",
+ "remoteDisc": 0,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ },
+ }
+ },
+ {
+ "utcTime": 1703658481.8778424,
+ },
+ ],
+ "inputs": {},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BFD peers are not up:\n192.0.255.7 is down in default VRF with remote disc 0.\n192.0.255.71 is down in MGMT VRF with remote disc 0."
+ ],
+ },
+ },
+ {
+ "name": "failure-session-up-disc",
+ "test": VerifyBFDPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 0,
+ "lastDown": 1703657258.652725,
+ "l3intf": "Ethernet2",
+ }
+ }
+ },
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 0,
+ "lastDown": 1703657258.652725,
+ "l3intf": "Ethernet2",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ }
+ }
+ },
+ {
+ "utcTime": 1703658481.8778424,
+ },
+ ],
+ "inputs": {},
+ "expected": {
+ "result": "failure",
+ "messages": ["Following BFD peers were down:\n192.0.255.7 in default VRF has remote disc 0.\n192.0.255.71 in default VRF has remote disc 0."],
+ },
+ },
+ {
+ "name": "failure-last-down",
+ "test": VerifyBFDPeersHealth,
+ "eos_data": [
+ {
+ "vrfs": {
+ "default": {
+ "ipv4Neighbors": {
+ "192.0.255.7": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ "192.0.255.71": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ "192.0.255.17": {
+ "peerStats": {
+ "": {
+ "status": "up",
+ "remoteDisc": 3940685114,
+ "lastDown": 1703657258.652725,
+ "l3intf": "",
+ }
+ }
+ },
+ },
+ "ipv6Neighbors": {},
+ }
+ }
+ },
+ {
+ "utcTime": 1703667348.111288,
+ },
+ ],
+ "inputs": {"down_threshold": 4},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Following BFD peers were down:\n192.0.255.7 in default VRF was down 3 hours ago.\n"
+ "192.0.255.71 in default VRF was down 3 hours ago.\n192.0.255.17 in default VRF was down 3 hours ago."
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_configuration.py b/tests/units/anta_tests/test_configuration.py
new file mode 100644
index 0000000..a2ab673
--- /dev/null
+++ b/tests/units/anta_tests/test_configuration.py
@@ -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.
+"""Data for testing anta.tests.configuration"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.configuration import VerifyRunningConfigDiffs, VerifyZeroTouch
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyZeroTouch,
+ "eos_data": [{"mode": "disabled"}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyZeroTouch,
+ "eos_data": [{"mode": "enabled"}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["ZTP is NOT disabled"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyRunningConfigDiffs,
+ "eos_data": [""],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {"name": "failure", "test": VerifyRunningConfigDiffs, "eos_data": ["blah blah"], "inputs": None, "expected": {"result": "failure", "messages": ["blah blah"]}},
+]
diff --git a/tests/units/anta_tests/test_connectivity.py b/tests/units/anta_tests/test_connectivity.py
new file mode 100644
index 0000000..f79ce24
--- /dev/null
+++ b/tests/units/anta_tests/test_connectivity.py
@@ -0,0 +1,369 @@
+# 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.tests.connectivity.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success-ip",
+ "test": VerifyReachability,
+ "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "10.0.0.5"}, {"destination": "10.0.0.2", "source": "10.0.0.5"}]},
+ "eos_data": [
+ {
+ "messages": [
+ """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.1 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ {
+ "messages": [
+ """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.2 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ ],
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-interface",
+ "test": VerifyReachability,
+ "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0"}, {"destination": "10.0.0.2", "source": "Management0"}]},
+ "eos_data": [
+ {
+ "messages": [
+ """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.1 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ {
+ "messages": [
+ """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.2 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ ],
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-repeat",
+ "test": VerifyReachability,
+ "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0", "repeat": 1}]},
+ "eos_data": [
+ {
+ "messages": [
+ """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms
+
+ --- 10.0.0.1 ping statistics ---
+ 1 packets transmitted, 1 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ ],
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-ip",
+ "test": VerifyReachability,
+ "inputs": {"hosts": [{"destination": "10.0.0.11", "source": "10.0.0.5"}, {"destination": "10.0.0.2", "source": "10.0.0.5"}]},
+ "eos_data": [
+ {
+ "messages": [
+ """ping: sendmsg: Network is unreachable
+ ping: sendmsg: Network is unreachable
+ PING 10.0.0.11 (10.0.0.11) from 10.0.0.5 : 72(100) bytes of data.
+
+ --- 10.0.0.11 ping statistics ---
+ 2 packets transmitted, 0 received, 100% packet loss, time 10ms
+
+
+ """
+ ]
+ },
+ {
+ "messages": [
+ """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.2 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ ],
+ "expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('10.0.0.5', '10.0.0.11')]"]},
+ },
+ {
+ "name": "failure-interface",
+ "test": VerifyReachability,
+ "inputs": {"hosts": [{"destination": "10.0.0.11", "source": "Management0"}, {"destination": "10.0.0.2", "source": "Management0"}]},
+ "eos_data": [
+ {
+ "messages": [
+ """ping: sendmsg: Network is unreachable
+ ping: sendmsg: Network is unreachable
+ PING 10.0.0.11 (10.0.0.11) from 10.0.0.5 : 72(100) bytes of data.
+
+ --- 10.0.0.11 ping statistics ---
+ 2 packets transmitted, 0 received, 100% packet loss, time 10ms
+
+
+ """
+ ]
+ },
+ {
+ "messages": [
+ """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data.
+ 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms
+ 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms
+
+ --- 10.0.0.2 ping statistics ---
+ 2 packets transmitted, 2 received, 0% packet loss, time 0ms
+ rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms
+
+ """
+ ]
+ },
+ ],
+ "expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('Management0', '10.0.0.11')]"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLLDPNeighbors,
+ "inputs": {
+ "neighbors": [
+ {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"},
+ ]
+ },
+ "eos_data": [
+ {
+ "lldpNeighbors": {
+ "Ethernet1": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73a0.fc18",
+ "systemName": "DC1-SPINE1",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet1"',
+ "interfaceId_v2": "Ethernet1",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1",
+ },
+ }
+ ]
+ },
+ "Ethernet2": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73f7.d138",
+ "systemName": "DC1-SPINE2",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet1"',
+ "interfaceId_v2": "Ethernet1",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet2",
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-port-not-configured",
+ "test": VerifyLLDPNeighbors,
+ "inputs": {
+ "neighbors": [
+ {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"},
+ ]
+ },
+ "eos_data": [
+ {
+ "lldpNeighbors": {
+ "Ethernet1": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73a0.fc18",
+ "systemName": "DC1-SPINE1",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet1"',
+ "interfaceId_v2": "Ethernet1",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1",
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'port_not_configured': ['Ethernet2']}"]},
+ },
+ {
+ "name": "failure-no-neighbor",
+ "test": VerifyLLDPNeighbors,
+ "inputs": {
+ "neighbors": [
+ {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"},
+ ]
+ },
+ "eos_data": [
+ {
+ "lldpNeighbors": {
+ "Ethernet1": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73a0.fc18",
+ "systemName": "DC1-SPINE1",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet1"',
+ "interfaceId_v2": "Ethernet1",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1",
+ },
+ }
+ ]
+ },
+ "Ethernet2": {"lldpNeighborInfo": []},
+ }
+ }
+ ],
+ "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'no_lldp_neighbor': ['Ethernet2']}"]},
+ },
+ {
+ "name": "failure-wrong-neighbor",
+ "test": VerifyLLDPNeighbors,
+ "inputs": {
+ "neighbors": [
+ {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"},
+ ]
+ },
+ "eos_data": [
+ {
+ "lldpNeighbors": {
+ "Ethernet1": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73a0.fc18",
+ "systemName": "DC1-SPINE1",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet1"',
+ "interfaceId_v2": "Ethernet1",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1",
+ },
+ }
+ ]
+ },
+ "Ethernet2": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73f7.d138",
+ "systemName": "DC1-SPINE2",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet2"',
+ "interfaceId_v2": "Ethernet2",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet2",
+ },
+ }
+ ]
+ },
+ }
+ }
+ ],
+ "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'wrong_lldp_neighbor': ['Ethernet2']}"]},
+ },
+ {
+ "name": "failure-multiple",
+ "test": VerifyLLDPNeighbors,
+ "inputs": {
+ "neighbors": [
+ {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"},
+ {"port": "Ethernet3", "neighbor_device": "DC1-SPINE3", "neighbor_port": "Ethernet1"},
+ ]
+ },
+ "eos_data": [
+ {
+ "lldpNeighbors": {
+ "Ethernet1": {
+ "lldpNeighborInfo": [
+ {
+ "chassisIdType": "macAddress",
+ "chassisId": "001c.73a0.fc18",
+ "systemName": "DC1-SPINE1",
+ "neighborInterfaceInfo": {
+ "interfaceIdType": "interfaceName",
+ "interfaceId": '"Ethernet2"',
+ "interfaceId_v2": "Ethernet2",
+ "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1",
+ },
+ }
+ ]
+ },
+ "Ethernet2": {"lldpNeighborInfo": []},
+ }
+ }
+ ],
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following port(s) have issues: {'wrong_lldp_neighbor': ['Ethernet1'], 'no_lldp_neighbor': ['Ethernet2'], 'port_not_configured': ['Ethernet3']}"
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_field_notices.py b/tests/units/anta_tests/test_field_notices.py
new file mode 100644
index 0000000..7c17f22
--- /dev/null
+++ b/tests/units/anta_tests/test_field_notices.py
@@ -0,0 +1,291 @@
+# 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.field_notices"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "DCS-7280QRA-C36S",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-4.0",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "DCS-7280QRA-C36S",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-4.0.1-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (4.0.1)"]},
+ },
+ {
+ "name": "failure-4.1",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "DCS-7280QRA-C36S",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-4.1.0-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (4.1.0)"]},
+ },
+ {
+ "name": "failure-6.0",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "DCS-7280QRA-C36S",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-6.0.1-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (6.0.1)"]},
+ },
+ {
+ "name": "failure-6.1",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "DCS-7280QRA-C36S",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-6.1.1-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (6.1.1)"]},
+ },
+ {
+ "name": "skipped-model",
+ "test": VerifyFieldNotice44Resolution,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1109144.35,
+ "modelName": "vEOS-lab",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["device is not impacted by FN044"]},
+ },
+ {
+ "name": "success-JPE",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3-48YC8",
+ "serialNumber": "JPE2130000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "7"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success", "messages": ["FN72 is mitigated"]},
+ },
+ {
+ "name": "success-JAS",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3-48YC8",
+ "serialNumber": "JAS2040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "7"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success", "messages": ["FN72 is mitigated"]},
+ },
+ {
+ "name": "success-K-JPE",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3K-48YC8",
+ "serialNumber": "JPE2133000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "7"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success", "messages": ["FN72 is mitigated"]},
+ },
+ {
+ "name": "success-K-JAS",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3K-48YC8",
+ "serialNumber": "JAS2040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "7"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success", "messages": ["FN72 is mitigated"]},
+ },
+ {
+ "name": "skipped-Serial",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3K-48YC8",
+ "serialNumber": "BAN2040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "7"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["Device not exposed"]},
+ },
+ {
+ "name": "skipped-Platform",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7150-52-CL",
+ "serialNumber": "JAS0040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["Platform is not impacted by FN072"]},
+ },
+ {
+ "name": "skipped-range-JPE",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3-48YC8",
+ "serialNumber": "JPE2131000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["Device not exposed"]},
+ },
+ {
+ "name": "skipped-range-K-JAS",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3K-48YC8",
+ "serialNumber": "JAS2041000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["Device not exposed"]},
+ },
+ {
+ "name": "failed-JPE",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3K-48YC8",
+ "serialNumber": "JPE2133000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device is exposed to FN72"]},
+ },
+ {
+ "name": "failed-JAS",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3-48YC8",
+ "serialNumber": "JAS2040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm1", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device is exposed to FN72"]},
+ },
+ {
+ "name": "error",
+ "test": VerifyFieldNotice72Resolution,
+ "eos_data": [
+ {
+ "modelName": "DCS-7280SR3-48YC8",
+ "serialNumber": "JAS2040000",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "FixedSystemvrm2", "version": "5"}],
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "error", "messages": ["Error in running test - FixedSystemvrm1 not found"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_greent.py b/tests/units/anta_tests/test_greent.py
new file mode 100644
index 0000000..65789a2
--- /dev/null
+++ b/tests/units/anta_tests/test_greent.py
@@ -0,0 +1,47 @@
+# 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.
+"""Data for testing anta.tests.configuration"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.greent import VerifyGreenT, VerifyGreenTCounters
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyGreenTCounters,
+ "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 1, "sampleSent": 0}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyGreenTCounters,
+ "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 0, "sampleSent": 0}],
+ "inputs": None,
+ "expected": {"result": "failure"},
+ },
+ {
+ "name": "success",
+ "test": VerifyGreenT,
+ "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 1, "sampleSent": 0}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyGreenT,
+ "eos_data": [
+ {
+ "profiles": {
+ "default": {"interfaces": [], "appliedInterfaces": [], "samplePolicy": "default", "failures": {}, "appliedInterfaces6": [], "failures6": {}},
+ "testProfile": {"interfaces": [], "appliedInterfaces": [], "samplePolicy": "default", "failures": {}, "appliedInterfaces6": [], "failures6": {}},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure"},
+ },
+]
diff --git a/tests/units/anta_tests/test_hardware.py b/tests/units/anta_tests/test_hardware.py
new file mode 100644
index 0000000..5279d89
--- /dev/null
+++ b/tests/units/anta_tests/test_hardware.py
@@ -0,0 +1,918 @@
+# 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.hardware"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.hardware import (
+ VerifyAdverseDrops,
+ VerifyEnvironmentCooling,
+ VerifyEnvironmentPower,
+ VerifyEnvironmentSystemCooling,
+ VerifyTemperature,
+ VerifyTransceiversManufacturers,
+ VerifyTransceiversTemperature,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyTransceiversManufacturers,
+ "eos_data": [
+ {
+ "xcvrSlots": {
+ "1": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501340", "hardwareRev": "21"},
+ "2": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501337", "hardwareRev": "21"},
+ }
+ }
+ ],
+ "inputs": {"manufacturers": ["Arista Networks"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyTransceiversManufacturers,
+ "eos_data": [
+ {
+ "xcvrSlots": {
+ "1": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501340", "hardwareRev": "21"},
+ "2": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501337", "hardwareRev": "21"},
+ }
+ }
+ ],
+ "inputs": {"manufacturers": ["Arista"]},
+ "expected": {"result": "failure", "messages": ["Some transceivers are from unapproved manufacturers: {'1': 'Arista Networks', '2': 'Arista Networks'}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTemperature,
+ "eos_data": [
+ {
+ "powercycleOnOverheat": "False",
+ "ambientThreshold": 45,
+ "cardSlots": [],
+ "shutdownOnOverheat": "True",
+ "systemStatus": "temperatureOk",
+ "recoveryModeOnOverheat": "recoveryModeNA",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyTemperature,
+ "eos_data": [
+ {
+ "powercycleOnOverheat": "False",
+ "ambientThreshold": 45,
+ "cardSlots": [],
+ "shutdownOnOverheat": "True",
+ "systemStatus": "temperatureKO",
+ "recoveryModeOnOverheat": "recoveryModeNA",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device temperature exceeds acceptable limits. Current system status: 'temperatureKO'"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTransceiversTemperature,
+ "eos_data": [
+ {
+ "tempSensors": [
+ {
+ "maxTemperature": 25.03125,
+ "maxTemperatureLastChange": 1682509618.2227979,
+ "hwStatus": "ok",
+ "alertCount": 0,
+ "description": "Xcvr54 temp sensor",
+ "overheatThreshold": 70.0,
+ "criticalThreshold": 70.0,
+ "inAlertState": False,
+ "targetTemperature": 62.0,
+ "relPos": "54",
+ "currentTemperature": 24.171875,
+ "setPointTemperature": 61.8,
+ "pidDriverCount": 0,
+ "isPidDriver": False,
+ "name": "DomTemperatureSensor54",
+ }
+ ],
+ "cardSlots": [],
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-hwStatus",
+ "test": VerifyTransceiversTemperature,
+ "eos_data": [
+ {
+ "tempSensors": [
+ {
+ "maxTemperature": 25.03125,
+ "maxTemperatureLastChange": 1682509618.2227979,
+ "hwStatus": "ko",
+ "alertCount": 0,
+ "description": "Xcvr54 temp sensor",
+ "overheatThreshold": 70.0,
+ "criticalThreshold": 70.0,
+ "inAlertState": False,
+ "targetTemperature": 62.0,
+ "relPos": "54",
+ "currentTemperature": 24.171875,
+ "setPointTemperature": 61.8,
+ "pidDriverCount": 0,
+ "isPidDriver": False,
+ "name": "DomTemperatureSensor54",
+ }
+ ],
+ "cardSlots": [],
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following sensors are operating outside the acceptable temperature range or have raised alerts: "
+ "{'DomTemperatureSensor54': "
+ "{'hwStatus': 'ko', 'alertCount': 0}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-alertCount",
+ "test": VerifyTransceiversTemperature,
+ "eos_data": [
+ {
+ "tempSensors": [
+ {
+ "maxTemperature": 25.03125,
+ "maxTemperatureLastChange": 1682509618.2227979,
+ "hwStatus": "ok",
+ "alertCount": 1,
+ "description": "Xcvr54 temp sensor",
+ "overheatThreshold": 70.0,
+ "criticalThreshold": 70.0,
+ "inAlertState": False,
+ "targetTemperature": 62.0,
+ "relPos": "54",
+ "currentTemperature": 24.171875,
+ "setPointTemperature": 61.8,
+ "pidDriverCount": 0,
+ "isPidDriver": False,
+ "name": "DomTemperatureSensor54",
+ }
+ ],
+ "cardSlots": [],
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following sensors are operating outside the acceptable temperature range or have raised alerts: "
+ "{'DomTemperatureSensor54': "
+ "{'hwStatus': 'ok', 'alertCount': 1}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyEnvironmentSystemCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [],
+ "fanTraySlots": [],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "coolingOk",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyEnvironmentSystemCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [],
+ "fanTraySlots": [],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "coolingKo",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device system cooling is not OK: 'coolingKo'"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyEnvironmentCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498937.0240965,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499033.0403435,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498935.9121106,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499092.4665174,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply2",
+ },
+ ],
+ "fanTraySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303148,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0139885,
+ "configuredSpeed": 30,
+ "actualSpeed": 29,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9304729,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498939.9329433,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "2",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9383528,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140095,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "3/1",
+ }
+ ],
+ "speed": 30,
+ "label": "3",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303904,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140295,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "4/1",
+ }
+ ],
+ "speed": 30,
+ "label": "4",
+ },
+ ],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "coolingOk",
+ }
+ ],
+ "inputs": {"states": ["ok"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-additional-states",
+ "test": VerifyEnvironmentCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498937.0240965,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499033.0403435,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "Not Inserted",
+ "uptime": 1682498935.9121106,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499092.4665174,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply2",
+ },
+ ],
+ "fanTraySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303148,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0139885,
+ "configuredSpeed": 30,
+ "actualSpeed": 29,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9304729,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498939.9329433,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "2",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9383528,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140095,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "3/1",
+ }
+ ],
+ "speed": 30,
+ "label": "3",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303904,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140295,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "4/1",
+ }
+ ],
+ "speed": 30,
+ "label": "4",
+ },
+ ],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "coolingOk",
+ }
+ ],
+ "inputs": {"states": ["ok", "Not Inserted"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-fan-tray",
+ "test": VerifyEnvironmentCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498937.0240965,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499033.0403435,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498935.9121106,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499092.4665174,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply2",
+ },
+ ],
+ "fanTraySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "down",
+ "uptime": 1682498923.9303148,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0139885,
+ "configuredSpeed": 30,
+ "actualSpeed": 29,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9304729,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498939.9329433,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "2",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "Not Inserted",
+ "uptime": 1682498923.9383528,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140095,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "3/1",
+ }
+ ],
+ "speed": 30,
+ "label": "3",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303904,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140295,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "4/1",
+ }
+ ],
+ "speed": 30,
+ "label": "4",
+ },
+ ],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "CoolingKo",
+ }
+ ],
+ "inputs": {"states": ["ok", "Not Inserted"]},
+ "expected": {"result": "failure", "messages": ["Fan 1/1 on Fan Tray 1 is: 'down'"]},
+ },
+ {
+ "name": "failure-power-supply",
+ "test": VerifyEnvironmentCooling,
+ "eos_data": [
+ {
+ "defaultZones": False,
+ "numCoolingZones": [],
+ "coolingMode": "automatic",
+ "ambientTemperature": 24.5,
+ "shutdownOnInsufficientFans": True,
+ "airflowDirection": "frontToBackAirflow",
+ "overrideFanSpeed": 0,
+ "powerSupplySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "down",
+ "uptime": 1682498937.0240965,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499033.0403435,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498935.9121106,
+ "maxSpeed": 23000,
+ "lastSpeedStableChangeTime": 1682499092.4665174,
+ "configuredSpeed": 30,
+ "actualSpeed": 33,
+ "speedHwOverride": True,
+ "speedStable": True,
+ "label": "PowerSupply2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "PowerSupply2",
+ },
+ ],
+ "fanTraySlots": [
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303148,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0139885,
+ "configuredSpeed": 30,
+ "actualSpeed": 29,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "1/1",
+ }
+ ],
+ "speed": 30,
+ "label": "1",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9304729,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498939.9329433,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "2/1",
+ }
+ ],
+ "speed": 30,
+ "label": "2",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "Not Inserted",
+ "uptime": 1682498923.9383528,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140095,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "3/1",
+ }
+ ],
+ "speed": 30,
+ "label": "3",
+ },
+ {
+ "status": "ok",
+ "fans": [
+ {
+ "status": "ok",
+ "uptime": 1682498923.9303904,
+ "maxSpeed": 17500,
+ "lastSpeedStableChangeTime": 1682498975.0140295,
+ "configuredSpeed": 30,
+ "actualSpeed": 30,
+ "speedHwOverride": False,
+ "speedStable": True,
+ "label": "4/1",
+ }
+ ],
+ "speed": 30,
+ "label": "4",
+ },
+ ],
+ "minFanSpeed": 0,
+ "currentZones": 1,
+ "configuredZones": 0,
+ "systemStatus": "CoolingKo",
+ }
+ ],
+ "inputs": {"states": ["ok", "Not Inserted"]},
+ "expected": {"result": "failure", "messages": ["Fan PowerSupply1/1 on PowerSupply PowerSupply1 is: 'down'"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyEnvironmentPower,
+ "eos_data": [
+ {
+ "powerSupplies": {
+ "1": {
+ "outputPower": 0.0,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP1/2": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/3": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/1": {"status": "ok", "temperature": 0.0},
+ },
+ "fans": {"FanP1/1": {"status": "ok", "speed": 33}},
+ "state": "ok",
+ "inputCurrent": 0.0,
+ "dominant": False,
+ "inputVoltage": 0.0,
+ "outputCurrent": 0.0,
+ "managed": True,
+ },
+ "2": {
+ "outputPower": 117.375,
+ "uptime": 1682498935.9121966,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP2/1": {"status": "ok", "temperature": 39.0},
+ "TempSensorP2/3": {"status": "ok", "temperature": 43.0},
+ "TempSensorP2/2": {"status": "ok", "temperature": 31.0},
+ },
+ "fans": {"FanP2/1": {"status": "ok", "speed": 33}},
+ "state": "ok",
+ "inputCurrent": 0.572265625,
+ "dominant": False,
+ "inputVoltage": 232.5,
+ "outputCurrent": 9.828125,
+ "managed": True,
+ },
+ }
+ }
+ ],
+ "inputs": {"states": ["ok"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-additional-states",
+ "test": VerifyEnvironmentPower,
+ "eos_data": [
+ {
+ "powerSupplies": {
+ "1": {
+ "outputPower": 0.0,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP1/2": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/3": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/1": {"status": "ok", "temperature": 0.0},
+ },
+ "fans": {"FanP1/1": {"status": "ok", "speed": 33}},
+ "state": "Not Inserted",
+ "inputCurrent": 0.0,
+ "dominant": False,
+ "inputVoltage": 0.0,
+ "outputCurrent": 0.0,
+ "managed": True,
+ },
+ "2": {
+ "outputPower": 117.375,
+ "uptime": 1682498935.9121966,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP2/1": {"status": "ok", "temperature": 39.0},
+ "TempSensorP2/3": {"status": "ok", "temperature": 43.0},
+ "TempSensorP2/2": {"status": "ok", "temperature": 31.0},
+ },
+ "fans": {"FanP2/1": {"status": "ok", "speed": 33}},
+ "state": "ok",
+ "inputCurrent": 0.572265625,
+ "dominant": False,
+ "inputVoltage": 232.5,
+ "outputCurrent": 9.828125,
+ "managed": True,
+ },
+ }
+ }
+ ],
+ "inputs": {"states": ["ok", "Not Inserted"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyEnvironmentPower,
+ "eos_data": [
+ {
+ "powerSupplies": {
+ "1": {
+ "outputPower": 0.0,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP1/2": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/3": {"status": "ok", "temperature": 0.0},
+ "TempSensorP1/1": {"status": "ok", "temperature": 0.0},
+ },
+ "fans": {"FanP1/1": {"status": "ok", "speed": 33}},
+ "state": "powerLoss",
+ "inputCurrent": 0.0,
+ "dominant": False,
+ "inputVoltage": 0.0,
+ "outputCurrent": 0.0,
+ "managed": True,
+ },
+ "2": {
+ "outputPower": 117.375,
+ "uptime": 1682498935.9121966,
+ "modelName": "PWR-500AC-F",
+ "capacity": 500.0,
+ "tempSensors": {
+ "TempSensorP2/1": {"status": "ok", "temperature": 39.0},
+ "TempSensorP2/3": {"status": "ok", "temperature": 43.0},
+ "TempSensorP2/2": {"status": "ok", "temperature": 31.0},
+ },
+ "fans": {"FanP2/1": {"status": "ok", "speed": 33}},
+ "state": "ok",
+ "inputCurrent": 0.572265625,
+ "dominant": False,
+ "inputVoltage": 232.5,
+ "outputCurrent": 9.828125,
+ "managed": True,
+ },
+ }
+ }
+ ],
+ "inputs": {"states": ["ok"]},
+ "expected": {"result": "failure", "messages": ["The following power supplies status are not in the accepted states list: {'1': {'state': 'powerLoss'}}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAdverseDrops,
+ "eos_data": [{"totalAdverseDrops": 0}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyAdverseDrops,
+ "eos_data": [{"totalAdverseDrops": 10}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device totalAdverseDrops counter is: '10'"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_interfaces.py b/tests/units/anta_tests/test_interfaces.py
new file mode 100644
index 0000000..5b0d845
--- /dev/null
+++ b/tests/units/anta_tests/test_interfaces.py
@@ -0,0 +1,1411 @@
+# 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.hardware"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.interfaces import (
+ VerifyIllegalLACP,
+ VerifyInterfaceDiscards,
+ VerifyInterfaceErrDisabled,
+ VerifyInterfaceErrors,
+ VerifyInterfaceIPv4,
+ VerifyInterfacesStatus,
+ VerifyInterfaceUtilization,
+ VerifyIPProxyARP,
+ VerifyIpVirtualRouterMac,
+ VerifyL2MTU,
+ VerifyL3MTU,
+ VerifyLoopbackCount,
+ VerifyPortChannels,
+ VerifyStormControlDrops,
+ VerifySVI,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyInterfaceUtilization,
+ "eos_data": [
+ """Port Name Intvl In Mbps % In Kpps Out Mbps % Out Kpps
+Et1 5:00 0.0 0.0% 0 0.0 0.0% 0
+Et4 5:00 0.0 0.0% 0 0.0 0.0% 0
+"""
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyInterfaceUtilization,
+ "eos_data": [
+ """Port Name Intvl In Mbps % In Kpps Out Mbps % Out Kpps
+Et1 5:00 0.0 0.0% 0 0.0 80.0% 0
+Et4 5:00 0.0 99.9% 0 0.0 0.0% 0
+"""
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following interfaces have a usage > 75%: {'Et1': '80.0%', 'Et4': '99.9%'}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyInterfaceErrors,
+ "eos_data": [
+ {
+ "interfaceErrorCounters": {
+ "Ethernet1": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0},
+ "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-multiple-intfs",
+ "test": VerifyInterfaceErrors,
+ "eos_data": [
+ {
+ "interfaceErrorCounters": {
+ "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0},
+ "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 666, "symbolErrors": 0},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts': 0,"
+ " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}, {'Ethernet6': {'inErrors': 0, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts':"
+ " 0, 'fcsErrors': 0, 'alignmentErrors': 666, 'symbolErrors': 0}}]"
+ ],
+ },
+ },
+ {
+ "name": "failure-multiple-intfs-multiple-errors",
+ "test": VerifyInterfaceErrors,
+ "eos_data": [
+ {
+ "interfaceErrorCounters": {
+ "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 10, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0},
+ "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 6, "symbolErrors": 10},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 10, 'frameTooShorts': 0,"
+ " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}, {'Ethernet6': {'inErrors': 0, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts':"
+ " 0, 'fcsErrors': 0, 'alignmentErrors': 6, 'symbolErrors': 10}}]"
+ ],
+ },
+ },
+ {
+ "name": "failure-single-intf-multiple-errors",
+ "test": VerifyInterfaceErrors,
+ "eos_data": [
+ {
+ "interfaceErrorCounters": {
+ "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 2, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 2, 'frameTooShorts': 0,"
+ " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}]"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyInterfaceDiscards,
+ "eos_data": [
+ {
+ "inDiscardsTotal": 0,
+ "interfaces": {
+ "Ethernet2": {"outDiscards": 0, "inDiscards": 0},
+ "Ethernet1": {"outDiscards": 0, "inDiscards": 0},
+ },
+ "outDiscardsTotal": 0,
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyInterfaceDiscards,
+ "eos_data": [
+ {
+ "inDiscardsTotal": 0,
+ "interfaces": {
+ "Ethernet2": {"outDiscards": 42, "inDiscards": 0},
+ "Ethernet1": {"outDiscards": 0, "inDiscards": 42},
+ },
+ "outDiscardsTotal": 0,
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following interfaces have non 0 discard counter(s): [{'Ethernet2': {'outDiscards': 42, 'inDiscards': 0}},"
+ " {'Ethernet1': {'outDiscards': 0, 'inDiscards': 42}}]"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyInterfaceErrDisabled,
+ "eos_data": [
+ {
+ "interfaceStatuses": {
+ "Management1": {
+ "linkStatus": "connected",
+ },
+ "Ethernet8": {
+ "linkStatus": "connected",
+ },
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyInterfaceErrDisabled,
+ "eos_data": [
+ {
+ "interfaceStatuses": {
+ "Management1": {
+ "linkStatus": "errdisabled",
+ },
+ "Ethernet8": {
+ "linkStatus": "errdisabled",
+ },
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following interfaces are in error disabled state: ['Management1', 'Ethernet8']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet2", "status": "adminDown"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-up-with-line-protocol-status",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet8", "status": "up", "line_protocol_status": "down"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-with-line-protocol-status",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "testing"},
+ "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet3.10": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "dormant"},
+ }
+ }
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "status": "adminDown", "line_protocol_status": "down"},
+ {"name": "Ethernet8", "status": "adminDown", "line_protocol_status": "testing"},
+ {"name": "Ethernet3.10", "status": "down", "line_protocol_status": "dormant"},
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-lower",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "ethernet2", "status": "adminDown"}, {"name": "ethernet8", "status": "up"}, {"name": "ethernet3", "status": "up"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-eth-name",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "eth2", "status": "adminDown"}, {"name": "et8", "status": "up"}, {"name": "et3", "status": "up"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-po-name",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Port-Channel100": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "po100", "status": "up"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-sub-interfaces",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet52/1.1963": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet52/1.1963", "status": "up"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-transceiver-down",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet49/1": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "notPresent"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet49/1", "status": "adminDown"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-po-down",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Port-Channel100": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "lowerLayerDown"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "PortChannel100", "status": "adminDown"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-po-lowerlayerdown",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Port-Channel100": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "lowerLayerDown"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Port-Channel100", "status": "adminDown", "line_protocol_status": "lowerLayerDown"}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet2", "status": "up"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following interface(s) are not configured: ['Ethernet8']"],
+ },
+ },
+ {
+ "name": "failure-status-down",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "Ethernet2", "status": "up"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following interface(s) are not in the expected state: ['Ethernet8 is down/down'"],
+ },
+ },
+ {
+ "name": "failure-proto-down",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "status": "up"},
+ {"name": "Ethernet8", "status": "up"},
+ {"name": "Ethernet3", "status": "up"},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["The following interface(s) are not in the expected state: ['Ethernet8 is up/down'"],
+ },
+ },
+ {
+ "name": "failure-po-status-down",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Port-Channel100": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "lowerLayerDown"},
+ }
+ }
+ ],
+ "inputs": {"interfaces": [{"name": "PortChannel100", "status": "up"}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following interface(s) are not in the expected state: ['Port-Channel100 is down/lowerLayerDown'"],
+ },
+ },
+ {
+ "name": "failure-proto-unknown",
+ "test": VerifyInterfacesStatus,
+ "eos_data": [
+ {
+ "interfaceDescriptions": {
+ "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"},
+ "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "unknown"},
+ "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"},
+ }
+ }
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "status": "up", "line_protocol_status": "down"},
+ {"name": "Ethernet8", "status": "up"},
+ {"name": "Ethernet3", "status": "up"},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["The following interface(s) are not in the expected state: ['Ethernet2 is up/unknown'"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyStormControlDrops,
+ "eos_data": [
+ {
+ "aggregateTrafficClasses": {},
+ "interfaces": {
+ "Ethernet1": {
+ "trafficTypes": {"broadcast": {"level": 100, "thresholdType": "packetsPerSecond", "rate": 0, "drop": 0, "dormant": False}},
+ "active": True,
+ "reason": "",
+ "errdisabled": False,
+ }
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyStormControlDrops,
+ "eos_data": [
+ {
+ "aggregateTrafficClasses": {},
+ "interfaces": {
+ "Ethernet1": {
+ "trafficTypes": {"broadcast": {"level": 100, "thresholdType": "packetsPerSecond", "rate": 0, "drop": 666, "dormant": False}},
+ "active": True,
+ "reason": "",
+ "errdisabled": False,
+ }
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following interfaces have none 0 storm-control drop counters {'Ethernet1': {'broadcast': 666}}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyPortChannels,
+ "eos_data": [
+ {
+ "portChannels": {
+ "Port-Channel42": {
+ "recircFeature": [],
+ "maxWeight": 16,
+ "minSpeed": "0 gbps",
+ "rxPorts": {},
+ "currWeight": 0,
+ "minLinks": 0,
+ "inactivePorts": {},
+ "activePorts": {},
+ "inactiveLag": False,
+ }
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyPortChannels,
+ "eos_data": [
+ {
+ "portChannels": {
+ "Port-Channel42": {
+ "recircFeature": [],
+ "maxWeight": 16,
+ "minSpeed": "0 gbps",
+ "rxPorts": {},
+ "currWeight": 0,
+ "minLinks": 0,
+ "inactivePorts": {"Ethernet8": {"reasonUnconfigured": "waiting for LACP response"}},
+ "activePorts": {},
+ "inactiveLag": False,
+ }
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following port-channels have inactive port(s): ['Port-Channel42']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyIllegalLACP,
+ "eos_data": [
+ {
+ "portChannels": {
+ "Port-Channel42": {
+ "interfaces": {
+ "Ethernet8": {
+ "actorPortStatus": "noAgg",
+ "illegalRxCount": 0,
+ "markerResponseTxCount": 0,
+ "markerResponseRxCount": 0,
+ "lacpdusRxCount": 0,
+ "lacpdusTxCount": 454,
+ "markersTxCount": 0,
+ "markersRxCount": 0,
+ }
+ }
+ }
+ },
+ "orphanPorts": {},
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyIllegalLACP,
+ "eos_data": [
+ {
+ "portChannels": {
+ "Port-Channel42": {
+ "interfaces": {
+ "Ethernet8": {
+ "actorPortStatus": "noAgg",
+ "illegalRxCount": 666,
+ "markerResponseTxCount": 0,
+ "markerResponseRxCount": 0,
+ "lacpdusRxCount": 0,
+ "lacpdusTxCount": 454,
+ "markersTxCount": 0,
+ "markersRxCount": 0,
+ }
+ }
+ }
+ },
+ "orphanPorts": {},
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": ["The following port-channels have recieved illegal lacp packets on the following ports: [{'Port-Channel42': 'Ethernet8'}]"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyLoopbackCount,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Loopback42": {
+ "name": "Loopback42",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "up",
+ "mtu": 65535,
+ },
+ "Loopback666": {
+ "name": "Loopback666",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 32, "address": "6.6.6.6"}},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "up",
+ "mtu": 65535,
+ },
+ }
+ }
+ ],
+ "inputs": {"number": 2},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-loopback-down",
+ "test": VerifyLoopbackCount,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Loopback42": {
+ "name": "Loopback42",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "up",
+ "mtu": 65535,
+ },
+ "Loopback666": {
+ "name": "Loopback666",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 32, "address": "6.6.6.6"}},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "down",
+ "mtu": 65535,
+ },
+ }
+ }
+ ],
+ "inputs": {"number": 2},
+ "expected": {"result": "failure", "messages": ["The following Loopbacks are not up: ['Loopback666']"]},
+ },
+ {
+ "name": "failure-count-loopback",
+ "test": VerifyLoopbackCount,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Loopback42": {
+ "name": "Loopback42",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "up",
+ "mtu": 65535,
+ },
+ }
+ }
+ ],
+ "inputs": {"number": 2},
+ "expected": {"result": "failure", "messages": ["Found 1 Loopbacks when expecting 2"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySVI,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Vlan42": {
+ "name": "Vlan42",
+ "interfaceStatus": "connected",
+ "interfaceAddress": {"ipAddr": {"maskLen": 24, "address": "11.11.11.11"}},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "up",
+ "mtu": 1500,
+ }
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifySVI,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Vlan42": {
+ "name": "Vlan42",
+ "interfaceStatus": "notconnect",
+ "interfaceAddress": {"ipAddr": {"maskLen": 24, "address": "11.11.11.11"}},
+ "ipv4Routable240": False,
+ "lineProtocolStatus": "lowerLayerDown",
+ "mtu": 1500,
+ }
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following SVIs are not up: ['Vlan42']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyL3MTU,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": True,
+ "l2Mru": 0,
+ },
+ "Ethernet10": {
+ "name": "Ethernet10",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Management1/1": {
+ "name": "Management0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Port-Channel2": {
+ "name": "Port-Channel2",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "lowerLayerDown",
+ "interfaceStatus": "notconnect",
+ "hardware": "portChannel",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Loopback0": {
+ "name": "Loopback0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "loopback",
+ "mtu": 65535,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Vxlan1": {
+ "name": "Vxlan1",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "down",
+ "interfaceStatus": "notconnect",
+ "hardware": "vxlan",
+ "mtu": 0,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ },
+ }
+ ],
+ "inputs": {"mtu": 1500},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success",
+ "test": VerifyL3MTU,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": True,
+ "l2Mru": 0,
+ },
+ "Ethernet10": {
+ "name": "Ethernet10",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1501,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Management0": {
+ "name": "Management0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Port-Channel2": {
+ "name": "Port-Channel2",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "lowerLayerDown",
+ "interfaceStatus": "notconnect",
+ "hardware": "portChannel",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Loopback0": {
+ "name": "Loopback0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "loopback",
+ "mtu": 65535,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Vxlan1": {
+ "name": "Vxlan1",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "down",
+ "interfaceStatus": "notconnect",
+ "hardware": "vxlan",
+ "mtu": 0,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ },
+ }
+ ],
+ "inputs": {"mtu": 1500, "ignored_interfaces": ["Loopback", "Port-Channel", "Management", "Vxlan"], "specific_mtu": [{"Ethernet10": 1501}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyL3MTU,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1600,
+ "l3MtuConfigured": True,
+ "l2Mru": 0,
+ },
+ "Ethernet10": {
+ "name": "Ethernet10",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Management0": {
+ "name": "Management0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Port-Channel2": {
+ "name": "Port-Channel2",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "lowerLayerDown",
+ "interfaceStatus": "notconnect",
+ "hardware": "portChannel",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Loopback0": {
+ "name": "Loopback0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "loopback",
+ "mtu": 65535,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Vxlan1": {
+ "name": "Vxlan1",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "down",
+ "interfaceStatus": "notconnect",
+ "hardware": "vxlan",
+ "mtu": 0,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ },
+ }
+ ],
+ "inputs": {"mtu": 1500},
+ "expected": {"result": "failure", "messages": ["Some interfaces do not have correct MTU configured:\n[{'Ethernet2': 1600}]"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyL2MTU,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": True,
+ "l2Mru": 0,
+ },
+ "Ethernet10": {
+ "name": "Ethernet10",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 9214,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Management0": {
+ "name": "Management0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Port-Channel2": {
+ "name": "Port-Channel2",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "lowerLayerDown",
+ "interfaceStatus": "notconnect",
+ "hardware": "portChannel",
+ "mtu": 9214,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Loopback0": {
+ "name": "Loopback0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "loopback",
+ "mtu": 65535,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Vxlan1": {
+ "name": "Vxlan1",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "down",
+ "interfaceStatus": "notconnect",
+ "hardware": "vxlan",
+ "mtu": 0,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ },
+ }
+ ],
+ "inputs": {"mtu": 9214},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyL2MTU,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1600,
+ "l3MtuConfigured": True,
+ "l2Mru": 0,
+ },
+ "Ethernet10": {
+ "name": "Ethernet10",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 9214,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Management0": {
+ "name": "Management0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "ethernet",
+ "mtu": 1500,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Port-Channel2": {
+ "name": "Port-Channel2",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "lowerLayerDown",
+ "interfaceStatus": "notconnect",
+ "hardware": "portChannel",
+ "mtu": 9214,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Loopback0": {
+ "name": "Loopback0",
+ "forwardingModel": "routed",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "hardware": "loopback",
+ "mtu": 65535,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ "Vxlan1": {
+ "name": "Vxlan1",
+ "forwardingModel": "bridged",
+ "lineProtocolStatus": "down",
+ "interfaceStatus": "notconnect",
+ "hardware": "vxlan",
+ "mtu": 0,
+ "l3MtuConfigured": False,
+ "l2Mru": 0,
+ },
+ },
+ }
+ ],
+ "inputs": {"mtu": 1500},
+ "expected": {"result": "failure", "messages": ["Some L2 interfaces do not have correct MTU configured:\n[{'Ethernet10': 9214}, {'Port-Channel2': 9214}]"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyIPProxyARP,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet1": {
+ "name": "Ethernet1",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "mtu": 1500,
+ "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.0", "maskLen": 31}},
+ "ipv4Routable240": False,
+ "ipv4Routable0": False,
+ "enabled": True,
+ "description": "P2P_LINK_TO_NW-CORE_Ethernet1",
+ "proxyArp": True,
+ "localProxyArp": False,
+ "gratuitousArp": False,
+ "vrf": "default",
+ "urpf": "disable",
+ "addresslessForwarding": "isInvalid",
+ "directedBroadcastEnabled": False,
+ "maxMssIngress": 0,
+ "maxMssEgress": 0,
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "mtu": 1500,
+ "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.2", "maskLen": 31}},
+ "ipv4Routable240": False,
+ "ipv4Routable0": False,
+ "enabled": True,
+ "description": "P2P_LINK_TO_SW-CORE_Ethernet1",
+ "proxyArp": True,
+ "localProxyArp": False,
+ "gratuitousArp": False,
+ "vrf": "default",
+ "urpf": "disable",
+ "addresslessForwarding": "isInvalid",
+ "directedBroadcastEnabled": False,
+ "maxMssIngress": 0,
+ "maxMssEgress": 0,
+ }
+ }
+ },
+ ],
+ "inputs": {"interfaces": ["Ethernet1", "Ethernet2"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyIPProxyARP,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet1": {
+ "name": "Ethernet1",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "mtu": 1500,
+ "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.0", "maskLen": 31}},
+ "ipv4Routable240": False,
+ "ipv4Routable0": False,
+ "enabled": True,
+ "description": "P2P_LINK_TO_NW-CORE_Ethernet1",
+ "proxyArp": True,
+ "localProxyArp": False,
+ "gratuitousArp": False,
+ "vrf": "default",
+ "urpf": "disable",
+ "addresslessForwarding": "isInvalid",
+ "directedBroadcastEnabled": False,
+ "maxMssIngress": 0,
+ "maxMssEgress": 0,
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "name": "Ethernet2",
+ "lineProtocolStatus": "up",
+ "interfaceStatus": "connected",
+ "mtu": 1500,
+ "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.2", "maskLen": 31}},
+ "ipv4Routable240": False,
+ "ipv4Routable0": False,
+ "enabled": True,
+ "description": "P2P_LINK_TO_SW-CORE_Ethernet1",
+ "proxyArp": False,
+ "localProxyArp": False,
+ "gratuitousArp": False,
+ "vrf": "default",
+ "urpf": "disable",
+ "addresslessForwarding": "isInvalid",
+ "directedBroadcastEnabled": False,
+ "maxMssIngress": 0,
+ "maxMssEgress": 0,
+ }
+ }
+ },
+ ],
+ "inputs": {"interfaces": ["Ethernet1", "Ethernet2"]},
+ "expected": {"result": "failure", "messages": ["The following interface(s) have Proxy-ARP disabled: ['Ethernet2']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.0", "maskLen": 31},
+ "secondaryIpsOrderedList": [{"address": "10.10.10.0", "maskLen": 31}, {"address": "10.10.10.10", "maskLen": 31}],
+ }
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet12": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.10", "maskLen": 31},
+ "secondaryIpsOrderedList": [{"address": "10.10.10.10", "maskLen": 31}, {"address": "10.10.10.20", "maskLen": 31}],
+ }
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]},
+ {"name": "Ethernet12", "primary_ip": "172.30.11.10/31", "secondary_ips": ["10.10.10.10/31", "10.10.10.20/31"]},
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-without-secondary-ip",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.0", "maskLen": 31},
+ "secondaryIpsOrderedList": [],
+ }
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet12": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.10", "maskLen": 31},
+ "secondaryIpsOrderedList": [],
+ }
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.0/31"},
+ {"name": "Ethernet12", "primary_ip": "172.30.11.10/31"},
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-l3-interface",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [{"interfaces": {"Ethernet2": {"interfaceAddress": {}}}}, {"interfaces": {"Ethernet12": {"interfaceAddress": {}}}}],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]},
+ {"name": "Ethernet12", "primary_ip": "172.30.11.20/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["For interface `Ethernet2`, IP address is not configured.", "For interface `Ethernet12`, IP address is not configured."],
+ },
+ },
+ {
+ "name": "failure-ip-address-not-configured",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "0.0.0.0", "maskLen": 0},
+ "secondaryIpsOrderedList": [],
+ }
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet12": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "0.0.0.0", "maskLen": 0},
+ "secondaryIpsOrderedList": [],
+ }
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]},
+ {"name": "Ethernet12", "primary_ip": "172.30.11.10/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "For interface `Ethernet2`, The expected primary IP address is `172.30.11.0/31`, but the actual primary IP address is `0.0.0.0/0`. "
+ "The expected secondary IP addresses are `['10.10.10.0/31', '10.10.10.10/31']`, but the actual secondary IP address is not configured.",
+ "For interface `Ethernet12`, The expected primary IP address is `172.30.11.10/31`, but the actual primary IP address is `0.0.0.0/0`. "
+ "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP address is not configured.",
+ ],
+ },
+ },
+ {
+ "name": "failure-ip-address-missmatch",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.0", "maskLen": 31},
+ "secondaryIpsOrderedList": [{"address": "10.10.10.0", "maskLen": 31}, {"address": "10.10.10.10", "maskLen": 31}],
+ }
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet3": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.10.10", "maskLen": 31},
+ "secondaryIpsOrderedList": [{"address": "10.10.11.0", "maskLen": 31}, {"address": "10.11.11.10", "maskLen": 31}],
+ }
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.2/31", "secondary_ips": ["10.10.10.20/31", "10.10.10.30/31"]},
+ {"name": "Ethernet3", "primary_ip": "172.30.10.2/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "For interface `Ethernet2`, The expected primary IP address is `172.30.11.2/31`, but the actual primary IP address is `172.30.11.0/31`. "
+ "The expected secondary IP addresses are `['10.10.10.20/31', '10.10.10.30/31']`, but the actual secondary IP addresses are "
+ "`['10.10.10.0/31', '10.10.10.10/31']`.",
+ "For interface `Ethernet3`, The expected primary IP address is `172.30.10.2/31`, but the actual primary IP address is `172.30.10.10/31`. "
+ "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP addresses are "
+ "`['10.10.11.0/31', '10.11.11.10/31']`.",
+ ],
+ },
+ },
+ {
+ "name": "failure-secondary-ip-address",
+ "test": VerifyInterfaceIPv4,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet2": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.11.0", "maskLen": 31},
+ "secondaryIpsOrderedList": [],
+ }
+ }
+ }
+ },
+ {
+ "interfaces": {
+ "Ethernet3": {
+ "interfaceAddress": {
+ "primaryIp": {"address": "172.30.10.10", "maskLen": 31},
+ "secondaryIpsOrderedList": [{"address": "10.10.11.0", "maskLen": 31}, {"address": "10.11.11.10", "maskLen": 31}],
+ }
+ }
+ }
+ },
+ ],
+ "inputs": {
+ "interfaces": [
+ {"name": "Ethernet2", "primary_ip": "172.30.11.2/31", "secondary_ips": ["10.10.10.20/31", "10.10.10.30/31"]},
+ {"name": "Ethernet3", "primary_ip": "172.30.10.2/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "For interface `Ethernet2`, The expected primary IP address is `172.30.11.2/31`, but the actual primary IP address is `172.30.11.0/31`. "
+ "The expected secondary IP addresses are `['10.10.10.20/31', '10.10.10.30/31']`, but the actual secondary IP address is not configured.",
+ "For interface `Ethernet3`, The expected primary IP address is `172.30.10.2/31`, but the actual primary IP address is `172.30.10.10/31`. "
+ "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP addresses are "
+ "`['10.10.11.0/31', '10.11.11.10/31']`.",
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyIpVirtualRouterMac,
+ "eos_data": [
+ {
+ "virtualMacs": [
+ {
+ "macAddress": "00:1c:73:00:dc:01",
+ }
+ ],
+ }
+ ],
+ "inputs": {"mac_address": "00:1c:73:00:dc:01"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "faliure-incorrect-mac-address",
+ "test": VerifyIpVirtualRouterMac,
+ "eos_data": [
+ {
+ "virtualMacs": [
+ {
+ "macAddress": "00:00:00:00:00:00",
+ }
+ ],
+ }
+ ],
+ "inputs": {"mac_address": "00:1c:73:00:dc:01"},
+ "expected": {"result": "failure", "messages": ["IP virtual router MAC address `00:1c:73:00:dc:01` is not configured."]},
+ },
+]
diff --git a/tests/units/anta_tests/test_lanz.py b/tests/units/anta_tests/test_lanz.py
new file mode 100644
index 0000000..932d1ac
--- /dev/null
+++ b/tests/units/anta_tests/test_lanz.py
@@ -0,0 +1,27 @@
+# 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.
+"""Data for testing anta.tests.configuration"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyLANZ,
+ "eos_data": [{"lanzEnabled": True}],
+ "inputs": None,
+ "expected": {"result": "success", "messages": ["LANZ is enabled"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLANZ,
+ "eos_data": [{"lanzEnabled": False}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["LANZ is not enabled"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_logging.py b/tests/units/anta_tests/test_logging.py
new file mode 100644
index 0000000..8ac2323
--- /dev/null
+++ b/tests/units/anta_tests/test_logging.py
@@ -0,0 +1,254 @@
+# 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.
+"""Data for testing anta.tests.logging"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.logging import (
+ VerifyLoggingAccounting,
+ VerifyLoggingErrors,
+ VerifyLoggingHostname,
+ VerifyLoggingHosts,
+ VerifyLoggingLogsGeneration,
+ VerifyLoggingPersistent,
+ VerifyLoggingSourceIntf,
+ VerifyLoggingTimestamp,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyLoggingPersistent,
+ "eos_data": [
+ "Persistent logging: level debugging\n",
+ """Directory of flash:/persist/messages
+
+ -rw- 9948 May 10 13:54 messages
+
+ 33214693376 bytes total (10081136640 bytes free)
+
+ """,
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-disabled",
+ "test": VerifyLoggingPersistent,
+ "eos_data": [
+ "Persistent logging: disabled\n",
+ """Directory of flash:/persist/messages
+
+ -rw- 0 Apr 13 16:29 messages
+
+ 33214693376 bytes total (10082168832 bytes free)
+
+ """,
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Persistent logging is disabled"]},
+ },
+ {
+ "name": "failure-not-saved",
+ "test": VerifyLoggingPersistent,
+ "eos_data": [
+ "Persistent logging: level debugging\n",
+ """Directory of flash:/persist/messages
+
+ -rw- 0 Apr 13 16:29 messages
+
+ 33214693376 bytes total (10082168832 bytes free)
+
+ """,
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["No persistent logs are saved in flash"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingSourceIntf,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.93' port 514 in VRF MGMT via tcp
+ Logging to '10.22.10.94' port 911 in VRF MGMT via udp
+
+ """
+ ],
+ "inputs": {"interface": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-intf",
+ "test": VerifyLoggingSourceIntf,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management1', IP Address 172.20.20.12 in VRF MGMT
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.93' port 514 in VRF MGMT via tcp
+ Logging to '10.22.10.94' port 911 in VRF MGMT via udp
+
+ """
+ ],
+ "inputs": {"interface": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Source-interface 'Management0' is not configured in VRF MGMT"]},
+ },
+ {
+ "name": "failure-vrf",
+ "test": VerifyLoggingSourceIntf,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF default
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.93' port 514 in VRF MGMT via tcp
+ Logging to '10.22.10.94' port 911 in VRF MGMT via udp
+
+ """
+ ],
+ "inputs": {"interface": "Management0", "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Source-interface 'Management0' is not configured in VRF MGMT"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingHosts,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.93' port 514 in VRF MGMT via tcp
+ Logging to '10.22.10.94' port 911 in VRF MGMT via udp
+
+ """
+ ],
+ "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-hosts",
+ "test": VerifyLoggingHosts,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management1', IP Address 172.20.20.12 in VRF MGMT
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.103' port 514 in VRF MGMT via tcp
+ Logging to '10.22.10.104' port 911 in VRF MGMT via udp
+
+ """
+ ],
+ "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Syslog servers ['10.22.10.93', '10.22.10.94'] are not configured in VRF MGMT"]},
+ },
+ {
+ "name": "failure-vrf",
+ "test": VerifyLoggingHosts,
+ "eos_data": [
+ """Trap logging: level informational
+ Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT
+ Logging to '10.22.10.92' port 514 in VRF MGMT via udp
+ Logging to '10.22.10.93' port 514 in VRF default via tcp
+ Logging to '10.22.10.94' port 911 in VRF default via udp
+
+ """
+ ],
+ "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Syslog servers ['10.22.10.93', '10.22.10.94'] are not configured in VRF MGMT"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingLogsGeneration,
+ "eos_data": [
+ "",
+ "2023-05-10T13:54:21.463497-05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: "
+ "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingLogsGeneration validation\n",
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLoggingLogsGeneration,
+ "eos_data": ["", "Log Buffer:\n"],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Logs are not generated"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingHostname,
+ "eos_data": [
+ {"hostname": "NW-CORE", "fqdn": "NW-CORE.example.org"},
+ "",
+ "2023-05-10T15:41:44.701810-05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: "
+ "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingHostname validation\n",
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLoggingHostname,
+ "eos_data": [
+ {"hostname": "NW-CORE", "fqdn": "NW-CORE.example.org"},
+ "",
+ "2023-05-10T13:54:21.463497-05:00 NW-CORE ConfigAgent: %SYS-6-LOGMSG_INFO: "
+ "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingLogsHostname validation\n",
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Logs are not generated with the device FQDN"]},
+ },
+ {
+ "name": "success",
+ "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",
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLoggingTimestamp,
+ "eos_data": [
+ "",
+ "May 10 13:54:22 NE-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: "
+ "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingTimestamp validation\n",
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Logs are not generated with the appropriate timestamp format"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingAccounting,
+ "eos_data": ["2023 May 10 15:50:31 arista command-api 10.22.1.107 stop service=shell priv-lvl=15 cmd=show aaa accounting logs | tail\n"],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLoggingAccounting,
+ "eos_data": ["2023 May 10 15:52:26 arista vty14 10.22.1.107 stop service=shell priv-lvl=15 cmd=show bgp summary\n"],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["AAA accounting logs are not generated"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyLoggingErrors,
+ "eos_data": [""],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyLoggingErrors,
+ "eos_data": [
+ "Aug 2 19:57:42 DC1-LEAF1A Mlag: %FWK-3-SOCKET_CLOSE_REMOTE: Connection to Mlag (pid:27200) at tbt://192.168.0.1:4432/+n closed by peer (EOF)"
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device has reported syslog messages with a severity of ERRORS or higher"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_mlag.py b/tests/units/anta_tests/test_mlag.py
new file mode 100644
index 0000000..90f3c7a
--- /dev/null
+++ b/tests/units/anta_tests/test_mlag.py
@@ -0,0 +1,343 @@
+# 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.tests.mlag.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyMlagStatus,
+ "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "up", "localIntfStatus": "up"}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped",
+ "test": VerifyMlagStatus,
+ "eos_data": [
+ {
+ "state": "disabled",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyMlagStatus,
+ "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "down", "localIntfStatus": "up"}],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": ["MLAG status is not OK: {'state': 'active', 'negStatus': 'connected', 'localIntfStatus': 'up', 'peerLinkStatus': 'down'}"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyMlagInterfaces,
+ "eos_data": [
+ {
+ "state": "active",
+ "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 0, "Active-full": 1},
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped",
+ "test": VerifyMlagInterfaces,
+ "eos_data": [
+ {
+ "state": "disabled",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
+ },
+ {
+ "name": "failure-active-partial",
+ "test": VerifyMlagInterfaces,
+ "eos_data": [
+ {
+ "state": "active",
+ "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 1, "Active-full": 1},
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 0, 'Active-partial': 1, 'Active-full': 1}"],
+ },
+ },
+ {
+ "name": "failure-inactive",
+ "test": VerifyMlagInterfaces,
+ "eos_data": [
+ {
+ "state": "active",
+ "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 1, "Active-partial": 1, "Active-full": 1},
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 1, 'Active-partial': 1, 'Active-full': 1}"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyMlagConfigSanity,
+ "eos_data": [{"globalConfiguration": {}, "interfaceConfiguration": {}, "mlagActive": True, "mlagConnected": True}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped",
+ "test": VerifyMlagConfigSanity,
+ "eos_data": [
+ {
+ "mlagActive": False,
+ }
+ ],
+ "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,
+ "eos_data": [
+ {
+ "globalConfiguration": {"mlag": {"globalParameters": {"dual-primary-detection-delay": {"localValue": "0", "peerValue": "200"}}}},
+ "interfaceConfiguration": {},
+ "mlagActive": True,
+ "mlagConnected": True,
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "MLAG config-sanity returned inconsistencies: "
+ "{'globalConfiguration': {'mlag': {'globalParameters': "
+ "{'dual-primary-detection-delay': {'localValue': '0', 'peerValue': '200'}}}}, "
+ "'interfaceConfiguration': {}}"
+ ],
+ },
+ },
+ {
+ "name": "failure-interface",
+ "test": VerifyMlagConfigSanity,
+ "eos_data": [
+ {
+ "globalConfiguration": {},
+ "interfaceConfiguration": {"trunk-native-vlan mlag30": {"interface": {"Port-Channel30": {"localValue": "123", "peerValue": "3700"}}}},
+ "mlagActive": True,
+ "mlagConnected": True,
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "MLAG config-sanity returned inconsistencies: "
+ "{'globalConfiguration': {}, "
+ "'interfaceConfiguration': {'trunk-native-vlan mlag30': "
+ "{'interface': {'Port-Channel30': {'localValue': '123', 'peerValue': '3700'}}}}}"
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyMlagReloadDelay,
+ "eos_data": [{"state": "active", "reloadDelay": 300, "reloadDelayNonMlag": 330}],
+ "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped-disabled",
+ "test": VerifyMlagReloadDelay,
+ "eos_data": [
+ {
+ "state": "disabled",
+ }
+ ],
+ "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330},
+ "expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyMlagReloadDelay,
+ "eos_data": [{"state": "active", "reloadDelay": 400, "reloadDelayNonMlag": 430}],
+ "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330},
+ "expected": {"result": "failure", "messages": ["The reload-delay parameters are not configured properly: {'reloadDelay': 400, 'reloadDelayNonMlag': 430}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyMlagDualPrimary,
+ "eos_data": [
+ {
+ "state": "active",
+ "dualPrimaryDetectionState": "configured",
+ "dualPrimaryPortsErrdisabled": False,
+ "dualPrimaryMlagRecoveryDelay": 60,
+ "dualPrimaryNonMlagRecoveryDelay": 0,
+ "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"},
+ }
+ ],
+ "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped-disabled",
+ "test": VerifyMlagDualPrimary,
+ "eos_data": [
+ {
+ "state": "disabled",
+ }
+ ],
+ "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
+ "expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
+ },
+ {
+ "name": "failure-disabled",
+ "test": VerifyMlagDualPrimary,
+ "eos_data": [
+ {
+ "state": "active",
+ "dualPrimaryDetectionState": "disabled",
+ "dualPrimaryPortsErrdisabled": False,
+ }
+ ],
+ "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
+ "expected": {"result": "failure", "messages": ["Dual-primary detection is disabled"]},
+ },
+ {
+ "name": "failure-wrong-timers",
+ "test": VerifyMlagDualPrimary,
+ "eos_data": [
+ {
+ "state": "active",
+ "dualPrimaryDetectionState": "configured",
+ "dualPrimaryPortsErrdisabled": False,
+ "dualPrimaryMlagRecoveryDelay": 160,
+ "dualPrimaryNonMlagRecoveryDelay": 0,
+ "detail": {"dualPrimaryDetectionDelay": 300, "dualPrimaryAction": "none"},
+ }
+ ],
+ "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ (
+ "The dual-primary parameters are not configured properly: "
+ "{'detail.dualPrimaryDetectionDelay': 300, "
+ "'detail.dualPrimaryAction': 'none', "
+ "'dualPrimaryMlagRecoveryDelay': 160, "
+ "'dualPrimaryNonMlagRecoveryDelay': 0}"
+ )
+ ],
+ },
+ },
+ {
+ "name": "failure-wrong-action",
+ "test": VerifyMlagDualPrimary,
+ "eos_data": [
+ {
+ "state": "active",
+ "dualPrimaryDetectionState": "configured",
+ "dualPrimaryPortsErrdisabled": False,
+ "dualPrimaryMlagRecoveryDelay": 60,
+ "dualPrimaryNonMlagRecoveryDelay": 0,
+ "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"},
+ }
+ ],
+ "inputs": {"detection_delay": 200, "errdisabled": True, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ (
+ "The dual-primary parameters are not configured properly: "
+ "{'detail.dualPrimaryDetectionDelay': 200, "
+ "'detail.dualPrimaryAction': 'none', "
+ "'dualPrimaryMlagRecoveryDelay': 60, "
+ "'dualPrimaryNonMlagRecoveryDelay': 0}"
+ )
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyMlagPrimaryPriority,
+ "eos_data": [
+ {
+ "state": "active",
+ "detail": {"mlagState": "primary", "primaryPriority": 32767},
+ }
+ ],
+ "inputs": {
+ "primary_priority": 32767,
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped-disabled",
+ "test": VerifyMlagPrimaryPriority,
+ "eos_data": [
+ {
+ "state": "disabled",
+ }
+ ],
+ "inputs": {"primary_priority": 32767},
+ "expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
+ },
+ {
+ "name": "failure-not-primary",
+ "test": VerifyMlagPrimaryPriority,
+ "eos_data": [
+ {
+ "state": "active",
+ "detail": {"mlagState": "secondary", "primaryPriority": 32767},
+ }
+ ],
+ "inputs": {"primary_priority": 32767},
+ "expected": {
+ "result": "failure",
+ "messages": ["The device is not set as MLAG primary."],
+ },
+ },
+ {
+ "name": "failure-incorrect-priority",
+ "test": VerifyMlagPrimaryPriority,
+ "eos_data": [
+ {
+ "state": "active",
+ "detail": {"mlagState": "secondary", "primaryPriority": 32767},
+ }
+ ],
+ "inputs": {"primary_priority": 1},
+ "expected": {
+ "result": "failure",
+ "messages": ["The device is not set as MLAG primary.", "The primary priority does not match expected. Expected `1`, but found `32767` instead."],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_multicast.py b/tests/units/anta_tests/test_multicast.py
new file mode 100644
index 0000000..9276a9f
--- /dev/null
+++ b/tests/units/anta_tests/test_multicast.py
@@ -0,0 +1,175 @@
+# 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.multicast"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success-enabled",
+ "test": VerifyIGMPSnoopingVlans,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "enabled",
+ "vlans": {
+ "1": {
+ "reportFlooding": "disabled",
+ "proxyActive": False,
+ "groupsOverrun": False,
+ "multicastRouterLearningMode": "pim-dvmrp",
+ "igmpSnoopingState": "enabled",
+ "pruningActive": False,
+ "maxGroups": 65534,
+ "immediateLeave": "default",
+ "floodingTraffic": True,
+ },
+ "42": {
+ "reportFlooding": "disabled",
+ "proxyActive": False,
+ "groupsOverrun": False,
+ "multicastRouterLearningMode": "pim-dvmrp",
+ "igmpSnoopingState": "enabled",
+ "pruningActive": False,
+ "maxGroups": 65534,
+ "immediateLeave": "default",
+ "floodingTraffic": True,
+ },
+ },
+ "robustness": 2,
+ "immediateLeave": "enabled",
+ "reportFloodingSwitchPorts": [],
+ }
+ ],
+ "inputs": {"vlans": {1: True, 42: True}},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-disabled",
+ "test": VerifyIGMPSnoopingVlans,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "enabled",
+ "vlans": {
+ "42": {
+ "reportFlooding": "disabled",
+ "proxyActive": False,
+ "groupsOverrun": False,
+ "multicastRouterLearningMode": "pim-dvmrp",
+ "igmpSnoopingState": "disabled",
+ "pruningActive": False,
+ "maxGroups": 65534,
+ "immediateLeave": "default",
+ "floodingTraffic": True,
+ }
+ },
+ "robustness": 2,
+ "immediateLeave": "enabled",
+ "reportFloodingSwitchPorts": [],
+ }
+ ],
+ "inputs": {"vlans": {42: False}},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-missing-vlan",
+ "test": VerifyIGMPSnoopingVlans,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "enabled",
+ "vlans": {
+ "1": {
+ "reportFlooding": "disabled",
+ "proxyActive": False,
+ "groupsOverrun": False,
+ "multicastRouterLearningMode": "pim-dvmrp",
+ "igmpSnoopingState": "enabled",
+ "pruningActive": False,
+ "maxGroups": 65534,
+ "immediateLeave": "default",
+ "floodingTraffic": True,
+ },
+ },
+ "robustness": 2,
+ "immediateLeave": "enabled",
+ "reportFloodingSwitchPorts": [],
+ }
+ ],
+ "inputs": {"vlans": {1: False, 42: False}},
+ "expected": {"result": "failure", "messages": ["IGMP state for vlan 1 is enabled", "Supplied vlan 42 is not present on the device."]},
+ },
+ {
+ "name": "failure-wrong-state",
+ "test": VerifyIGMPSnoopingVlans,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "enabled",
+ "vlans": {
+ "1": {
+ "reportFlooding": "disabled",
+ "proxyActive": False,
+ "groupsOverrun": False,
+ "multicastRouterLearningMode": "pim-dvmrp",
+ "igmpSnoopingState": "disabled",
+ "pruningActive": False,
+ "maxGroups": 65534,
+ "immediateLeave": "default",
+ "floodingTraffic": True,
+ },
+ },
+ "robustness": 2,
+ "immediateLeave": "enabled",
+ "reportFloodingSwitchPorts": [],
+ }
+ ],
+ "inputs": {"vlans": {1: True}},
+ "expected": {"result": "failure", "messages": ["IGMP state for vlan 1 is disabled"]},
+ },
+ {
+ "name": "success-enabled",
+ "test": VerifyIGMPSnoopingGlobal,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "enabled",
+ "robustness": 2,
+ "immediateLeave": "enabled",
+ "reportFloodingSwitchPorts": [],
+ }
+ ],
+ "inputs": {"enabled": True},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-disabled",
+ "test": VerifyIGMPSnoopingGlobal,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "disabled",
+ }
+ ],
+ "inputs": {"enabled": False},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-state",
+ "test": VerifyIGMPSnoopingGlobal,
+ "eos_data": [
+ {
+ "reportFlooding": "disabled",
+ "igmpSnoopingState": "disabled",
+ }
+ ],
+ "inputs": {"enabled": True},
+ "expected": {"result": "failure", "messages": ["IGMP state is not valid: disabled"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_profiles.py b/tests/units/anta_tests/test_profiles.py
new file mode 100644
index 0000000..c0ebb57
--- /dev/null
+++ b/tests/units/anta_tests/test_profiles.py
@@ -0,0 +1,47 @@
+# 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.tests.profiles.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyUnifiedForwardingTableMode,
+ "eos_data": [{"uftMode": "2", "urpfEnabled": False, "chipModel": "bcm56870", "l2TableSize": 163840, "l3TableSize": 147456, "lpmTableSize": 32768}],
+ "inputs": {"mode": 2},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyUnifiedForwardingTableMode,
+ "eos_data": [{"uftMode": "2", "urpfEnabled": False, "chipModel": "bcm56870", "l2TableSize": 163840, "l3TableSize": 147456, "lpmTableSize": 32768}],
+ "inputs": {"mode": 3},
+ "expected": {"result": "failure", "messages": ["Device is not running correct UFT mode (expected: 3 / running: 2)"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTcamProfile,
+ "eos_data": [
+ {"pmfProfiles": {"FixedSystem": {"config": "test", "configType": "System Profile", "status": "test", "mode": "tcam"}}, "lastProgrammingStatus": {}}
+ ],
+ "inputs": {"profile": "test"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyTcamProfile,
+ "eos_data": [
+ {"pmfProfiles": {"FixedSystem": {"config": "test", "configType": "System Profile", "status": "default", "mode": "tcam"}}, "lastProgrammingStatus": {}}
+ ],
+ "inputs": {"profile": "test"},
+ "expected": {"result": "failure", "messages": ["Incorrect profile running on device: default"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_ptp.py b/tests/units/anta_tests/test_ptp.py
new file mode 100644
index 0000000..3969c97
--- /dev/null
+++ b/tests/units/anta_tests/test_ptp.py
@@ -0,0 +1,42 @@
+# 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.
+"""Data for testing anta.tests.configuration"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.ptp import VerifyPtpStatus
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyPtpStatus,
+ "eos_data": [
+ {
+ "ptpMode": "ptpBoundaryClock",
+ "ptpProfile": "ptpDefaultProfile",
+ "ptpClockSummary": {
+ "clockIdentity": "0xcc:1a:a3:ff:ff:c3:bf:eb",
+ "gmClockIdentity": "0x00:00:00:00:00:00:00:00",
+ "numberOfSlavePorts": 0,
+ "numberOfMasterPorts": 0,
+ "offsetFromMaster": 0,
+ "meanPathDelay": 0,
+ "stepsRemoved": 0,
+ "skew": 1.0,
+ },
+ "ptpIntfSummaries": {},
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyPtpStatus,
+ "eos_data": [{"ptpIntfSummaries": {}}],
+ "inputs": None,
+ "expected": {"result": "failure"},
+ },
+]
diff --git a/tests/units/anta_tests/test_security.py b/tests/units/anta_tests/test_security.py
new file mode 100644
index 0000000..17fa04e
--- /dev/null
+++ b/tests/units/anta_tests/test_security.py
@@ -0,0 +1,900 @@
+# 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.tests.security.py
+"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.security import (
+ VerifyAPIHttpsSSL,
+ VerifyAPIHttpStatus,
+ VerifyAPIIPv4Acl,
+ VerifyAPIIPv6Acl,
+ VerifyAPISSLCertificate,
+ VerifyBannerLogin,
+ VerifyBannerMotd,
+ VerifyIPv4ACL,
+ VerifySSHIPv4Acl,
+ VerifySSHIPv6Acl,
+ VerifySSHStatus,
+ VerifyTelnetStatus,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifySSHStatus,
+ "eos_data": ["SSHD status for Default VRF is disabled\nSSH connection limit is 50\nSSH per host connection limit is 20\nFIPS status: disabled\n\n"],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "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",
+ "test": VerifySSHIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SSH", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifySSHIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 SSH IPv4 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifySSHIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SSH", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["SSH IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_SSH']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySSHIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SSH", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifySSHIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 SSH IPv6 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifySSHIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SSH", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["SSH IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_SSH']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTelnetStatus,
+ "eos_data": [{"serverState": "disabled", "vrfName": "default", "maxTelnetSessions": 20, "maxTelnetSessionsPerHost": 20}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyTelnetStatus,
+ "eos_data": [{"serverState": "enabled", "vrfName": "default", "maxTelnetSessions": 20, "maxTelnetSessionsPerHost": 20}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Telnet status for Default VRF is enabled"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAPIHttpStatus,
+ "eos_data": [
+ {
+ "enabled": True,
+ "httpServer": {"configured": False, "running": False, "port": 80},
+ "localHttpServer": {"configured": False, "running": False, "port": 8080},
+ "httpsServer": {"configured": True, "running": True, "port": 443},
+ "unixSocketServer": {"configured": False, "running": False},
+ "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"},
+ "tlsProtocol": ["1.2"],
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyAPIHttpStatus,
+ "eos_data": [
+ {
+ "enabled": True,
+ "httpServer": {"configured": True, "running": True, "port": 80},
+ "localHttpServer": {"configured": False, "running": False, "port": 8080},
+ "httpsServer": {"configured": True, "running": True, "port": 443},
+ "unixSocketServer": {"configured": False, "running": False},
+ "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"},
+ "tlsProtocol": ["1.2"],
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["eAPI HTTP server is enabled globally"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAPIHttpsSSL,
+ "eos_data": [
+ {
+ "enabled": True,
+ "httpServer": {"configured": False, "running": False, "port": 80},
+ "localHttpServer": {"configured": False, "running": False, "port": 8080},
+ "httpsServer": {"configured": True, "running": True, "port": 443},
+ "unixSocketServer": {"configured": False, "running": False},
+ "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"},
+ "tlsProtocol": ["1.2"],
+ }
+ ],
+ "inputs": {"profile": "API_SSL_Profile"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-not-configured",
+ "test": VerifyAPIHttpsSSL,
+ "eos_data": [
+ {
+ "enabled": True,
+ "httpServer": {"configured": True, "running": True, "port": 80},
+ "localHttpServer": {"configured": False, "running": False, "port": 8080},
+ "httpsServer": {"configured": True, "running": True, "port": 443},
+ "unixSocketServer": {"configured": False, "running": False},
+ "tlsProtocol": ["1.2"],
+ }
+ ],
+ "inputs": {"profile": "API_SSL_Profile"},
+ "expected": {"result": "failure", "messages": ["eAPI HTTPS server SSL profile (API_SSL_Profile) is not configured"]},
+ },
+ {
+ "name": "failure-misconfigured-invalid",
+ "test": VerifyAPIHttpsSSL,
+ "eos_data": [
+ {
+ "enabled": True,
+ "httpServer": {"configured": True, "running": True, "port": 80},
+ "localHttpServer": {"configured": False, "running": False, "port": 8080},
+ "httpsServer": {"configured": True, "running": True, "port": 443},
+ "unixSocketServer": {"configured": False, "running": False},
+ "sslProfile": {"name": "Wrong_SSL_Profile", "configured": True, "state": "valid"},
+ "tlsProtocol": ["1.2"],
+ }
+ ],
+ "inputs": {"profile": "API_SSL_Profile"},
+ "expected": {"result": "failure", "messages": ["eAPI HTTPS server SSL profile (API_SSL_Profile) is misconfigured or invalid"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAPIIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_API", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifyAPIIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 eAPI IPv4 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifyAPIIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_API", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["eAPI IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_API']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAPIIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_API", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifyAPIIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 eAPI IPv6 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifyAPIIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_API", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["eAPI IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_API']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "RSA",
+ "size": 4096,
+ },
+ },
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "ECDSA",
+ "size": 256,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702288467.6736515,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-certificate-not-configured",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "ECDSA",
+ "size": 256,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702288467.6736515,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["SSL certificate 'ARISTA_ROOT_CA.crt', is not configured.\n"],
+ },
+ },
+ {
+ "name": "failure-certificate-expired",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"},
+ "notAfter": 1702533518,
+ "publicKey": {
+ "encryptionAlgorithm": "RSA",
+ "size": 4096,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702622372.2240553,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["SSL certificate 'ARISTA_SIGNING_CA.crt', is not configured.\n", "SSL certificate `ARISTA_ROOT_CA.crt` is expired.\n"],
+ },
+ },
+ {
+ "name": "failure-certificate-about-to-expire",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"},
+ "notAfter": 1704782709,
+ "publicKey": {
+ "encryptionAlgorithm": "RSA",
+ "size": 4096,
+ },
+ },
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"},
+ "notAfter": 1702533518,
+ "publicKey": {
+ "encryptionAlgorithm": "ECDSA",
+ "size": 256,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702622372.2240553,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["SSL certificate `ARISTA_SIGNING_CA.crt` is expired.\n", "SSL certificate `ARISTA_ROOT_CA.crt` is about to expire in 25 days."],
+ },
+ },
+ {
+ "name": "failure-wrong-subject-name",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA Networks Internal IT Root Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "RSA",
+ "size": 4096,
+ },
+ },
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "Arista ECDSA Issuing Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "ECDSA",
+ "size": 256,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702288467.6736515,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n"
+ "Expected `AristaIT-ICA ECDSA Issuing Cert Authority` as the subject.commonName, but found "
+ "`Arista ECDSA Issuing Cert Authority` instead.\n",
+ "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n"
+ "Expected `Arista Networks Internal IT Root Cert Authority` as the subject.commonName, "
+ "but found `AristaIT-ICA Networks Internal IT Root Cert Authority` instead.\n",
+ ],
+ },
+ },
+ {
+ "name": "failure-wrong-encryption-type-and-size",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "ECDSA",
+ "size": 256,
+ },
+ },
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"},
+ "notAfter": 2127420899,
+ "publicKey": {
+ "encryptionAlgorithm": "RSA",
+ "size": 4096,
+ },
+ },
+ }
+ },
+ {
+ "utcTime": 1702288467.6736515,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n"
+ "Expected `ECDSA` as the publicKey.encryptionAlgorithm, but found `RSA` instead.\n"
+ "Expected `256` as the publicKey.size, but found `4096` instead.\n",
+ "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n"
+ "Expected `RSA` as the publicKey.encryptionAlgorithm, but found `ECDSA` instead.\n"
+ "Expected `4096` as the publicKey.size, but found `256` instead.\n",
+ ],
+ },
+ },
+ {
+ "name": "failure-missing-actual-output",
+ "test": VerifyAPISSLCertificate,
+ "eos_data": [
+ {
+ "certificates": {
+ "ARISTA_ROOT_CA.crt": {
+ "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"},
+ "notAfter": 2127420899,
+ },
+ "ARISTA_SIGNING_CA.crt": {
+ "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"},
+ "notAfter": 2127420899,
+ },
+ }
+ },
+ {
+ "utcTime": 1702288467.6736515,
+ },
+ ],
+ "inputs": {
+ "certificates": [
+ {
+ "certificate_name": "ARISTA_SIGNING_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority",
+ "encryption_algorithm": "ECDSA",
+ "key_size": 256,
+ },
+ {
+ "certificate_name": "ARISTA_ROOT_CA.crt",
+ "expiry_threshold": 30,
+ "common_name": "Arista Networks Internal IT Root Cert Authority",
+ "encryption_algorithm": "RSA",
+ "key_size": 4096,
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n"
+ "Expected `ECDSA` as the publicKey.encryptionAlgorithm, but it was not found in the actual output.\n"
+ "Expected `256` as the publicKey.size, but it was not found in the actual output.\n",
+ "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n"
+ "Expected `RSA` as the publicKey.encryptionAlgorithm, but it was not found in the actual output.\n"
+ "Expected `4096` as the publicKey.size, but it was not found in the actual output.\n",
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBannerLogin,
+ "eos_data": [
+ {
+ "loginBanner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "login_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiline",
+ "test": VerifyBannerLogin,
+ "eos_data": [
+ {
+ "loginBanner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "login_banner": """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."""
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-login-banner",
+ "test": VerifyBannerLogin,
+ "eos_data": [
+ {
+ "loginBanner": "Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "login_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Expected `Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file.` as the login banner, but found `Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is "
+ "governed by the Apache License 2.0\nthat can be found in the LICENSE file.` instead."
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyBannerMotd,
+ "eos_data": [
+ {
+ "motd": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "motd_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-multiline",
+ "test": VerifyBannerMotd,
+ "eos_data": [
+ {
+ "motd": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "motd_banner": """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."""
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-motd-banner",
+ "test": VerifyBannerMotd,
+ "eos_data": [
+ {
+ "motd": "Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ }
+ ],
+ "inputs": {
+ "motd_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file."
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Expected `Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n"
+ "that can be found in the LICENSE file.` as the motd banner, but found `Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is "
+ "governed by the Apache License 2.0\nthat can be found in the LICENSE file.` instead."
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyIPv4ACL,
+ "eos_data": [
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit ip any any tracked", "sequenceNumber": 20},
+ {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30},
+ ],
+ }
+ ]
+ },
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 20},
+ ],
+ }
+ ]
+ },
+ ],
+ "inputs": {
+ "ipv4_access_lists": [
+ {
+ "name": "default-control-plane-acl",
+ "entries": [
+ {"sequence": 10, "action": "permit icmp any any"},
+ {"sequence": 20, "action": "permit ip any any tracked"},
+ {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
+ ],
+ },
+ {
+ "name": "LabTest",
+ "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
+ },
+ ]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-acl-not-found",
+ "test": VerifyIPv4ACL,
+ "eos_data": [
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit ip any any tracked", "sequenceNumber": 20},
+ {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30},
+ ],
+ }
+ ]
+ },
+ {"aclList": []},
+ ],
+ "inputs": {
+ "ipv4_access_lists": [
+ {
+ "name": "default-control-plane-acl",
+ "entries": [
+ {"sequence": 10, "action": "permit icmp any any"},
+ {"sequence": 20, "action": "permit ip any any tracked"},
+ {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
+ ],
+ },
+ {
+ "name": "LabTest",
+ "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
+ },
+ ]
+ },
+ "expected": {"result": "failure", "messages": ["LabTest: Not found"]},
+ },
+ {
+ "name": "failure-sequence-not-found",
+ "test": VerifyIPv4ACL,
+ "eos_data": [
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit ip any any tracked", "sequenceNumber": 20},
+ {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 40},
+ ],
+ }
+ ]
+ },
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
+ ],
+ }
+ ]
+ },
+ ],
+ "inputs": {
+ "ipv4_access_lists": [
+ {
+ "name": "default-control-plane-acl",
+ "entries": [
+ {"sequence": 10, "action": "permit icmp any any"},
+ {"sequence": 20, "action": "permit ip any any tracked"},
+ {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
+ ],
+ },
+ {
+ "name": "LabTest",
+ "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["default-control-plane-acl:\nSequence number `30` is not found.\n", "LabTest:\nSequence number `20` is not found.\n"],
+ },
+ },
+ {
+ "name": "failure-action-not-match",
+ "test": VerifyIPv4ACL,
+ "eos_data": [
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit ip any any tracked", "sequenceNumber": 20},
+ {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
+ ],
+ }
+ ]
+ },
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 20},
+ ],
+ }
+ ]
+ },
+ ],
+ "inputs": {
+ "ipv4_access_lists": [
+ {
+ "name": "default-control-plane-acl",
+ "entries": [
+ {"sequence": 10, "action": "permit icmp any any"},
+ {"sequence": 20, "action": "permit ip any any tracked"},
+ {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
+ ],
+ },
+ {
+ "name": "LabTest",
+ "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "default-control-plane-acl:\n"
+ "Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n",
+ "LabTest:\nExpected `permit tcp any any range 5900 5910` as sequence number 20 action but found `permit udp any any eq bfd ttl eq 255` instead.\n",
+ ],
+ },
+ },
+ {
+ "name": "failure-all-type",
+ "test": VerifyIPv4ACL,
+ "eos_data": [
+ {
+ "aclList": [
+ {
+ "sequence": [
+ {"text": "permit icmp any any", "sequenceNumber": 10},
+ {"text": "permit ip any any tracked", "sequenceNumber": 40},
+ {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
+ ],
+ }
+ ]
+ },
+ {"aclList": []},
+ ],
+ "inputs": {
+ "ipv4_access_lists": [
+ {
+ "name": "default-control-plane-acl",
+ "entries": [
+ {"sequence": 10, "action": "permit icmp any any"},
+ {"sequence": 20, "action": "permit ip any any tracked"},
+ {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
+ ],
+ },
+ {
+ "name": "LabTest",
+ "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
+ },
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "default-control-plane-acl:\nSequence number `20` is not found.\n"
+ "Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n",
+ "LabTest: Not found",
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_services.py b/tests/units/anta_tests/test_services.py
new file mode 100644
index 0000000..dcd1ee2
--- /dev/null
+++ b/tests/units/anta_tests/test_services.py
@@ -0,0 +1,218 @@
+# 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.tests.services.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyHostname,
+ "eos_data": [{"hostname": "s1-spine1", "fqdn": "s1-spine1.fun.aristanetworks.com"}],
+ "inputs": {"hostname": "s1-spine1"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-hostname",
+ "test": VerifyHostname,
+ "eos_data": [{"hostname": "s1-spine2", "fqdn": "s1-spine1.fun.aristanetworks.com"}],
+ "inputs": {"hostname": "s1-spine1"},
+ "expected": {
+ "result": "failure",
+ "messages": ["Expected `s1-spine1` as the hostname, but found `s1-spine2` instead."],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyDNSLookup,
+ "eos_data": [
+ {
+ "messages": [
+ "Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\tarista.com\nAddress: 151.101.130.132\nName:\tarista.com\n"
+ "Address: 151.101.2.132\nName:\tarista.com\nAddress: 151.101.194.132\nName:\tarista.com\nAddress: 151.101.66.132\n\n"
+ ]
+ },
+ {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\twww.google.com\nAddress: 172.217.12.100\n\n"]},
+ ],
+ "inputs": {"domain_names": ["arista.com", "www.google.com"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyDNSLookup,
+ "eos_data": [
+ {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\n*** Can't find arista.ca: No answer\n\n"]},
+ {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\twww.google.com\nAddress: 172.217.12.100\n\n"]},
+ {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\n*** Can't find google.ca: No answer\n\n"]},
+ ],
+ "inputs": {"domain_names": ["arista.ca", "www.google.com", "google.ca"]},
+ "expected": {"result": "failure", "messages": ["The following domain(s) are not resolved to an IP address: arista.ca, google.ca"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyDNSServers,
+ "eos_data": [
+ {
+ "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "default", "priority": 0}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}],
+ }
+ ],
+ "inputs": {
+ "dns_servers": [{"server_address": "10.14.0.1", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.11", "vrf": "MGMT", "priority": 1}]
+ },
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-dns-missing",
+ "test": VerifyDNSServers,
+ "eos_data": [
+ {
+ "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "default", "priority": 0}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}],
+ }
+ ],
+ "inputs": {
+ "dns_servers": [{"server_address": "10.14.0.10", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.21", "vrf": "MGMT", "priority": 1}]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["DNS server `10.14.0.10` is not configured with any VRF.", "DNS server `10.14.0.21` is not configured with any VRF."],
+ },
+ },
+ {
+ "name": "failure-no-dns-found",
+ "test": VerifyDNSServers,
+ "eos_data": [
+ {
+ "nameServerConfigs": [],
+ }
+ ],
+ "inputs": {
+ "dns_servers": [{"server_address": "10.14.0.10", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.21", "vrf": "MGMT", "priority": 1}]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": ["DNS server `10.14.0.10` is not configured with any VRF.", "DNS server `10.14.0.21` is not configured with any VRF."],
+ },
+ },
+ {
+ "name": "failure-incorrect-dns-details",
+ "test": VerifyDNSServers,
+ "eos_data": [
+ {
+ "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "CS", "priority": 1}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}],
+ }
+ ],
+ "inputs": {
+ "dns_servers": [
+ {"server_address": "10.14.0.1", "vrf": "CS", "priority": 0},
+ {"server_address": "10.14.0.11", "vrf": "default", "priority": 0},
+ {"server_address": "10.14.0.110", "vrf": "MGMT", "priority": 0},
+ ]
+ },
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "For DNS server `10.14.0.1`, the expected priority is `0`, but `1` was found instead.",
+ "DNS server `10.14.0.11` is not configured with VRF `default`.",
+ "DNS server `10.14.0.110` is not configured with any VRF.",
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyErrdisableRecovery,
+ "eos_data": [
+ """
+ Errdisable Reason Timer Status Timer Interval
+ ------------------------------ ----------------- --------------
+ acl Enabled 300
+ bpduguard Enabled 300
+ arp-inspection Enabled 30
+ """
+ ],
+ "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "bpduguard", "interval": 300}]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-reason-missing",
+ "test": VerifyErrdisableRecovery,
+ "eos_data": [
+ """
+ Errdisable Reason Timer Status Timer Interval
+ ------------------------------ ----------------- --------------
+ acl Enabled 300
+ bpduguard Enabled 300
+ arp-inspection Enabled 30
+ """
+ ],
+ "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "arp-inspection", "interval": 30}, {"reason": "tapagg", "interval": 30}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["`tapagg`: Not found."],
+ },
+ },
+ {
+ "name": "failure-reason-disabled",
+ "test": VerifyErrdisableRecovery,
+ "eos_data": [
+ """
+ Errdisable Reason Timer Status Timer Interval
+ ------------------------------ ----------------- --------------
+ acl Disabled 300
+ bpduguard Enabled 300
+ arp-inspection Enabled 30
+ """
+ ],
+ "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "arp-inspection", "interval": 30}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["`acl`:\nExpected `Enabled` as the status, but found `Disabled` instead."],
+ },
+ },
+ {
+ "name": "failure-interval-not-ok",
+ "test": VerifyErrdisableRecovery,
+ "eos_data": [
+ """
+ Errdisable Reason Timer Status Timer Interval
+ ------------------------------ ----------------- --------------
+ acl Enabled 300
+ bpduguard Enabled 300
+ arp-inspection Enabled 30
+ """
+ ],
+ "inputs": {"reasons": [{"reason": "acl", "interval": 30}, {"reason": "arp-inspection", "interval": 30}]},
+ "expected": {
+ "result": "failure",
+ "messages": ["`acl`:\nExpected `30` as the interval, but found `300` instead."],
+ },
+ },
+ {
+ "name": "failure-all-type",
+ "test": VerifyErrdisableRecovery,
+ "eos_data": [
+ """
+ Errdisable Reason Timer Status Timer Interval
+ ------------------------------ ----------------- --------------
+ acl Disabled 300
+ bpduguard Enabled 300
+ arp-inspection Enabled 30
+ """
+ ],
+ "inputs": {"reasons": [{"reason": "acl", "interval": 30}, {"reason": "arp-inspection", "interval": 300}, {"reason": "tapagg", "interval": 30}]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "`acl`:\nExpected `30` as the interval, but found `300` instead.\nExpected `Enabled` as the status, but found `Disabled` instead.",
+ "`arp-inspection`:\nExpected `300` as the interval, but found `30` instead.",
+ "`tapagg`: Not found.",
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_snmp.py b/tests/units/anta_tests/test_snmp.py
new file mode 100644
index 0000000..7009689
--- /dev/null
+++ b/tests/units/anta_tests/test_snmp.py
@@ -0,0 +1,128 @@
+# 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.tests.snmp.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifySnmpStatus,
+ "eos_data": [{"vrfs": {"snmpVrfs": ["MGMT", "default"]}, "enabled": True}],
+ "inputs": {"vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifySnmpStatus,
+ "eos_data": [{"vrfs": {"snmpVrfs": ["default"]}, "enabled": True}],
+ "inputs": {"vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["SNMP agent disabled in vrf MGMT"]},
+ },
+ {
+ "name": "failure-disabled",
+ "test": VerifySnmpStatus,
+ "eos_data": [{"vrfs": {"snmpVrfs": ["default"]}, "enabled": False}],
+ "inputs": {"vrf": "default"},
+ "expected": {"result": "failure", "messages": ["SNMP agent disabled in vrf default"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySnmpIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SNMP", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifySnmpIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 SNMP IPv4 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifySnmpIPv4Acl,
+ "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SNMP", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["SNMP IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_SNMP']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySnmpIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SNMP", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-wrong-number",
+ "test": VerifySnmpIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": []}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["Expected 1 SNMP IPv6 ACL(s) in vrf MGMT but got 0"]},
+ },
+ {
+ "name": "failure-wrong-vrf",
+ "test": VerifySnmpIPv6Acl,
+ "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SNMP", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}],
+ "inputs": {"number": 1, "vrf": "MGMT"},
+ "expected": {"result": "failure", "messages": ["SNMP IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_SNMP']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySnmpLocation,
+ "eos_data": [
+ {
+ "location": {"location": "New York"},
+ }
+ ],
+ "inputs": {"location": "New York"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-location",
+ "test": VerifySnmpLocation,
+ "eos_data": [
+ {
+ "location": {"location": "Europe"},
+ }
+ ],
+ "inputs": {"location": "New York"},
+ "expected": {
+ "result": "failure",
+ "messages": ["Expected `New York` as the location, but found `Europe` instead."],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifySnmpContact,
+ "eos_data": [
+ {
+ "contact": {"contact": "Jon@example.com"},
+ }
+ ],
+ "inputs": {"contact": "Jon@example.com"},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-contact",
+ "test": VerifySnmpContact,
+ "eos_data": [
+ {
+ "contact": {"contact": "Jon@example.com"},
+ }
+ ],
+ "inputs": {"contact": "Bob@example.com"},
+ "expected": {
+ "result": "failure",
+ "messages": ["Expected `Bob@example.com` as the contact, but found `Jon@example.com` instead."],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_software.py b/tests/units/anta_tests/test_software.py
new file mode 100644
index 0000000..6d39c04
--- /dev/null
+++ b/tests/units/anta_tests/test_software.py
@@ -0,0 +1,101 @@
+# 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.hardware"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyEOSVersion,
+ "eos_data": [
+ {
+ "modelName": "vEOS-lab",
+ "internalVersion": "4.27.0F-24305004.4270F",
+ "version": "4.27.0F",
+ }
+ ],
+ "inputs": {"versions": ["4.27.0F", "4.28.0F"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyEOSVersion,
+ "eos_data": [
+ {
+ "modelName": "vEOS-lab",
+ "internalVersion": "4.27.0F-24305004.4270F",
+ "version": "4.27.0F",
+ }
+ ],
+ "inputs": {"versions": ["4.27.1F"]},
+ "expected": {"result": "failure", "messages": ["device is running version \"4.27.0F\" not in expected versions: ['4.27.1F']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyTerminAttrVersion,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1107543.52,
+ "modelName": "vEOS-lab",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}],
+ "switchType": "fixedSystem",
+ "packages": {
+ "TerminAttr-core": {"release": "1", "version": "v1.17.0"},
+ },
+ },
+ }
+ ],
+ "inputs": {"versions": ["v1.17.0", "v1.18.1"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyTerminAttrVersion,
+ "eos_data": [
+ {
+ "imageFormatVersion": "1.0",
+ "uptime": 1107543.52,
+ "modelName": "vEOS-lab",
+ "details": {
+ "deviations": [],
+ "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}],
+ "switchType": "fixedSystem",
+ "packages": {
+ "TerminAttr-core": {"release": "1", "version": "v1.17.0"},
+ },
+ },
+ }
+ ],
+ "inputs": {"versions": ["v1.17.1", "v1.18.1"]},
+ "expected": {"result": "failure", "messages": ["device is running TerminAttr version v1.17.0 and is not in the allowed list: ['v1.17.1', 'v1.18.1']"]},
+ },
+ {
+ "name": "success-no-extensions",
+ "test": VerifyEOSExtensions,
+ "eos_data": [
+ {"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]},
+ {"extensions": []},
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyEOSExtensions,
+ "eos_data": [
+ {"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]},
+ {"extensions": ["dummy"]},
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Missing EOS extensions: installed [] / configured: ['dummy']"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_stp.py b/tests/units/anta_tests/test_stp.py
new file mode 100644
index 0000000..26f0b90
--- /dev/null
+++ b/tests/units/anta_tests/test_stp.py
@@ -0,0 +1,328 @@
+# 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.tests.stp.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifySTPMode,
+ "eos_data": [
+ {"spanningTreeVlanInstances": {"10": {"spanningTreeVlanInstance": {"protocol": "rstp"}}}},
+ {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "rstp"}}}},
+ ],
+ "inputs": {"mode": "rstp", "vlans": [10, 20]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-instances",
+ "test": VerifySTPMode,
+ "eos_data": [
+ {"spanningTreeVlanInstances": {}},
+ {"spanningTreeVlanInstances": {}},
+ ],
+ "inputs": {"mode": "rstp", "vlans": [10, 20]},
+ "expected": {"result": "failure", "messages": ["STP mode 'rstp' not configured for the following VLAN(s): [10, 20]"]},
+ },
+ {
+ "name": "failure-wrong-mode",
+ "test": VerifySTPMode,
+ "eos_data": [
+ {"spanningTreeVlanInstances": {"10": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}},
+ {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}},
+ ],
+ "inputs": {"mode": "rstp", "vlans": [10, 20]},
+ "expected": {"result": "failure", "messages": ["Wrong STP mode configured for the following VLAN(s): [10, 20]"]},
+ },
+ {
+ "name": "failure-both",
+ "test": VerifySTPMode,
+ "eos_data": [
+ {"spanningTreeVlanInstances": {}},
+ {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}},
+ ],
+ "inputs": {"mode": "rstp", "vlans": [10, 20]},
+ "expected": {
+ "result": "failure",
+ "messages": ["STP mode 'rstp' not configured for the following VLAN(s): [10]", "Wrong STP mode configured for the following VLAN(s): [20]"],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifySTPBlockedPorts,
+ "eos_data": [{"spanningTreeInstances": {}}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifySTPBlockedPorts,
+ "eos_data": [{"spanningTreeInstances": {"MST0": {"spanningTreeBlockedPorts": ["Ethernet10"]}, "MST10": {"spanningTreeBlockedPorts": ["Ethernet10"]}}}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following ports are blocked by STP: {'MST0': ['Ethernet10'], 'MST10': ['Ethernet10']}"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySTPCounters,
+ "eos_data": [{"interfaces": {"Ethernet10": {"bpduSent": 99, "bpduReceived": 0, "bpduTaggedError": 0, "bpduOtherError": 0, "bpduRateLimitCount": 0}}}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifySTPCounters,
+ "eos_data": [
+ {
+ "interfaces": {
+ "Ethernet10": {"bpduSent": 201, "bpduReceived": 0, "bpduTaggedError": 3, "bpduOtherError": 0, "bpduRateLimitCount": 0},
+ "Ethernet11": {"bpduSent": 99, "bpduReceived": 0, "bpduTaggedError": 0, "bpduOtherError": 6, "bpduRateLimitCount": 0},
+ }
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The following interfaces have STP BPDU packet errors: ['Ethernet10', 'Ethernet11']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifySTPForwardingPorts,
+ "eos_data": [
+ {
+ "unmappedVlans": [],
+ "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ {
+ "unmappedVlans": [],
+ "topologies": {"Mst20": {"vlans": [20], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ ],
+ "inputs": {"vlans": [10, 20]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-vlan-not-in-topology", # Should it succeed really ? TODO - this output should be impossible
+ "test": VerifySTPForwardingPorts,
+ "eos_data": [
+ {
+ "unmappedVlans": [],
+ "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ {
+ "unmappedVlans": [],
+ "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ ],
+ "inputs": {"vlans": [10, 20]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-instances",
+ "test": VerifySTPForwardingPorts,
+ "eos_data": [{"unmappedVlans": [], "topologies": {}}, {"unmappedVlans": [], "topologies": {}}],
+ "inputs": {"vlans": [10, 20]},
+ "expected": {"result": "failure", "messages": ["STP instance is not configured for the following VLAN(s): [10, 20]"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifySTPForwardingPorts,
+ "eos_data": [
+ {
+ "unmappedVlans": [],
+ "topologies": {"Vl10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "discarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ {
+ "unmappedVlans": [],
+ "topologies": {"Vl20": {"vlans": [20], "interfaces": {"Ethernet10": {"state": "discarding"}, "MplsTrunk1": {"state": "forwarding"}}}},
+ },
+ ],
+ "inputs": {"vlans": [10, 20]},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following VLAN(s) have interface(s) that are not in a fowarding state: [{'VLAN 10': ['Ethernet10']}, {'VLAN 20': ['Ethernet10']}]"],
+ },
+ },
+ {
+ "name": "success-specific-instances",
+ "test": VerifySTPRootPriority,
+ "eos_data": [
+ {
+ "instances": {
+ "VL10": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 10,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL20": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 20,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL30": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 30,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"priority": 32768, "instances": [10, 20]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-all-instances",
+ "test": VerifySTPRootPriority,
+ "eos_data": [
+ {
+ "instances": {
+ "VL10": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 10,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL20": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 20,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL30": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 30,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"priority": 32768},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-MST",
+ "test": VerifySTPRootPriority,
+ "eos_data": [
+ {
+ "instances": {
+ "MST0": {
+ "rootBridge": {
+ "priority": 16384,
+ "systemIdExtension": 0,
+ "macAddress": "02:1c:73:8b:93:ac",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ }
+ }
+ }
+ ],
+ "inputs": {"priority": 16384, "instances": [0]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-instances",
+ "test": VerifySTPRootPriority,
+ "eos_data": [
+ {
+ "instances": {
+ "WRONG0": {
+ "rootBridge": {
+ "priority": 16384,
+ "systemIdExtension": 0,
+ "macAddress": "02:1c:73:8b:93:ac",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ }
+ }
+ }
+ ],
+ "inputs": {"priority": 32768, "instances": [0]},
+ "expected": {"result": "failure", "messages": ["Unsupported STP instance type: WRONG0"]},
+ },
+ {
+ "name": "failure-wrong-instance-type",
+ "test": VerifySTPRootPriority,
+ "eos_data": [{"instances": {}}],
+ "inputs": {"priority": 32768, "instances": [10, 20]},
+ "expected": {"result": "failure", "messages": ["No STP instances configured"]},
+ },
+ {
+ "name": "failure-wrong-priority",
+ "test": VerifySTPRootPriority,
+ "eos_data": [
+ {
+ "instances": {
+ "VL10": {
+ "rootBridge": {
+ "priority": 32768,
+ "systemIdExtension": 10,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL20": {
+ "rootBridge": {
+ "priority": 8196,
+ "systemIdExtension": 20,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ "VL30": {
+ "rootBridge": {
+ "priority": 8196,
+ "systemIdExtension": 30,
+ "macAddress": "00:1c:73:27:95:a2",
+ "helloTime": 2.0,
+ "maxAge": 20,
+ "forwardDelay": 15,
+ }
+ },
+ }
+ }
+ ],
+ "inputs": {"priority": 32768, "instances": [10, 20, 30]},
+ "expected": {"result": "failure", "messages": ["The following instance(s) have the wrong STP root priority configured: ['VL20', 'VL30']"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_system.py b/tests/units/anta_tests/test_system.py
new file mode 100644
index 0000000..62260fa
--- /dev/null
+++ b/tests/units/anta_tests/test_system.py
@@ -0,0 +1,283 @@
+# 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.system"""
+from __future__ import annotations
+
+from typing import Any
+
+from anta.tests.system import (
+ VerifyAgentLogs,
+ VerifyCoredump,
+ VerifyCPUUtilization,
+ VerifyFileSystemUtilization,
+ VerifyMemoryUtilization,
+ VerifyNTP,
+ VerifyReloadCause,
+ VerifyUptime,
+)
+from tests.lib.anta import test # noqa: F401; pylint: disable=W0611
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyUptime,
+ "eos_data": [{"upTime": 1186689.15, "loadAvg": [0.13, 0.12, 0.09], "users": 1, "currentTime": 1683186659.139859}],
+ "inputs": {"minimum": 666},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyUptime,
+ "eos_data": [{"upTime": 665.15, "loadAvg": [0.13, 0.12, 0.09], "users": 1, "currentTime": 1683186659.139859}],
+ "inputs": {"minimum": 666},
+ "expected": {"result": "failure", "messages": ["Device uptime is 665.15 seconds"]},
+ },
+ {
+ "name": "success-no-reload",
+ "test": VerifyReloadCause,
+ "eos_data": [{"kernelCrashData": [], "resetCauses": [], "full": False}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-valid-cause",
+ "test": VerifyReloadCause,
+ "eos_data": [
+ {
+ "resetCauses": [
+ {"recommendedAction": "No action necessary.", "description": "Reload requested by the user.", "timestamp": 1683186892.0, "debugInfoIsDir": False}
+ ],
+ "full": False,
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyReloadCause,
+ # The failure cause is made up
+ "eos_data": [
+ {
+ "resetCauses": [
+ {"recommendedAction": "No action necessary.", "description": "Reload after crash.", "timestamp": 1683186892.0, "debugInfoIsDir": False}
+ ],
+ "full": False,
+ }
+ ],
+ "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,
+ "eos_data": [{"mode": "compressedDeferred", "coreFiles": []}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "success-with-minidump",
+ "test": VerifyCoredump,
+ "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["minidump"]}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-without-minidump",
+ "test": VerifyCoredump,
+ "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["core.2344.1584483862.Mlag.gz", "core.23101.1584483867.Mlag.gz"]}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Core dump(s) have been found: ['core.2344.1584483862.Mlag.gz', 'core.23101.1584483867.Mlag.gz']"]},
+ },
+ {
+ "name": "failure-with-minidump",
+ "test": VerifyCoredump,
+ "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["minidump", "core.2344.1584483862.Mlag.gz", "core.23101.1584483867.Mlag.gz"]}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Core dump(s) have been found: ['core.2344.1584483862.Mlag.gz', 'core.23101.1584483867.Mlag.gz']"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyAgentLogs,
+ "eos_data": [""],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyAgentLogs,
+ "eos_data": [
+ """===> /var/log/agents/Test-666 Thu May 4 09:57:02 2023 <===
+CLI Exception: Exception
+CLI Exception: Backtrace
+===> /var/log/agents/Aaa-855 Fri Jul 7 15:07:00 2023 <===
+===== Output from /usr/bin/Aaa [] (PID=855) started Jul 7 15:06:11.606414 ===
+EntityManager::doBackoff waiting for remote sysdb version ....ok
+
+===> /var/log/agents/Acl-830 Fri Jul 7 15:07:00 2023 <===
+===== Output from /usr/bin/Acl [] (PID=830) started Jul 7 15:06:10.871700 ===
+EntityManager::doBackoff waiting for remote sysdb version ...................ok
+"""
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Device has reported agent crashes:\n"
+ " * /var/log/agents/Test-666 Thu May 4 09:57:02 2023\n"
+ " * /var/log/agents/Aaa-855 Fri Jul 7 15:07:00 2023\n"
+ " * /var/log/agents/Acl-830 Fri Jul 7 15:07:00 2023",
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyCPUUtilization,
+ "eos_data": [
+ {
+ "cpuInfo": {"%Cpu(s)": {"idle": 88.2, "stolen": 0.0, "user": 5.9, "swIrq": 0.0, "ioWait": 0.0, "system": 0.0, "hwIrq": 5.9, "nice": 0.0}},
+ "processes": {
+ "1": {
+ "userName": "root",
+ "status": "S",
+ "memPct": 0.3,
+ "niceValue": 0,
+ "cpuPct": 0.0,
+ "cpuPctType": "{:.1f}",
+ "cmd": "systemd",
+ "residentMem": "5096",
+ "priority": "20",
+ "activeTime": 360,
+ "virtMem": "6644",
+ "sharedMem": "3996",
+ }
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyCPUUtilization,
+ "eos_data": [
+ {
+ "cpuInfo": {"%Cpu(s)": {"idle": 24.8, "stolen": 0.0, "user": 5.9, "swIrq": 0.0, "ioWait": 0.0, "system": 0.0, "hwIrq": 5.9, "nice": 0.0}},
+ "processes": {
+ "1": {
+ "userName": "root",
+ "status": "S",
+ "memPct": 0.3,
+ "niceValue": 0,
+ "cpuPct": 0.0,
+ "cpuPctType": "{:.1f}",
+ "cmd": "systemd",
+ "residentMem": "5096",
+ "priority": "20",
+ "activeTime": 360,
+ "virtMem": "6644",
+ "sharedMem": "3996",
+ }
+ },
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device has reported a high CPU utilization: 75.2%"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyMemoryUtilization,
+ "eos_data": [
+ {
+ "uptime": 1994.67,
+ "modelName": "vEOS-lab",
+ "internalVersion": "4.27.3F-26379303.4273F",
+ "memTotal": 2004568,
+ "memFree": 879004,
+ "version": "4.27.3F",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyMemoryUtilization,
+ "eos_data": [
+ {
+ "uptime": 1994.67,
+ "modelName": "vEOS-lab",
+ "internalVersion": "4.27.3F-26379303.4273F",
+ "memTotal": 2004568,
+ "memFree": 89004,
+ "version": "4.27.3F",
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Device has reported a high memory usage: 95.56%"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyFileSystemUtilization,
+ "eos_data": [
+ """Filesystem Size Used Avail Use% Mounted on
+/dev/sda2 3.9G 988M 2.9G 26% /mnt/flash
+none 294M 78M 217M 27% /
+none 294M 78M 217M 27% /.overlay
+/dev/loop0 461M 461M 0 100% /rootfs-i386
+"""
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyFileSystemUtilization,
+ "eos_data": [
+ """Filesystem Size Used Avail Use% Mounted on
+/dev/sda2 3.9G 988M 2.9G 84% /mnt/flash
+none 294M 78M 217M 27% /
+none 294M 78M 217M 84% /.overlay
+/dev/loop0 461M 461M 0 100% /rootfs-i386
+"""
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Mount point /dev/sda2 3.9G 988M 2.9G 84% /mnt/flash is higher than 75%: reported 84%",
+ "Mount point none 294M 78M 217M 84% /.overlay is higher than 75%: reported 84%",
+ ],
+ },
+ },
+ {
+ "name": "success",
+ "test": VerifyNTP,
+ "eos_data": [
+ """synchronised
+poll interval unknown
+"""
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyNTP,
+ "eos_data": [
+ """unsynchronised
+poll interval unknown
+"""
+ ],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["The device is not synchronized with the configured NTP server(s): 'unsynchronised'"]},
+ },
+]
diff --git a/tests/units/anta_tests/test_vlan.py b/tests/units/anta_tests/test_vlan.py
new file mode 100644
index 0000000..93398f6
--- /dev/null
+++ b/tests/units/anta_tests/test_vlan.py
@@ -0,0 +1,37 @@
+# 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.tests.vlan.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyVlanInternalPolicy,
+ "eos_data": [{"policy": "ascending", "startVlanId": 1006, "endVlanId": 4094}],
+ "inputs": {"policy": "ascending", "start_vlan_id": 1006, "end_vlan_id": 4094},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-incorrect-policy",
+ "test": VerifyVlanInternalPolicy,
+ "eos_data": [{"policy": "descending", "startVlanId": 4094, "endVlanId": 1006}],
+ "inputs": {"policy": "ascending", "start_vlan_id": 1006, "end_vlan_id": 4094},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The VLAN internal allocation policy is not configured properly:\n"
+ "Expected `ascending` as the policy, but found `descending` instead.\n"
+ "Expected `1006` as the startVlanId, but found `4094` instead.\n"
+ "Expected `4094` as the endVlanId, but found `1006` instead."
+ ],
+ },
+ },
+]
diff --git a/tests/units/anta_tests/test_vxlan.py b/tests/units/anta_tests/test_vxlan.py
new file mode 100644
index 0000000..2a9a875
--- /dev/null
+++ b/tests/units/anta_tests/test_vxlan.py
@@ -0,0 +1,365 @@
+# 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.tests.vxlan.py
+"""
+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
+
+DATA: list[dict[str, Any]] = [
+ {
+ "name": "success",
+ "test": VerifyVxlan1Interface,
+ "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "up", "interfaceStatus": "up"}}}],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped",
+ "test": VerifyVxlan1Interface,
+ "eos_data": [{"interfaceDescriptions": {"Loopback0": {"lineProtocolStatus": "up", "interfaceStatus": "up"}}}],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyVxlan1Interface,
+ "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "up"}}}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Vxlan1 interface is down/up"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyVxlan1Interface,
+ "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "up", "interfaceStatus": "down"}}}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Vxlan1 interface is up/down"]},
+ },
+ {
+ "name": "failure",
+ "test": VerifyVxlan1Interface,
+ "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "down"}}}],
+ "inputs": None,
+ "expected": {"result": "failure", "messages": ["Vxlan1 interface is down/down"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyVxlanConfigSanity,
+ "eos_data": [
+ {
+ "categories": {
+ "localVtep": {
+ "description": "Local VTEP Configuration Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [
+ {"name": "Loopback IP Address", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VLAN-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Flood List", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Routing", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VNI VRF ACL", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VRF-VNI Dynamic VLAN", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Decap VRF-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""},
+ ],
+ },
+ "remoteVtep": {
+ "description": "Remote VTEP Configuration Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [{"name": "Remote VTEP", "checkPass": True, "hasWarning": False, "detail": ""}],
+ },
+ "pd": {
+ "description": "Platform Dependent Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [
+ {"name": "VXLAN Bridging", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VXLAN Routing", "checkPass": True, "hasWarning": False, "detail": "VXLAN Routing not enabled"},
+ ],
+ },
+ "cvx": {
+ "description": "CVX Configuration Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [{"name": "CVX Server", "checkPass": True, "hasWarning": False, "detail": "Not in controller client mode"}],
+ },
+ "mlag": {
+ "description": "MLAG Configuration Check",
+ "allCheckPass": True,
+ "detail": "Run 'show mlag config-sanity' to verify MLAG config",
+ "hasWarning": False,
+ "items": [
+ {"name": "Peer VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "MLAG VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Virtual VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Peer VLAN-VNI", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "MLAG Inactive State", "checkPass": True, "hasWarning": False, "detail": ""},
+ ],
+ },
+ },
+ "warnings": [],
+ }
+ ],
+ "inputs": None,
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure",
+ "test": VerifyVxlanConfigSanity,
+ "eos_data": [
+ {
+ "categories": {
+ "localVtep": {
+ "description": "Local VTEP Configuration Check",
+ "allCheckPass": False,
+ "detail": "",
+ "hasWarning": True,
+ "items": [
+ {"name": "Loopback IP Address", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VLAN-VNI Map", "checkPass": False, "hasWarning": False, "detail": "No VLAN-VNI mapping in Vxlan1"},
+ {"name": "Flood List", "checkPass": False, "hasWarning": True, "detail": "No VXLAN VLANs in Vxlan1"},
+ {"name": "Routing", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VNI VRF ACL", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VRF-VNI Dynamic VLAN", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Decap VRF-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""},
+ ],
+ },
+ "remoteVtep": {
+ "description": "Remote VTEP Configuration Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [{"name": "Remote VTEP", "checkPass": True, "hasWarning": False, "detail": ""}],
+ },
+ "pd": {
+ "description": "Platform Dependent Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [
+ {"name": "VXLAN Bridging", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "VXLAN Routing", "checkPass": True, "hasWarning": False, "detail": "VXLAN Routing not enabled"},
+ ],
+ },
+ "cvx": {
+ "description": "CVX Configuration Check",
+ "allCheckPass": True,
+ "detail": "",
+ "hasWarning": False,
+ "items": [{"name": "CVX Server", "checkPass": True, "hasWarning": False, "detail": "Not in controller client mode"}],
+ },
+ "mlag": {
+ "description": "MLAG Configuration Check",
+ "allCheckPass": True,
+ "detail": "Run 'show mlag config-sanity' to verify MLAG config",
+ "hasWarning": False,
+ "items": [
+ {"name": "Peer VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "MLAG VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Virtual VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "Peer VLAN-VNI", "checkPass": True, "hasWarning": False, "detail": ""},
+ {"name": "MLAG Inactive State", "checkPass": True, "hasWarning": False, "detail": ""},
+ ],
+ },
+ },
+ "warnings": ["Your configuration contains warnings. This does not mean misconfigurations. But you may wish to re-check your configurations."],
+ }
+ ],
+ "inputs": None,
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "VXLAN config sanity check is not passing: {'localVtep': {'description': 'Local VTEP Configuration Check', "
+ "'allCheckPass': False, 'detail': '', 'hasWarning': True, 'items': [{'name': 'Loopback IP Address', 'checkPass': True, "
+ "'hasWarning': False, 'detail': ''}, {'name': 'VLAN-VNI Map', 'checkPass': False, 'hasWarning': False, 'detail': "
+ "'No VLAN-VNI mapping in Vxlan1'}, {'name': 'Flood List', 'checkPass': False, 'hasWarning': True, 'detail': "
+ "'No VXLAN VLANs in Vxlan1'}, {'name': 'Routing', 'checkPass': True, 'hasWarning': False, 'detail': ''}, {'name': "
+ "'VNI VRF ACL', 'checkPass': True, 'hasWarning': False, 'detail': ''}, {'name': 'VRF-VNI Dynamic VLAN', 'checkPass': True, "
+ "'hasWarning': False, 'detail': ''}, {'name': 'Decap VRF-VNI Map', 'checkPass': True, 'hasWarning': False, 'detail': ''}]}}"
+ ],
+ },
+ },
+ {
+ "name": "skipped",
+ "test": VerifyVxlanConfigSanity,
+ "eos_data": [{"categories": {}}],
+ "inputs": None,
+ "expected": {"result": "skipped", "messages": ["VXLAN is not configured"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyVxlanVniBinding,
+ "eos_data": [
+ {
+ "vxlanIntfs": {
+ "Vxlan1": {
+ "vniBindings": {
+ "10020": {"vlan": 20, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}}
+ },
+ "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}},
+ }
+ }
+ }
+ ],
+ "inputs": {"bindings": {10020: 20, 500: 1199}},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-no-binding",
+ "test": VerifyVxlanVniBinding,
+ "eos_data": [
+ {
+ "vxlanIntfs": {
+ "Vxlan1": {
+ "vniBindings": {
+ "10020": {"vlan": 20, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}}
+ },
+ "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}},
+ }
+ }
+ }
+ ],
+ "inputs": {"bindings": {10010: 10, 10020: 20, 500: 1199}},
+ "expected": {"result": "failure", "messages": ["The following VNI(s) have no binding: ['10010']"]},
+ },
+ {
+ "name": "failure-wrong-binding",
+ "test": VerifyVxlanVniBinding,
+ "eos_data": [
+ {
+ "vxlanIntfs": {
+ "Vxlan1": {
+ "vniBindings": {
+ "10020": {"vlan": 30, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}}
+ },
+ "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}},
+ }
+ }
+ }
+ ],
+ "inputs": {"bindings": {10020: 20, 500: 1199}},
+ "expected": {"result": "failure", "messages": ["The following VNI(s) have the wrong VLAN binding: [{'10020': 30}]"]},
+ },
+ {
+ "name": "failure-no-and-wrong-binding",
+ "test": VerifyVxlanVniBinding,
+ "eos_data": [
+ {
+ "vxlanIntfs": {
+ "Vxlan1": {
+ "vniBindings": {
+ "10020": {"vlan": 30, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}}
+ },
+ "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}},
+ }
+ }
+ }
+ ],
+ "inputs": {"bindings": {10010: 10, 10020: 20, 500: 1199}},
+ "expected": {
+ "result": "failure",
+ "messages": ["The following VNI(s) have no binding: ['10010']", "The following VNI(s) have the wrong VLAN binding: [{'10020': 30}]"],
+ },
+ },
+ {
+ "name": "skipped",
+ "test": VerifyVxlanVniBinding,
+ "eos_data": [{"vxlanIntfs": {}}],
+ "inputs": {"bindings": {10020: 20, 500: 1199}},
+ "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5", "10.1.1.6"]}}}],
+ "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "failure-missing-vtep",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5", "10.1.1.6"]}}}],
+ "inputs": {"vteps": ["10.1.1.5", "10.1.1.6", "10.1.1.7"]},
+ "expected": {"result": "failure", "messages": ["The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.7']"]},
+ },
+ {
+ "name": "failure-no-vtep",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": []}}}],
+ "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]},
+ "expected": {"result": "failure", "messages": ["The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.5', '10.1.1.6']"]},
+ },
+ {
+ "name": "failure-no-input-vtep",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5"]}}}],
+ "inputs": {"vteps": []},
+ "expected": {"result": "failure", "messages": ["Unexpected VTEP peer(s) on Vxlan1 interface: ['10.1.1.5']"]},
+ },
+ {
+ "name": "failure-missmatch",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.6", "10.1.1.7", "10.1.1.8"]}}}],
+ "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.5']",
+ "Unexpected VTEP peer(s) on Vxlan1 interface: ['10.1.1.7', '10.1.1.8']",
+ ],
+ },
+ },
+ {
+ "name": "skipped",
+ "test": VerifyVxlanVtep,
+ "eos_data": [{"vteps": {}, "interfaces": {}}],
+ "inputs": {"vteps": ["10.1.1.5", "10.1.1.6", "10.1.1.7"]},
+ "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]},
+ },
+ {
+ "name": "success",
+ "test": VerifyVxlan1ConnSettings,
+ "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback1", "udpPort": 4789}}}],
+ "inputs": {"source_interface": "Loopback1", "udp_port": 4789},
+ "expected": {"result": "success"},
+ },
+ {
+ "name": "skipped",
+ "test": VerifyVxlan1ConnSettings,
+ "eos_data": [{"interfaces": {}}],
+ "inputs": {"source_interface": "Loopback1", "udp_port": 4789},
+ "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured."]},
+ },
+ {
+ "name": "failure-wrong-interface",
+ "test": VerifyVxlan1ConnSettings,
+ "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback10", "udpPort": 4789}}}],
+ "inputs": {"source_interface": "lo1", "udp_port": 4789},
+ "expected": {
+ "result": "failure",
+ "messages": ["Source interface is not correct. Expected `Loopback1` as source interface but found `Loopback10` instead."],
+ },
+ },
+ {
+ "name": "failure-wrong-port",
+ "test": VerifyVxlan1ConnSettings,
+ "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback10", "udpPort": 4789}}}],
+ "inputs": {"source_interface": "Lo1", "udp_port": 4780},
+ "expected": {
+ "result": "failure",
+ "messages": [
+ "Source interface is not correct. Expected `Loopback1` as source interface but found `Loopback10` instead.",
+ "UDP port is not correct. Expected `4780` as UDP port but found `4789` instead.",
+ ],
+ },
+ },
+]