Repository: aristanetworks/anta
Pull request #926 (2024-11-14 13:15:17)

fix(anta.tests): Cleaning up BFD tests module
# Description

Refactoring BFD tests module to address the following issues:
- #809
- #587
- #388


# Checklist:

- [X] My code follows the style guidelines of this project
- [X] I have performed a self-review of my code
- [X] I have run pre-commit for code linting and typing (`pre-commit run`)
- [ ] I have made corresponding changes to the documentation
- [X] I have added tests that prove my fix is effective or that my feature works
- [X] New and existing unit tests pass locally with my changes (`tox -e testenv`)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926)


codspeed-hq[bot]: ## [CodSpeed Performance Report](https://codspeed.io/aristanetworks/anta/branches/vitthalmagadum:feat/BFD)

### Merging #926 will **not alter performance**

<sub>Comparing <code>vitthalmagadum:feat/BFD</code> (277e506) with <code>main</code> (91eac73)</sub>



### Summary

`✅ 8` untouched benchmarks





sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=926&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aristanetworks_anta&pullRequest=926&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=926&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=926)



Patch:
diff --git a/anta/input_models/bfd.py b/anta/input_models/bfd.py
new file mode 100644
index 00000000..9ccc6254
--- /dev/null
+++ b/anta/input_models/bfd.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.
+"""Module containing input models for BFD tests."""
+
+from __future__ import annotations
+
+from ipaddress import IPv4Address
+
+from pydantic import BaseModel, ConfigDict
+
+from anta.custom_types import BfdInterval, BfdMultiplier, BfdProtocol
+
+
+class BFDPeer(BaseModel):
+    """BFD (Bidirectional Forwarding Detection) model representing the peer details.
+
+    Only IPv4 peers are supported for now.
+    """
+
+    model_config = ConfigDict(extra="forbid")
+    peer_address: IPv4Address
+    """IPv4 address of a BFD peer."""
+    vrf: str = "default"
+    """Optional VRF for the BFD peer. Defaults to `default`."""
+    tx_interval: BfdInterval | None = None
+    """Tx interval of BFD peer in milliseconds. Required field in the `VerifyBFDPeersIntervals` test."""
+    rx_interval: BfdInterval | None = None
+    """Rx interval of BFD peer in milliseconds. Required field in the `VerifyBFDPeersIntervals` test."""
+    multiplier: BfdMultiplier | None = None
+    """Multiplier of BFD peer. Required field in the `VerifyBFDPeersIntervals` test."""
+    protocols: list[BfdProtocol] | None = None
+    """List of protocols to be verified. Required field in the `VerifyBFDPeersRegProtocols` test."""
+
+    def __str__(self) -> str:
+        """Return a human-readable string representation of the BFDPeer for reporting."""
+        return f"Peer: {self.peer_address} VRF: {self.vrf}"


Test patch:
diff --git a/anta/tests/bfd.py b/anta/tests/bfd.py
index b48cf27c..ba27f942 100644
--- a/anta/tests/bfd.py
+++ b/anta/tests/bfd.py
@@ -8,12 +8,11 @@
 from __future__ import annotations
 
 from datetime import datetime, timezone
-from ipaddress import IPv4Address
-from typing import TYPE_CHECKING, Any, ClassVar
+from typing import TYPE_CHECKING, ClassVar
 
-from pydantic import BaseModel, Field
+from pydantic import Field
 
-from anta.custom_types import BfdInterval, BfdMultiplier, BfdProtocol
+from anta.input_models.bfd import BFDPeer
 from anta.models import AntaCommand, AntaTest
 from anta.tools import get_value
 
@@ -22,12 +21,24 @@ if TYPE_CHECKING:
 
 
 class VerifyBFDSpecificPeers(AntaTest):
-    """Verifies if the IPv4 BFD peer's sessions are UP and remote disc is non-zero in the specified VRF.
+    """Verifies the state of IPv4 BFD peer sessions.
+
+    This test performs the following checks for each specified peer:
+
+      1. Confirms that the specified VRF is configured.
+      2. Verifies that the peer exists in the BFD configuration.
+      3. For each specified BFD peer:
+        - Validates that the state is `up`
+        - Confirms that the remote discriminator identifier (disc) is non-zero.
 
     Expected Results
     ----------------
