Repository: aristanetworks/anta
Pull request #939 (2024-11-29 06:50:59)

fix(anta.tests): Cleaning up AVT tests module (VerifyAVTSpecificPath)
# Description

Refactoring AVT tests module to address the following issues:

- https://github.com/aristanetworks/anta/issues/809
- https://github.com/aristanetworks/anta/issues/587
- https://github.com/aristanetworks/anta/issues/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=939) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=939&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=939&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=939&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=939&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=939&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=939)


codspeed-hq[bot]: ## [CodSpeed Performance Report](https://codspeed.io/aristanetworks/anta/branches/vitthalmagadum%3Afeat%2FAVT)

### Merging #939 will **not alter performance**

<sub>Comparing <code>vitthalmagadum:feat/AVT</code> (2c0ba6a) with <code>main</code> (d2c8218)</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=939) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=939&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=939&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=939&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=939&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=939&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=939)


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=939) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=939&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=939&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=939&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=939&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=939&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=939)


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=939) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=939&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=939&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=939&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=939&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=939&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=939)


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=939) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=aristanetworks_anta&pullRequest=939&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=939&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=939&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=939&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=939&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=939)



Patch:
diff --git a/anta/input_models/avt.py b/anta/input_models/avt.py
new file mode 100644
index 00000000..9219c2fc
--- /dev/null
+++ b/anta/input_models/avt.py
@@ -0,0 +1,36 @@
+# 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 AVT tests."""
+
+from __future__ import annotations
+
+from ipaddress import IPv4Address
+
+from pydantic import BaseModel, ConfigDict
+
+
+class AVTPath(BaseModel):
+    """AVT (Adaptive Virtual Topology) model representing path details and associated information."""
+
+    model_config = ConfigDict(extra="forbid")
+    vrf: str = "default"
+    """VRF context. Defaults to `default`."""
+    avt_name: str
+    """The name of the Adaptive Virtual Topology (AVT)."""
+    destination: IPv4Address
+    """The IPv4 address of the destination peer in the AVT."""
+    next_hop: IPv4Address
+    """The IPv4 address of the next hop used to reach the AVT peer."""
+    path_type: str | None = None
+    """Specifies the type of path for the AVT. If not specified, both types 'direct' and 'multihop' are considered."""
+
+    def __str__(self) -> str:
+        """Return a human-readable string representation of the AVTPath for reporting.
+
+        Examples
+        --------
+        AVT CONTROL-PLANE-PROFILE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1)
+
+        """
+        return f"AVT {self.avt_name} VRF: {self.vrf} (Destination: {self.destination}, Next-hop: {self.next_hop})"


Test patch:
diff --git a/anta/tests/avt.py b/anta/tests/avt.py
index 66b30bab..b0f1a465 100644
--- a/anta/tests/avt.py
+++ b/anta/tests/avt.py
@@ -7,12 +7,10 @@
 # mypy: disable-error-code=attr-defined
 from __future__ import annotations
 
-from ipaddress import IPv4Address
 from typing import ClassVar
 
-from pydantic import BaseModel
-
 from anta.decorators import skip_on_platforms
+from anta.input_models.avt import AVTPath
 from anta.models import AntaCommand, AntaTemplate, AntaTest
 from anta.tools import get_value
 
@@ -71,14 +69,22 @@ class VerifyAVTPathHealth(AntaTest):
 
 
 class VerifyAVTSpecificPath(AntaTest):
-    """Verifies the status and type of an Adaptive Virtual Topology (AVT) path for a specified VRF.
+    """Verifies the Adaptive Virtual Topology (AVT) path.
+
+    This test performs the following checks for each specified LLDP neighbor:
+
+      1. Confirming that the AVT paths are associated with the specified VRF.
+      2. Verifying that each AVT path is active and valid.
+      3. Ensuring that the AVT path matches the specified type (direct/multihop) if provided.
 
     Expected Results
     ----------------
-    * Success: The test will pass if all AVT paths for the specified VRF are active, valid, and match the specified type (direct/multihop) if provided.
-               If multiple paths are configured, the test will pass only if all the paths are valid and active.
-    * Failure: The test will fail if no AVT paths are configured for the specified VRF, or if any configured path is not active, valid,
-               or does not match the specified type.
+    * Success: The test will pass if all of the following conditions are met:
+        - All AVT paths for the specified VRF are active, valid, and match the specified path type (direct/multihop), if provided.
+        - If multiple paths are configured, the test will pass only if all paths meet these criteria.
+    * Failure: The test will fail if any of the following conditions are met:
+        - No AVT paths are configured for the specified VRF.
+        - Any configured path is inactive, invalid, or does not match the specified type.
 
     Examples
     --------
