From 05f91b5d09e0d4d6661239ec04fd1d29fbae4965 Mon Sep 17 00:00:00 2001 From: vitthalmagadum Date: Wed, 8 Jan 2025 05:31:27 -0500 Subject: [PATCH 1/4] issue_997: BFD tests with proper validators --- anta/tests/bfd.py | 33 ++++++++++++- tests/units/input_models/test_bfd.py | 69 ++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/units/input_models/test_bfd.py diff --git a/anta/tests/bfd.py b/anta/tests/bfd.py index a27a786cf..3131f3789 100644 --- a/anta/tests/bfd.py +++ b/anta/tests/bfd.py @@ -8,9 +8,9 @@ from __future__ import annotations from datetime import datetime, timezone -from typing import TYPE_CHECKING, ClassVar +from typing import TYPE_CHECKING, ClassVar, TypeVar -from pydantic import Field +from pydantic import Field, field_validator from anta.input_models.bfd import BFDPeer from anta.models import AntaCommand, AntaTest @@ -19,6 +19,9 @@ if TYPE_CHECKING: from anta.models import AntaTemplate +# Using a TypeVar for the BFDPeer model since mypy thinks it's a ClassVar and not a valid type when used in field validators +T = TypeVar("T", bound=BFDPeer) + class VerifyBFDSpecificPeers(AntaTest): """Verifies the state of IPv4 BFD peer sessions. @@ -139,6 +142,22 @@ class Input(AntaTest.Input): BFDPeer: ClassVar[type[BFDPeer]] = BFDPeer """To maintain backward compatibility""" + @field_validator("bfd_peers") + @classmethod + def validate_snmp_user(cls, bfd_peers: list[T]) -> list[T]: + """Validate that 'tx_interval', 'rx_interval' or 'multiplier' field is provided in each BFD peer.""" + for peer in bfd_peers: + if peer.tx_interval is None: + msg = f"{peer}; 'tx_interval' field missing in the input" + raise ValueError(msg) + if peer.rx_interval is None: + msg = f"{peer}; 'rx_interval' field missing in the input" + raise ValueError(msg) + if peer.multiplier is None: + msg = f"{peer}; 'multiplier' field missing in the input" + raise ValueError(msg) + return bfd_peers + @AntaTest.anta_test def test(self) -> None: """Main test function for VerifyBFDPeersIntervals.""" @@ -299,6 +318,16 @@ class Input(AntaTest.Input): BFDPeer: ClassVar[type[BFDPeer]] = BFDPeer """To maintain backward compatibility""" + @field_validator("bfd_peers") + @classmethod + def validate_snmp_user(cls, bfd_peers: list[T]) -> list[T]: + """Validate that 'protocols' field is provided in each BFD peer.""" + for peer in bfd_peers: + if peer.protocols is None: + msg = f"{peer}; 'protocols' field missing in the input" + raise ValueError(msg) + return bfd_peers + @AntaTest.anta_test def test(self) -> None: """Main test function for VerifyBFDPeersRegProtocols.""" diff --git a/tests/units/input_models/test_bfd.py b/tests/units/input_models/test_bfd.py new file mode 100644 index 000000000..d341bb8b5 --- /dev/null +++ b/tests/units/input_models/test_bfd.py @@ -0,0 +1,69 @@ +# Copyright (c) 2023-2025 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.input_models.bfd.py.""" + +# pylint: disable=C0302 +from __future__ import annotations + +from typing import TYPE_CHECKING + +import pytest +from pydantic import ValidationError + +from anta.tests.bfd import VerifyBFDPeersIntervals, VerifyBFDPeersRegProtocols + +if TYPE_CHECKING: + from anta.input_models.bfd import BFDPeer + + +class TestVerifyBFDPeersIntervalsInput: + """Test anta.tests.bfd.VerifyBFDPeersIntervals.Input.""" + + @pytest.mark.parametrize( + ("bfd_peers"), + [ + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}], id="valid"), + ], + ) + def test_valid(self, bfd_peers: list[BFDPeer]) -> None: + """Test VerifyBFDPeersIntervals.Input valid inputs.""" + VerifyBFDPeersIntervals.Input(bfd_peers=bfd_peers) + + @pytest.mark.parametrize( + ("bfd_peers"), + [ + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "tx_interval": 1200}], id="invalid-tx-interval"), + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "rx_interval": 1200}], id="invalid-rx-interval"), + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "multiplier": 3}], id="invalid-multiplier"), + ], + ) + def test_invalid(self, bfd_peers: list[BFDPeer]) -> None: + """Test VerifyBFDPeersIntervals.Input invalid inputs.""" + with pytest.raises(ValidationError): + VerifyBFDPeersIntervals.Input(bfd_peers=bfd_peers) + + +class TestVerifyBFDPeersRegProtocolsInput: + """Test anta.tests.bfd.VerifyBFDPeersRegProtocols.Input.""" + + @pytest.mark.parametrize( + ("bfd_peers"), + [ + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "protocols": ["bgp"]}], id="valid"), + ], + ) + def test_valid(self, bfd_peers: list[BFDPeer]) -> None: + """Test VerifyBFDPeersRegProtocols.Input valid inputs.""" + VerifyBFDPeersRegProtocols.Input(bfd_peers=bfd_peers) + + @pytest.mark.parametrize( + ("bfd_peers"), + [ + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default"}], id="invalid"), + ], + ) + def test_invalid(self, bfd_peers: list[BFDPeer]) -> None: + """Test VerifyBFDPeersRegProtocols.Input invalid inputs.""" + with pytest.raises(ValidationError): + VerifyBFDPeersRegProtocols.Input(bfd_peers=bfd_peers) From f0ac8edcc7260f8bae9a0ca5d753d9a5ece3a8ef Mon Sep 17 00:00:00 2001 From: vitthalmagadum Date: Wed, 8 Jan 2025 05:43:11 -0500 Subject: [PATCH 2/4] improved the test coverage --- tests/units/input_models/test_bfd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/units/input_models/test_bfd.py b/tests/units/input_models/test_bfd.py index d341bb8b5..5c26c7591 100644 --- a/tests/units/input_models/test_bfd.py +++ b/tests/units/input_models/test_bfd.py @@ -35,7 +35,7 @@ def test_valid(self, bfd_peers: list[BFDPeer]) -> None: [ pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "tx_interval": 1200}], id="invalid-tx-interval"), pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "rx_interval": 1200}], id="invalid-rx-interval"), - pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "multiplier": 3}], id="invalid-multiplier"), + pytest.param([{"peer_address": "10.0.0.1", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200}], id="invalid-multiplier"), ], ) def test_invalid(self, bfd_peers: list[BFDPeer]) -> None: From cc17365169de420bf3854140091c1817db2d7b8c Mon Sep 17 00:00:00 2001 From: vitthalmagadum Date: Wed, 8 Jan 2025 22:07:51 -0500 Subject: [PATCH 3/4] updated validator function --- anta/tests/bfd.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/anta/tests/bfd.py b/anta/tests/bfd.py index 9e12b680c..13b1a6a86 100644 --- a/anta/tests/bfd.py +++ b/anta/tests/bfd.py @@ -148,17 +148,18 @@ class Input(AntaTest.Input): @field_validator("bfd_peers") @classmethod - def validate_snmp_user(cls, bfd_peers: list[T]) -> list[T]: - """Validate that 'tx_interval', 'rx_interval' or 'multiplier' field is provided in each BFD peer.""" + def validate_bfd_peers(cls, bfd_peers: list[T]) -> list[T]: + """Validate that 'tx_interval', 'rx_interval' and 'multiplier' fields are provided in each BFD peer.""" for peer in bfd_peers: + missing_fileds = [] if peer.tx_interval is None: - msg = f"{peer}; 'tx_interval' field missing in the input" - raise ValueError(msg) + missing_fileds.append("tx_interval") if peer.rx_interval is None: - msg = f"{peer}; 'rx_interval' field missing in the input" - raise ValueError(msg) + missing_fileds.append("rx_interval") if peer.multiplier is None: - msg = f"{peer}; 'multiplier' field missing in the input" + missing_fileds.append("multiplier") + if missing_fileds: + msg = f"{peer}; {', '.join(missing_fileds)} field(s) are missing in the input." raise ValueError(msg) return bfd_peers @@ -329,7 +330,7 @@ class Input(AntaTest.Input): @field_validator("bfd_peers") @classmethod - def validate_snmp_user(cls, bfd_peers: list[T]) -> list[T]: + def validate_bfd_peers(cls, bfd_peers: list[T]) -> list[T]: """Validate that 'protocols' field is provided in each BFD peer.""" for peer in bfd_peers: if peer.protocols is None: From d027827507d5101b9defedd81654a478cfdf01b6 Mon Sep 17 00:00:00 2001 From: vitthalmagadum Date: Tue, 14 Jan 2025 04:27:35 -0500 Subject: [PATCH 4/4] addressed review commenrs: updated validator msgs --- anta/tests/bfd.py | 4 ++-- tests/units/input_models/test_bfd.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/anta/tests/bfd.py b/anta/tests/bfd.py index 13b1a6a86..2361a4221 100644 --- a/anta/tests/bfd.py +++ b/anta/tests/bfd.py @@ -159,7 +159,7 @@ def validate_bfd_peers(cls, bfd_peers: list[T]) -> list[T]: if peer.multiplier is None: missing_fileds.append("multiplier") if missing_fileds: - msg = f"{peer}; {', '.join(missing_fileds)} field(s) are missing in the input." + msg = f"{peer} {', '.join(missing_fileds)} field(s) are missing in the input." raise ValueError(msg) return bfd_peers @@ -334,7 +334,7 @@ def validate_bfd_peers(cls, bfd_peers: list[T]) -> list[T]: """Validate that 'protocols' field is provided in each BFD peer.""" for peer in bfd_peers: if peer.protocols is None: - msg = f"{peer}; 'protocols' field missing in the input" + msg = f"{peer} 'protocols' field missing in the input." raise ValueError(msg) return bfd_peers diff --git a/tests/units/input_models/test_bfd.py b/tests/units/input_models/test_bfd.py index 5c26c7591..e179f39fe 100644 --- a/tests/units/input_models/test_bfd.py +++ b/tests/units/input_models/test_bfd.py @@ -3,7 +3,6 @@ # that can be found in the LICENSE file. """Tests for anta.input_models.bfd.py.""" -# pylint: disable=C0302 from __future__ import annotations from typing import TYPE_CHECKING