-    * Success: The test will pass if IPv4 BFD peers are up and remote disc is non-zero in the specified VRF.
-    * Failure: The test will fail if IPv4 BFD peers are not found, the status is not UP or remote disc is zero in the specified VRF.
+    * Success: If all of the following conditions are met:
+        - All specified peers are found in the BFD configuration within the specified VRF.
+        - All BFD peers are `up` and remote disc is non-zero.
+    * Failure: If any of the following occur:
+        - A specified peer is not found in the BFD configuration within the specified VRF.
+        - Any BFD peer session is not `up` or the remote discriminator identifier is zero.
 
     Examples
     --------
@@ -42,7 +53,6 @@ class VerifyBFDSpecificPeers(AntaTest):
     ```
     """
 
-    description = "Verifies the IPv4 BFD peer's sessions and remote disc in the specified VRF."
     categories: ClassVar[list[str]] = ["bfd"]
     commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bfd peers", revision=1)]
 
@@ -50,20 +60,14 @@ class VerifyBFDSpecificPeers(AntaTest):
         """Input model for the VerifyBFDSpecificPeers test."""
 
         bfd_peers: list[BFDPeer]
-        """List of IPv4 BFD peers."""
-
-        class BFDPeer(BaseModel):
-            """Model for an IPv4 BFD peer."""
-
-            peer_address: IPv4Address
-            """IPv4 address of a BFD peer."""
-            vrf: str = "default"
-            """Optional VRF for BFD peer. If not provided, it defaults to `default`."""
+        """List of IPv4 BFD"""
+        BFDPeer: ClassVar[type[BFDPeer]] = BFDPeer
+        """To maintain backward compatibility."""
 
     @AntaTest.anta_test
     def test(self) -> None:
         """Main test function for VerifyBFDSpecificPeers."""
-        failures: dict[Any, Any] = {}
+        self.result.is_success()
 
         # Iterating over BFD peers
         for bfd_peer in self.inputs.bfd_peers:
@@ -77,31 +81,33 @@ class VerifyBFDSpecificPeers(AntaTest):
 
             # Check if BFD peer configured
             if not bfd_output:
-                failures[peer] = {vrf: "Not Configured"}
+                self.result.is_failure(f"{bfd_peer} - Not found")
                 continue
 
             # Check BFD peer status and remote disc
-            if not (bfd_output.get("status") == "up" and bfd_output.get("remoteDisc") != 0):
-                failures[peer] = {
-                    vrf: {
-                        "status": bfd_output.get("status"),
-                        "remote_disc": bfd_output.get("remoteDisc"),
-                    }
-                }
-
-        if not failures:
-            self.result.is_success()
-        else:
-            self.result.is_failure(f"Following BFD peers are not configured, status is not up or remote disc is zero:\n{failures}")
+            state = bfd_output.get("status")
+            remote_disc = bfd_output.get("remoteDisc")
+            if not (state == "up" and remote_disc != 0):
+                self.result.is_failure(f"{bfd_peer} - Session not properly established - State: {state} Remote Discriminator: {remote_disc}")
 
 
 class VerifyBFDPeersIntervals(AntaTest):
-    """Verifies the timers of the IPv4 BFD peers in the specified VRF.
+    """Verifies the timers of IPv4 BFD peer sessions.
+
+    This test performs the following checks for each specified peer:
+
+      1. Confirms that the specified VRF is configured.
+      2. Verifies that the peer exists in the BFD configuration.
+      3. Confirms that BFD peer is correctly configured with the `Transmit interval, Receive interval and Multiplier`.
 
     Expected Results
     ----------------
-    * Success: The test will pass if the timers of the IPv4 BFD peers are correct in the specified VRF.
-    * Failure: The test will fail if the IPv4 BFD peers are not found or their timers are incorrect in the specified VRF.
+    * Success: If all of the following conditions are met:
+        - All specified peers are found in the BFD configuration within the specified VRF.
+        - All BFD peers are correctly configured with the `Transmit interval, Receive interval and Multiplier`.
+    * Failure: If any of the following occur:
+        - A specified peer is not found in the BFD configuration within the specified VRF.
+        - Any BFD peer not correctly configured with the `Transmit interval, Receive interval and Multiplier`.
 
     Examples
     --------
@@ -129,34 +135,22 @@ class VerifyBFDPeersIntervals(AntaTest):
         """Input model for the VerifyBFDPeersIntervals test."""
 
         bfd_peers: list[BFDPeer]
-        """List of BFD peers."""
-
-        class BFDPeer(BaseModel):
-            """Model for an IPv4 BFD peer."""
-
-            peer_address: IPv4Address
-            """IPv4 address of a BFD peer."""
-            vrf: str = "default"
-            """Optional VRF for BFD peer. If not provided, it defaults to `default`."""
-            tx_interval: BfdInterval
-            """Tx interval of BFD peer in milliseconds."""
-            rx_interval: BfdInterval
-            """Rx interval of BFD peer in milliseconds."""
-            multiplier: BfdMultiplier
-            """Multiplier of BFD peer."""
+        """List of IPv4 BFD"""
+        BFDPeer: ClassVar[type[BFDPeer]] = BFDPeer
+        """To maintain backward compatibility"""
 
     @AntaTest.anta_test
     def test(self) -> None:
         """Main test function for VerifyBFDPeersIntervals."""
-        failures: dict[Any, Any] = {}
+        self.result.is_success()
 
         # Iterating over BFD peers
-        for bfd_peers in self.inputs.bfd_peers:
-            peer = str(bfd_peers.peer_address)
-            vrf = bfd_peers.vrf
-            tx_interval = bfd_peers.tx_interval
-            rx_interval = bfd_peers.rx_interval
-            multiplier = bfd_peers.multiplier
+        for bfd_peer in self.inputs.bfd_peers:
+            peer = str(bfd_peer.peer_address)
+            vrf = bfd_peer.vrf
+            tx_interval = bfd_peer.tx_interval
+            rx_interval = bfd_peer.rx_interval
+            multiplier = bfd_peer.multiplier
 
             # Check if BFD peer configured
             bfd_output = get_value(
@@ -165,7 +159,7 @@ class VerifyBFDPeersIntervals(AntaTest):
                 separator="..",
             )
             if not bfd_output:
-                failures[peer] = {vrf: "Not Configured"}
+                self.result.is_failure(f"{bfd_peer} - Not found")
                 continue
 
             # Convert interval timer(s) into milliseconds to be consistent with the inputs.
@@ -173,38 +167,34 @@ class VerifyBFDPeersIntervals(AntaTest):
             op_tx_interval = bfd_details.get("operTxInterval") // 1000
             op_rx_interval = bfd_details.get("operRxInterval") // 1000
             detect_multiplier = bfd_details.get("detectMult")
-            intervals_ok = op_tx_interval == tx_interval and op_rx_interval == rx_interval and detect_multiplier == multiplier
 
-            # Check timers of BFD peer
-            if not intervals_ok:
-                failures[peer] = {
-                    vrf: {
-                        "tx_interval": op_tx_interval,
-                        "rx_interval": op_rx_interval,
-                        "multiplier": detect_multiplier,
-                    }
-                }
+            if op_tx_interval != tx_interval:
+                self.result.is_failure(f"{bfd_peer} - Incorrect Transmit interval - Expected: {tx_interval} Actual: {op_tx_interval}")
 
-        # Check if any failures
-        if not failures:
-            self.result.is_success()
-        else:
-            self.result.is_failure(f"Following BFD peers are not configured or timers are not correct:\n{failures}")
+            if op_rx_interval != rx_interval:
+                self.result.is_failure(f"{bfd_peer} - Incorrect Receive interval - Expected: {rx_interval} Actual: {op_rx_interval}")
+
+            if detect_multiplier != multiplier:
+                self.result.is_failure(f"{bfd_peer} - Incorrect Multiplier - Expected: {multiplier} Actual: {detect_multiplier}")
 
 
 class VerifyBFDPeersHealth(AntaTest):
     """Verifies the health of IPv4 BFD peers across all VRFs.
 
-    It checks that no BFD peer is in the down state and that the discriminator value of the remote system is not zero.
+    This test performs the following checks for BFD peers across all VRFs:
 
-    Optionally, it can also verify that BFD peers have not been down before a specified threshold of hours.
+      1. Validates that the state is `up`.
+      2. Confirms that the remote discriminator identifier (disc) is non-zero.
+      3. Optionally verifies that the peer have not been down before a specified threshold of hours.
 
     Expected Results
     ----------------
-    * Success: The test will pass if all IPv4 BFD peers are up, the discriminator value of each remote system is non-zero,
-               and the last downtime of each peer is above the defined threshold.
-    * Failure: The test will fail if any IPv4 BFD peer is down, the discriminator value of any remote system is zero,
-               or the last downtime of any peer is below the defined threshold.
+    * Success: If all of the following conditions are met:
+        - All BFD peers across the VRFs are up and remote disc is non-zero.
+        - Last downtime of each peer is above the defined threshold, if specified.
+    * Failure: If any of the following occur:
+        - Any BFD peer session is not up or the remote discriminator identifier is zero.
+        - Last downtime of any peer is below the defined threshold, if specified.
 
     Examples
     --------
@@ -231,18 +221,13 @@ class VerifyBFDPeersHealth(AntaTest):
     @AntaTest.anta_test
     def test(self) -> None:
         """Main test function for VerifyBFDPeersHealth."""
-        # Initialize failure strings
-        down_failures = []
-        up_failures = []
+        self.result.is_success()
 
         # Extract the current timestamp and command output
         clock_output = self.instance_commands[1].json_output
         current_timestamp = clock_output["utcTime"]
         bfd_output = self.instance_commands[0].json_output
 
-        # set the initial result
-        self.result.is_success()
-
         # Check if any IPv4 BFD peer is configured
         ipv4_neighbors_exist = any(vrf_data["ipv4Neighbors"] for vrf_data in bfd_output["vrfs"].values())
         if not ipv4_neighbors_exist:
@@ -255,40 +240,40 @@ class VerifyBFDPeersHealth(AntaTest):
                 for peer_data in neighbor_data["peerStats"].values():
                     peer_status = peer_data["status"]
                     remote_disc = peer_data["remoteDisc"]
-                    remote_disc_info = f" with remote disc {remote_disc}" if remote_disc == 0 else ""
                     last_down = peer_data["lastDown"]
                     hours_difference = (
                         datetime.fromtimestamp(current_timestamp, tz=timezone.utc) - datetime.fromtimestamp(last_down, tz=timezone.utc)
                     ).total_seconds() / 3600
 
-                    # Check if peer status is not up
-                    if peer_status != "up":
-                        down_failures.append(f"{peer} is {peer_status} in {vrf} VRF{remote_disc_info}.")
+                    if not (peer_status == "up" and remote_disc != 0):
+                        self.result.is_failure(
+                            f"Peer: {peer} VRF: {vrf} - Session not properly established - State: {peer_status} Remote Discriminator: {remote_disc}"
+                        )
 
                     # Check if the last down is within the threshold
-                    elif self.inputs.down_threshold and hours_difference < self.inputs.down_threshold:
-                        up_failures.append(f"{peer} in {vrf} VRF was down {round(hours_difference)} hours ago{remote_disc_info}.")
+                    if self.inputs.down_threshold and hours_difference < self.inputs.down_threshold:
+                        self.result.is_failure(
+                            f"Peer: {peer} VRF: {vrf} - Session failure detected within the expected uptime threshold ({round(hours_difference)} hours ago)"
+                        )
 
-                    # Check if remote disc is 0
-                    elif remote_disc == 0:
-                        up_failures.append(f"{peer} in {vrf} VRF has remote disc {remote_disc}.")
 
-        # Check if there are any failures
-        if down_failures:
-            down_failures_str = "\n".join(down_failures)
-            self.result.is_failure(f"Following BFD peers are not up:\n{down_failures_str}")
-        if up_failures:
-            up_failures_str = "\n".join(up_failures)
-            self.result.is_failure(f"\nFollowing BFD peers were down:\n{up_failures_str}")
+class VerifyBFDPeersRegProtocols(AntaTest):
+    """Verifies the registered routing protocol of IPv4 BFD peer sessions.
 
+    This test performs the following checks for each specified peer:
 
-class VerifyBFDPeersRegProtocols(AntaTest):
-    """Verifies that IPv4 BFD peer(s) have the specified protocol(s) registered.
+      1. Confirms that the specified VRF is configured.
+      2. Verifies that the peer exists in the BFD configuration.
+      3. Confirms that BFD peer is correctly configured with the `routing protocol`.
 
     Expected Results
     ----------------
-    * Success: The test will pass if IPv4 BFD peers are registered with the specified protocol(s).
-    * Failure: The test will fail if IPv4 BFD peers are not found or the specified protocol(s) are not registered for the BFD peer(s).
+    * Success: If all of the following conditions are met:
+        - All specified peers are found in the BFD configuration within the specified VRF.
+        - All BFD peers are correctly configured with the `routing protocol`.
+    * Failure: If any of the following occur:
+        - A specified peer is not found in the BFD configuration within the specified VRF.
+        - Any BFD peer not correctly configured with the `routing protocol`.
 
     Examples
     --------
@@ -310,23 +295,14 @@ class VerifyBFDPeersRegProtocols(AntaTest):
         """Input model for the VerifyBFDPeersRegProtocols test."""
 
         bfd_peers: list[BFDPeer]
-        """List of IPv4 BFD peers."""
-
-        class BFDPeer(BaseModel):
-            """Model for an IPv4 BFD peer."""
-
-            peer_address: IPv4Address
-            """IPv4 address of a BFD peer."""
-            vrf: str = "default"
-            """Optional VRF for BFD peer. If not provided, it defaults to `default`."""
-            protocols: list[BfdProtocol]
-            """List of protocols to be verified."""
+        """List of IPv4 BFD"""
+        BFDPeer: ClassVar[type[BFDPeer]] = BFDPeer
+        """To maintain backward compatibility"""
 
     @AntaTest.anta_test
     def test(self) -> None:
         """Main test function for VerifyBFDPeersRegProtocols."""
-        # Initialize failure messages
-        failures: dict[Any, Any] = {}
+        self.result.is_success()
 
         # Iterating over BFD peers, extract the parameters and command output
         for bfd_peer in self.inputs.bfd_peers:
@@ -341,16 +317,11 @@ class VerifyBFDPeersRegProtocols(AntaTest):
 
             # Check if BFD peer configured
             if not bfd_output:
-                failures[peer] = {vrf: "Not Configured"}
+                self.result.is_failure(f"{bfd_peer} - Not found")
                 continue
 
             # Check registered protocols
-            difference = set(protocols) - set(get_value(bfd_output, "peerStatsDetail.apps"))
-
+            difference = sorted(set(protocols) - set(get_value(bfd_output, "peerStatsDetail.apps")))
             if difference:
-                failures[peer] = {vrf: sorted(difference)}
-
-        if not failures:
-            self.result.is_success()
-        else:
-            self.result.is_failure(f"The following BFD peers are not configured or have non-registered protocol(s):\n{failures}")
+                failures = " ".join(f"`{item}`" for item in difference)
+                self.result.is_failure(f"{bfd_peer} - {failures} routing protocol(s) not configured")
diff --git a/docs/api/tests.bfd.md b/docs/api/tests.bfd.md
index 719466e6..ee950875 100644
--- a/docs/api/tests.bfd.md
+++ b/docs/api/tests.bfd.md
@@ -7,7 +7,10 @@ anta_title: ANTA catalog for BFD tests
   ~ that can be found in the LICENSE file.
   -->
 
+# Tests
+
 ::: anta.tests.bfd
+
     options:
       show_root_heading: false
       show_root_toc_entry: false
@@ -18,3 +21,16 @@ anta_title: ANTA catalog for BFD tests
       filters:
         - "!test"
         - "!render"
+
+# Input models
+
+::: anta.input_models.bfd
+
+    options:
+      show_root_heading: false
+      show_root_toc_entry: false
+      show_bases: false
+      merge_init_into_class: false
+      anta_hide_test_module_description: true
+      show_labels: true
+      filters: ["!^__str__"]
diff --git a/tests/units/anta_tests/test_bfd.py b/tests/units/anta_tests/test_bfd.py
index 9bd64656..952e8388 100644
--- a/tests/units/anta_tests/test_bfd.py
+++ b/tests/units/anta_tests/test_bfd.py
@@ -107,8 +107,8 @@ DATA: list[dict[str, Any]] = [
         "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'}}"
+                "Peer: 192.0.255.7 VRF: CS - Not found",
+                "Peer: 192.0.255.70 VRF: MGMT - Not found",
             ],
         },
     },
@@ -160,9 +160,11 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "Following BFD peers are not configured or timers are not correct:\n"
-                "{'192.0.255.7': {'default': {'tx_interval': 1300, 'rx_interval': 1200, 'multiplier': 4}}, "
-                "'192.0.255.70': {'MGMT': {'tx_interval': 120, 'rx_interval': 120, 'multiplier': 5}}}"
+                "Peer: 192.0.255.7 VRF: default - Incorrect Transmit interval - Expected: 1200 Actual: 1300",
+                "Peer: 192.0.255.7 VRF: default - Incorrect Multiplier - Expected: 3 Actual: 4",
+                "Peer: 192.0.255.70 VRF: MGMT - Incorrect Transmit interval - Expected: 1200 Actual: 120",
+                "Peer: 192.0.255.70 VRF: MGMT - Incorrect Receive interval - Expected: 1200 Actual: 120",
+                "Peer: 192.0.255.70 VRF: MGMT - Incorrect Multiplier - Expected: 3 Actual: 5",
             ],
         },
     },
@@ -239,8 +241,8 @@ DATA: list[dict[str, Any]] = [
         "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'}}"
+                "Peer: 192.0.255.7 VRF: CS - Not found",
+                "Peer: 192.0.255.70 VRF: MGMT - Not found",
             ],
         },
     },
@@ -255,7 +257,7 @@ DATA: list[dict[str, Any]] = [
                             "192.0.255.7": {
                                 "peerStats": {
                                     "": {
-                                        "status": "Down",
+                                        "status": "down",
                                         "remoteDisc": 108328132,
                                     }
                                 }
@@ -267,7 +269,7 @@ DATA: list[dict[str, Any]] = [
                             "192.0.255.70": {
                                 "peerStats": {
                                     "": {
-                                        "status": "Down",
+                                        "status": "down",
                                         "remoteDisc": 0,
                                     }
                                 }
@@ -281,9 +283,8 @@ DATA: list[dict[str, Any]] = [
         "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}}}"
+                "Peer: 192.0.255.7 VRF: default - Session not properly established - State: down Remote Discriminator: 108328132",
+                "Peer: 192.0.255.70 VRF: MGMT - Session not properly established - State: down Remote Discriminator: 0",
             ],
         },
     },
@@ -414,7 +415,8 @@ DATA: list[dict[str, Any]] = [
         "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."
+                "Peer: 192.0.255.7 VRF: default - Session not properly established - State: down Remote Discriminator: 0",
+                "Peer: 192.0.255.71 VRF: MGMT - Session not properly established - State: down Remote Discriminator: 0",
             ],
         },
     },
@@ -458,7 +460,10 @@ DATA: list[dict[str, Any]] = [
         "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."],
+            "messages": [
+                "Peer: 192.0.255.7 VRF: default - Session not properly established - State: up Remote Discriminator: 0",
+                "Peer: 192.0.255.71 VRF: default - Session not properly established - State: up Remote Discriminator: 0",
+            ],
         },
     },
     {
@@ -512,8 +517,9 @@ DATA: list[dict[str, Any]] = [
         "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."
+                "Peer: 192.0.255.7 VRF: default - Session failure detected within the expected uptime threshold (3 hours ago)",
+                "Peer: 192.0.255.71 VRF: default - Session failure detected within the expected uptime threshold (3 hours ago)",
+                "Peer: 192.0.255.17 VRF: default - Session failure detected within the expected uptime threshold (3 hours ago)",
             ],
         },
     },
@@ -609,15 +615,14 @@ DATA: list[dict[str, Any]] = [
         "inputs": {
             "bfd_peers": [
                 {"peer_address": "192.0.255.7", "vrf": "default", "protocols": ["isis"]},
-                {"peer_address": "192.0.255.70", "vrf": "MGMT", "protocols": ["isis"]},
+                {"peer_address": "192.0.255.70", "vrf": "MGMT", "protocols": ["isis", "ospf"]},
             ]
         },
         "expected": {
             "result": "failure",
             "messages": [
-                "The following BFD peers are not configured or have non-registered protocol(s):\n"
-                "{'192.0.255.7': {'default': ['isis']}, "
-                "'192.0.255.70': {'MGMT': ['isis']}}"
+                "Peer: 192.0.255.7 VRF: default - `isis` routing protocol(s) not configured",
+                "Peer: 192.0.255.70 VRF: MGMT - `isis` `ospf` routing protocol(s) not configured",
             ],
         },
     },
@@ -641,8 +646,8 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "The following BFD peers are not configured or have non-registered protocol(s):\n"
-                "{'192.0.255.7': {'default': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}"
+                "Peer: 192.0.255.7 VRF: default - Not found",
+                "Peer: 192.0.255.70 VRF: MGMT - Not found",
             ],
         },
     },