@@ -94,35 +100,16 @@ class VerifyAVTSpecificPath(AntaTest):
     ```
     """
 
-    description = "Verifies the status and type of an AVT path for a specified VRF."
     categories: ClassVar[list[str]] = ["avt"]
-    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
-        AntaTemplate(template="show adaptive-virtual-topology path vrf {vrf} avt {avt_name} destination {destination}")
-    ]
+    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show adaptive-virtual-topology path", revision=1)]
 
     class Input(AntaTest.Input):
         """Input model for the VerifyAVTSpecificPath test."""
 
-        avt_paths: list[AVTPaths]
+        avt_paths: list[AVTPath]
         """List of AVT paths to verify."""
-
-        class AVTPaths(BaseModel):
-            """Model for the details of AVT paths."""
-
-            vrf: str = "default"
-            """The VRF for the AVT path. Defaults to 'default' if not provided."""
-            avt_name: str
-            """Name of the adaptive virtual topology."""
-            destination: IPv4Address
-            """The IPv4 address of the AVT peer."""
-            next_hop: IPv4Address
-            """The IPv4 address of the next hop for the AVT peer."""
-            path_type: str | None = None
-            """The type of the AVT path. If not provided, both 'direct' and 'multihop' paths are considered."""
-
-    def render(self, template: AntaTemplate) -> list[AntaCommand]:
-        """Render the template for each input AVT path/peer."""
-        return [template.render(vrf=path.vrf, avt_name=path.avt_name, destination=path.destination) for path in self.inputs.avt_paths]
+        AVTPaths: ClassVar[type[AVTPath]] = AVTPath
+        """To maintain backward compatibility."""
 
     @skip_on_platforms(["cEOSLab", "vEOS-lab"])
     @AntaTest.anta_test
@@ -131,59 +118,39 @@ class VerifyAVTSpecificPath(AntaTest):
         # Assume the test is successful until a failure is detected
         self.result.is_success()
 
-        # Process each command in the instance
-        for command, input_avt in zip(self.instance_commands, self.inputs.avt_paths):
-            # Extract the command output and parameters
-            vrf = command.params.vrf
-            avt_name = command.params.avt_name
-            peer = str(command.params.destination)
-
-            command_output = command.json_output.get("vrfs", {})
-
-            # If no AVT is configured, mark the test as failed and skip to the next command
-            if not command_output:
-                self.result.is_failure(f"AVT configuration for peer '{peer}' under topology '{avt_name}' in VRF '{vrf}' is not found.")
-                continue
-
-            # Extract the AVT paths
-            avt_paths = get_value(command_output, f"{vrf}.avts.{avt_name}.avtPaths")
-            next_hop, input_path_type = str(input_avt.next_hop), input_avt.path_type
+        command_output = self.instance_commands[0].json_output
+        for avt_path in self.inputs.avt_paths:
+            if (path_output := get_value(command_output, f"vrfs.{avt_path.vrf}.avts.{avt_path.avt_name}.avtPaths")) is None:
+                self.result.is_failure(f"{avt_path} - No AVT path configured")
+                return
 
-            nexthop_path_found = path_type_found = False
+            path_found = path_type_found = False
 
             # Check each AVT path
-            for path, path_data in avt_paths.items():
-                # If the path does not match the expected next hop, skip to the next path
-                if path_data.get("nexthopAddr") != next_hop:
-                    continue
-
-                nexthop_path_found = True
+            for path, path_data in path_output.items():
+                dest = path_data.get("destination")
+                nexthop = path_data.get("nexthopAddr")
                 path_type = "direct" if get_value(path_data, "flags.directPath") else "multihop"
 
-                # If the path type does not match the expected path type, skip to the next path
-                if input_path_type and path_type != input_path_type:
-                    continue
-
-                path_type_found = True
-                valid = get_value(path_data, "flags.valid")
-                active = get_value(path_data, "flags.active")
-
-                # Check the path status and type against the expected values
-                if not all([valid, active]):
-                    failure_reasons = []
-                    if not get_value(path_data, "flags.active"):
-                        failure_reasons.append("inactive")
-                    if not get_value(path_data, "flags.valid"):
-                        failure_reasons.append("invalid")
-                    # Construct the failure message prefix
-                    failed_log = f"AVT path '{path}' for topology '{avt_name}' in VRF '{vrf}'"
-                    self.result.is_failure(f"{failed_log} is {', '.join(failure_reasons)}.")
-
-            # If no matching next hop or path type was found, mark the test as failed
-            if not nexthop_path_found or not path_type_found:
-                self.result.is_failure(
-                    f"No '{input_path_type}' path found with next-hop address '{next_hop}' for AVT peer '{peer}' under topology '{avt_name}' in VRF '{vrf}'."
-                )
+                if not avt_path.path_type:
+                    path_found = all([dest == str(avt_path.destination), nexthop == str(avt_path.next_hop)])
+
+                else:
+                    path_type_found = all([dest == str(avt_path.destination), nexthop == str(avt_path.next_hop), path_type == avt_path.path_type])
+                    if path_type_found:
+                        path_found = True
+                        # Check the path status and type against the expected values
+                        valid = get_value(path_data, "flags.valid")
+                        active = get_value(path_data, "flags.active")
+                        if not all([valid, active]):
+                            self.result.is_failure(f"{avt_path} - Incorrect path {path} - Valid: {valid}, Active: {active}")
+
+            # If no matching path found, mark the test as failed
+            if not path_found:
+                if avt_path.path_type and not path_type_found:
+                    self.result.is_failure(f"{avt_path} Path Type: {avt_path.path_type} - Path not found")
+                else:
+                    self.result.is_failure(f"{avt_path} - Path not found")
 
 
 class VerifyAVTRole(AntaTest):
diff --git a/docs/api/tests.avt.md b/docs/api/tests.avt.md
index f9e1acfd..a55fcce1 100644
--- a/docs/api/tests.avt.md
+++ b/docs/api/tests.avt.md
@@ -7,7 +7,10 @@ anta_title: ANTA catalog for Adaptive Virtual Topology (AVT) tests
   ~ that can be found in the LICENSE file.
   -->
 
+# Tests
+
 ::: anta.tests.avt
+
     options:
       show_root_heading: false
       show_root_toc_entry: false
@@ -18,3 +21,18 @@ anta_title: ANTA catalog for Adaptive Virtual Topology (AVT) tests
       filters:
         - "!test"
         - "!render"
+
+# Input models
+
+::: anta.input_models.avt
+
+    options:
+      show_root_heading: false
+      show_root_toc_entry: false
+      show_bases: false
+      anta_hide_test_module_description: true
+      merge_init_into_class: false
+      show_labels: true
+      filters:
+        - "!^__init__"
+        - "!^__str__"
diff --git a/examples/tests.yaml b/examples/tests.yaml
index d2a02998..86ed117a 100644
--- a/examples/tests.yaml
+++ b/examples/tests.yaml
@@ -63,7 +63,7 @@ anta.tests.avt:
       # Verifies the AVT role of a device.
       role: edge
   - VerifyAVTSpecificPath:
-      # Verifies the status and type of an AVT path for a specified VRF.
+      # Verifies the Adaptive Virtual Topology (AVT) path.
       avt_paths:
         - avt_name: CONTROL-PLANE-PROFILE
           vrf: default
diff --git a/tests/units/anta_tests/test_avt.py b/tests/units/anta_tests/test_avt.py
index 80fbce03..d9cdaa1f 100644
--- a/tests/units/anta_tests/test_avt.py
+++ b/tests/units/anta_tests/test_avt.py
@@ -361,48 +361,63 @@ DATA: list[dict[str, Any]] = [
                         "avts": {
                             "DEFAULT-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                }
-                            }
-                        }
-                    }
-                }
-            },
-            {
-                "vrfs": {
-                    "data": {
-                        "avts": {
-                            "DATA-AVT-POLICY-CONTROL-PLANE": {
-                                "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:8": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                    "multihop:1": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                    "multihop:3": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
                                 }
                             }
-                        }
-                    }
-                }
-            },
-            {
-                "vrfs": {
+                        },
+                    },
                     "data": {
                         "avts": {
                             "DATA-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:8": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "direct:8": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "multihop:1": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "multihop:3": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
                                 }
-                            }
+                            },
                         }
-                    }
+                    },
                 }
             },
         ],
@@ -420,36 +435,85 @@ DATA: list[dict[str, Any]] = [
         "test": VerifyAVTSpecificPath,
         "eos_data": [
             {"vrfs": {}},
+        ],
+        "inputs": {
+            "avt_paths": [
+                {"avt_name": "MGMT-AVT-POLICY-DEFAULT", "vrf": "default", "destination": "10.101.255.2", "next_hop": "10.101.255.1", "path_type": "multihop"},
+                {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.2", "path_type": "multihop"},
+            ]
+        },
+        "expected": {
+            "result": "failure",
+            "messages": ["AVT MGMT-AVT-POLICY-DEFAULT VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1) - No AVT path configured"],
+        },
+    },
+    {
+        "name": "failure-path_type_check_true",
+        "test": VerifyAVTSpecificPath,
+        "eos_data": [
             {
                 "vrfs": {
+                    "default": {
+                        "avts": {
+                            "DEFAULT-AVT-POLICY-CONTROL-PLANE": {
+                                "avtPaths": {
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                }
+                            }
+                        },
+                    },
                     "data": {
                         "avts": {
                             "DATA-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.3",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.3",
+                                    },
                                 }
-                            }
+                            },
                         }
-                    }
+                    },
                 }
             },
         ],
         "inputs": {
             "avt_paths": [
-                {"avt_name": "MGMT-AVT-POLICY-DEFAULT", "vrf": "default", "destination": "10.101.255.2", "next_hop": "10.101.255.1", "path_type": "multihop"},
-                {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.2", "path_type": "multihop"},
+                {
+                    "avt_name": "DEFAULT-AVT-POLICY-CONTROL-PLANE",
+                    "vrf": "default",
+                    "destination": "10.101.255.2",
+                    "next_hop": "10.101.255.11",
+                    "path_type": "multihop",
+                },
+                {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21", "path_type": "direct"},
             ]
         },
         "expected": {
             "result": "failure",
-            "messages": ["AVT configuration for peer '10.101.255.2' under topology 'MGMT-AVT-POLICY-DEFAULT' in VRF 'default' is not found."],
+            "messages": [
+                "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.11) Path Type: multihop - Path not found",
+                "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.21) Path Type: direct - Path not found",
+            ],
         },
     },
     {
-        "name": "failure-no-path-with-correct-next-hop",
+        "name": "failure-path_type_check_false",
         "test": VerifyAVTSpecificPath,
         "eos_data": [
             {
@@ -458,30 +522,38 @@ DATA: list[dict[str, Any]] = [
                         "avts": {
                             "DEFAULT-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
                                 }
                             }
-                        }
-                    }
-                }
-            },
-            {
-                "vrfs": {
+                        },
+                    },
                     "data": {
                         "avts": {
                             "DATA-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.3",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.3",
+                                    },
                                 }
-                            }
+                            },
                         }
-                    }
+                    },
                 }
             },
         ],
@@ -492,18 +564,15 @@ DATA: list[dict[str, Any]] = [
                     "vrf": "default",
                     "destination": "10.101.255.2",
                     "next_hop": "10.101.255.11",
-                    "path_type": "multihop",
                 },
-                {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21", "path_type": "direct"},
+                {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21"},
             ]
         },
         "expected": {
             "result": "failure",
             "messages": [
-                "No 'multihop' path found with next-hop address '10.101.255.11' for AVT peer '10.101.255.2' under "
-                "topology 'DEFAULT-AVT-POLICY-CONTROL-PLANE' in VRF 'default'.",
-                "No 'direct' path found with next-hop address '10.101.255.21' for AVT peer '10.101.255.1' under "
-                "topology 'DATA-AVT-POLICY-CONTROL-PLANE' in VRF 'data'.",
+                "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.11) - Path not found",
+                "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.21) - Path not found",
             ],
         },
     },
@@ -517,30 +586,48 @@ DATA: list[dict[str, Any]] = [
                         "avts": {
                             "DEFAULT-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:1": {"flags": {"directPath": True, "valid": False, "active": False}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": False}, "nexthopAddr": "10.101.255.1"},
+                                    "multihop:3": {
+                                        "flags": {"directPath": False, "valid": False, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.2",
+                                    },
                                 }
                             }
-                        }
-                    }
-                }
-            },
-            {
-                "vrfs": {
+                        },
+                    },
                     "data": {
                         "avts": {
                             "DATA-AVT-POLICY-CONTROL-PLANE": {
                                 "avtPaths": {
-                                    "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "direct:9": {"flags": {"directPath": True, "valid": False, "active": True}, "nexthopAddr": "10.101.255.1"},
-                                    "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
-                                    "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"},
+                                    "direct:10": {
+                                        "flags": {"directPath": True, "valid": False, "active": True},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "direct:9": {
+                                        "flags": {"directPath": True, "valid": True, "active": False},
+                                        "nexthopAddr": "10.101.255.1",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "direct:8": {
+                                        "flags": {"directPath": True, "valid": False, "active": False},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "multihop:1": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
+                                    "multihop:3": {
+                                        "flags": {"directPath": False, "valid": True, "active": True},
+                                        "nexthopAddr": "10.101.255.2",
+                                        "destination": "10.101.255.1",
+                                    },
                                 }
-                            }
+                            },
                         }
-                    }
+                    },
                 }
             },
         ],
@@ -559,8 +646,12 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "AVT path 'multihop:3' for topology 'DEFAULT-AVT-POLICY-CONTROL-PLANE' in VRF 'default' is inactive.",
-                "AVT path 'direct:9' for topology 'DATA-AVT-POLICY-CONTROL-PLANE' in VRF 'data' is invalid.",
+                "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1) - "
+                "Incorrect path multihop:3 - Valid: False, Active: True",
+                "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.1) - "
+                "Incorrect path direct:10 - Valid: False, Active: True",
+                "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.1) - "
+                "Incorrect path direct:9 - Valid: True, Active: False",
             ],
         },
     },