Repository: aristanetworks/anta
Pull request #964 (2024-12-12 11:38:13)

fix(anta.tests): Cleaning up flow-tracking tests module
# Description

Refactoring flow-tracking 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`)
- [X] 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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


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

### Merging #964 will **not alter performance**

<sub>Comparing <code>vitthalmagadum:feat/flow_tracking</code> (3533103) with <code>main</code> (1e23172)</sub>



### Summary

`✅ 8` untouched benchmarks  




sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


vitthalmagadum: > please move back revision to 1

Reverted to revision 1.
Thanks!!
sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.7% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_anta&pullRequest=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)


sonarqubecloud[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=964) **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=964&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=964&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=964&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=964&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=964&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_anta&pullRequest=964)



Patch:
diff --git a/anta/input_models/flow_tracking.py b/anta/input_models/flow_tracking.py
new file mode 100644
index 00000000..79676d93
--- /dev/null
+++ b/anta/input_models/flow_tracking.py
@@ -0,0 +1,72 @@
+# 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.
+"""Module containing input models for flow tracking tests."""
+
+from __future__ import annotations
+
+from pydantic import BaseModel, ConfigDict
+
+
+class FlowTracker(BaseModel):
+    """Flow Tracking model representing the tracker details."""
+
+    model_config = ConfigDict(extra="forbid")
+    name: str
+    """The name of the flow tracker."""
+    record_export: RecordExport | None = None
+    """Configuration for record export, specifying details about timeouts."""
+    exporters: list[Exporter] | None = None
+    """A list of exporters associated with the flow tracker."""
+
+    def __str__(self) -> str:
+        """Return a human-readable string representation of the FlowTracker for reporting.
+
+        Examples
+        --------
+        Flow Tracker: FLOW-TRACKER
+
+        """
+        return f"Flow Tracker: {self.name}"
+
+
+class RecordExport(BaseModel):
+    """Model representing the record export configuration for a flow tracker."""
+
+    model_config = ConfigDict(extra="forbid")
+    on_inactive_timeout: int
+    """The timeout in milliseconds for exporting flow records when the flow becomes inactive."""
+    on_interval: int
+    """The interval in milliseconds for exporting flow records."""
+
+    def __str__(self) -> str:
+        """Return a human-readable string representation of the RecordExport for reporting.
+
+        Examples
+        --------
+        Inactive Timeout: 60000, Active Interval: 300000
+
+        """
+        return f"Inactive Timeout: {self.on_inactive_timeout}, Active Interval: {self.on_interval}"
+
+
+class Exporter(BaseModel):
+    """Model representing the exporter used for flow record export."""
+
+    model_config = ConfigDict(extra="forbid")
+    name: str
+    """The name of the exporter."""
+    local_interface: str
+    """The local interface used by the exporter to send flow records."""
+    template_interval: int
+    """The template interval, in milliseconds, for the exporter to refresh the flow template."""
+
+    def __str__(self) -> str:
+        """Return a human-readable string representation of the Exporter for reporting.
+
+        Examples
+        --------
+        Exporter: CVP-TELEMETRY
+
+        """
+        return f"Exporter: {self.name}"


Test patch:
diff --git a/anta/tests/flow_tracking.py b/anta/tests/flow_tracking.py
index 245d1fd8..5c10b302 100644
--- a/anta/tests/flow_tracking.py
+++ b/anta/tests/flow_tracking.py
@@ -9,37 +9,13 @@ from __future__ import annotations
 
 from typing import ClassVar
 
-from pydantic import BaseModel
-
 from anta.decorators import skip_on_platforms
+from anta.input_models.flow_tracking import FlowTracker
 from anta.models import AntaCommand, AntaTemplate, AntaTest
-from anta.tools import get_failed_logs
-
+from anta.tools import get_value
 
-def validate_record_export(record_export: dict[str, str], tracker_info: dict[str, str]) -> str:
-    """Validate the record export configuration against the tracker info.
-
-    Parameters
-    ----------
-    record_export
-        The expected record export configuration.
-    tracker_info
-        The actual tracker info from the command output.
 
-    Returns
-    -------
-    str
-        A failure message if the record export configuration does not match, otherwise blank string.
-    """
-    failed_log = ""
-    actual_export = {"inactive timeout": tracker_info.get("inactiveTimeout"), "interval": tracker_info.get("activeInterval")}
-    expected_export = {"inactive timeout": record_export.get("on_inactive_timeout"), "interval": record_export.get("on_interval")}
-    if actual_export != expected_export:
-        failed_log = get_failed_logs(expected_export, actual_export)
-    return failed_log
-
-
-def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str, str]) -> str:
+def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str, str]) -> list[str]:
     """Validate the exporter configurations against the tracker info.
 
     Parameters
@@ -51,36 +27,52 @@ def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str,
 
     Returns
     -------
-    str
-        Failure message if any exporter configuration does not match.
+    list
+        List of failure messages for any exporter configuration that does not match.
     """
-    failed_log = ""
+    failure_messages = []
     for exporter in exporters:
-        exporter_name = exporter["name"]
+        exporter_name = exporter.name
         actual_exporter_info = tracker_info["exporters"].get(exporter_name)
         if not actual_exporter_info:
-            failed_log += f"\nExporter `{exporter_name}` is not configured."
+            failure_messages.append(f"{exporter} - Not configured")
             continue
+        local_interface = actual_exporter_info["localIntf"]
+        template_interval = actual_exporter_info["templateInterval"]
 
-        expected_exporter_data = {"local interface": exporter["local_interface"], "template interval": exporter["template_interval"]}
-        actual_exporter_data = {"local interface": actual_exporter_info["localIntf"], "template interval": actual_exporter_info["templateInterval"]}
+        if local_interface != exporter.local_interface:
+            failure_messages.append(f"{exporter} - Incorrect local interface - Expected: {exporter.local_interface}, Actual: {local_interface}")
 
-        if expected_exporter_data != actual_exporter_data:
-            failed_msg = get_failed_logs(expected_exporter_data, actual_exporter_data)
-            failed_log += f"\nExporter `{exporter_name}`: {failed_msg}"
-    return failed_log
+        if template_interval != exporter.template_interval:
+            failure_messages.append(f"{exporter} - Incorrect template interval - Expected: {exporter.template_interval}, Actual: {template_interval}")
+    return failure_messages
 
 
 class VerifyHardwareFlowTrackerStatus(AntaTest):
-    """Verifies if hardware flow tracking is running and an input tracker is active.
+    """Verifies the hardware flow tracking state.
+
+    This test performs the following checks:
 
-    This test optionally verifies the tracker interval/timeout and exporter configuration.
+      1. Confirms that hardware flow tracking is running.
+      2. For each specified flow tracker:
+        - Confirms that the tracker is active.
+        - Optionally, checks the tracker interval/timeout configuration.
+        - Optionally, verifies the tracker exporter configuration
 
     Expected Results
     ----------------
-    * Success: The test will pass if hardware flow tracking is running and an input tracker is active.
-    * Failure: The test will fail if hardware flow tracking is not running, an input tracker is not active,
-               or the tracker interval/timeout and exporter configuration does not match the expected values.
+    * Success: The test will pass if all of the following conditions are met:
+        - Hardware flow tracking is running.
+        - For each specified flow tracker:
+            - The flow tracker is active.
+            - The tracker interval/timeout matches the expected values, if provided.
+            - The exporter configuration matches the expected values, if provided.
+    * Failure: The test will fail if any of the following conditions are met:
+        - Hardware flow tracking is not running.
+        - For any specified flow tracker:
+            - The flow tracker is not active.
+            - The tracker interval/timeout does not match the expected values, if provided.
+            - The exporter configuration does not match the expected values, if provided.
 
     Examples
     --------
@@ -99,11 +91,8 @@ class VerifyHardwareFlowTrackerStatus(AntaTest):
     ```
     """
 
-    description = (
-        "Verifies if hardware flow tracking is running and an input tracker is active. Optionally verifies the tracker interval/timeout and exporter configuration."
-    )
     categories: ClassVar[list[str]] = ["flow tracking"]
-    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show flow tracking hardware tracker {name}", revision=1)]
+    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show flow tracking hardware", revision=1)]
 
     class Input(AntaTest.Input):
         """Input model for the VerifyHardwareFlowTrackerStatus test."""
@@ -111,82 +100,42 @@ class VerifyHardwareFlowTrackerStatus(AntaTest):
         trackers: list[FlowTracker]
         """List of flow trackers to verify."""
 
-        class FlowTracker(BaseModel):
-            """Detail of a flow tracker."""
-
-            name: str
-            """Name of the flow tracker."""
-
-            record_export: RecordExport | None = None
-            """Record export configuration for the flow tracker."""
-
-            exporters: list[Exporter] | None = None
-            """List of exporters for the flow tracker."""
-
-            class RecordExport(BaseModel):
-                """Record export configuration."""
-
-                on_inactive_timeout: int
-                """Timeout in milliseconds for exporting records when inactive."""
-
-                on_interval: int
-                """Interval in milliseconds for exporting records."""
-
-            class Exporter(BaseModel):
-                """Detail of an exporter."""
-
-                name: str
-                """Name of the exporter."""
-
-                local_interface: str
-                """Local interface used by the exporter."""
-
-                template_interval: int
-                """Template interval in milliseconds for the exporter."""
-
-    def render(self, template: AntaTemplate) -> list[AntaCommand]:
-        """Render the template for each hardware tracker."""
-        return [template.render(name=tracker.name) for tracker in self.inputs.trackers]
-
     @skip_on_platforms(["cEOSLab", "vEOS-lab"])
     @AntaTest.anta_test
     def test(self) -> None:
         """Main test function for VerifyHardwareFlowTrackerStatus."""
         self.result.is_success()
-        for command, tracker_input in zip(self.instance_commands, self.inputs.trackers):
-            hardware_tracker_name = command.params.name
-            record_export = tracker_input.record_export.model_dump() if tracker_input.record_export else None
-            exporters = [exporter.model_dump() for exporter in tracker_input.exporters] if tracker_input.exporters else None
-            command_output = command.json_output
 
-            # Check if hardware flow tracking is configured
-            if not command_output.get("running"):
-                self.result.is_failure("Hardware flow tracking is not running.")
-                return
+        command_output = self.instance_commands[0].json_output
+        # Check if hardware flow tracking is configured
+        if not command_output.get("running"):
+            self.result.is_failure("Hardware flow tracking is not running.")
+            return
 
+        for tracker in self.inputs.trackers:
             # Check if the input hardware tracker is configured
-            tracker_info = command_output["trackers"].get(hardware_tracker_name)
-            if not tracker_info:
-                self.result.is_failure(f"Hardware flow tracker `{hardware_tracker_name}` is not configured.")
+            if not (tracker_info := get_value(command_output["trackers"], f"{tracker.name}")):
+                self.result.is_failure(f"{tracker} - Not found")
                 continue
 
             # Check if the input hardware tracker is active
             if not tracker_info.get("active"):
-                self.result.is_failure(f"Hardware flow tracker `{hardware_tracker_name}` is not active.")
+                self.result.is_failure(f"{tracker} - Disabled")
                 continue
 
             # Check the input hardware tracker timeouts
-            failure_msg = ""
-            if record_export:
-                record_export_failure = validate_record_export(record_export, tracker_info)
-                if record_export_failure:
-                    failure_msg += record_export_failure
-
-            # Check the input hardware tracker exporters' configuration
-            if exporters:
-                exporters_failure = validate_exporters(exporters, tracker_info)
-                if exporters_failure:
-                    failure_msg += exporters_failure
-
-            if failure_msg:
-                self.result.is_failure(f"{hardware_tracker_name}: {failure_msg}\n")
+            if tracker.record_export:
+                inactive_interval = tracker.record_export.on_inactive_timeout
+                on_interval = tracker.record_export.on_interval
+                act_inactive = tracker_info.get("inactiveTimeout")
+                act_interval = tracker_info.get("activeInterval")
+                if not all([inactive_interval == act_inactive, on_interval == act_interval]):
+                    self.result.is_failure(
+                        f"{tracker}, {tracker.record_export} - Incorrect timers - Inactive Timeout: {act_inactive}, OnActive Interval: {act_interval}"
+                    )
+
+            # Check the input hardware tracker exporters configuration
+            if tracker.exporters:
+                failure_messages = validate_exporters(tracker.exporters, tracker_info)
+                for message in failure_messages:
+                    self.result.is_failure(f"{tracker}, {message}")
diff --git a/docs/api/tests.flow_tracking.md b/docs/api/tests.flow_tracking.md
index e6e9df2d..786f56ee 100644
--- a/docs/api/tests.flow_tracking.md
+++ b/docs/api/tests.flow_tracking.md
@@ -7,6 +7,8 @@ anta_title: ANTA catalog for flow tracking tests
   ~ that can be found in the LICENSE file.
   -->
 
+# Tests
+
 ::: anta.tests.flow_tracking
     options:
       show_root_heading: false
@@ -18,3 +20,19 @@ anta_title: ANTA catalog for flow tracking tests
       filters:
         - "!test"
         - "!render"
+        - "!validate_exporters"
+
+# Input models
+
+::: anta.input_models.flow_tracking
+
+    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 6c64f5d9..b231c4b6 100644
--- a/examples/tests.yaml
+++ b/examples/tests.yaml
@@ -162,7 +162,7 @@ anta.tests.field_notices:
       # Verifies if the device is exposed to FN0072, and if the issue has been mitigated.
 anta.tests.flow_tracking:
   - VerifyHardwareFlowTrackerStatus:
-      # Verifies if hardware flow tracking is running and an input tracker is active. Optionally verifies the tracker interval/timeout and exporter configuration.
+      # Verifies the hardware flow tracking state.
       trackers:
         - name: FLOW-TRACKER
           record_export:
diff --git a/tests/units/anta_tests/test_flow_tracking.py b/tests/units/anta_tests/test_flow_tracking.py
index 19f4d325..6934c021 100644
--- a/tests/units/anta_tests/test_flow_tracking.py
+++ b/tests/units/anta_tests/test_flow_tracking.py
@@ -22,18 +22,13 @@ DATA: list[dict[str, Any]] = [
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER": {
                         "active": True,
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -52,18 +47,13 @@ DATA: list[dict[str, Any]] = [
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER": {
                         "active": True,
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -113,7 +103,7 @@ DATA: list[dict[str, Any]] = [
         "inputs": {"trackers": [{"name": "FLOW-Sample"}]},
         "expected": {
             "result": "failure",
-            "messages": ["Hardware flow tracker `FLOW-Sample` is not configured."],
+            "messages": ["Flow Tracker: FLOW-Sample - Not found"],
         },
     },
     {
@@ -127,18 +117,13 @@ DATA: list[dict[str, Any]] = [
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER": {
                         "active": False,
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -159,7 +144,7 @@ DATA: list[dict[str, Any]] = [
         },
         "expected": {
             "result": "failure",
-            "messages": ["Hardware flow tracker `FLOW-TRACKER` is not active.", "Hardware flow tracker `HARDWARE-TRACKER` is not active."],
+            "messages": ["Flow Tracker: FLOW-TRACKER - Disabled", "Flow Tracker: HARDWARE-TRACKER - Disabled"],
         },
     },
     {
@@ -173,18 +158,13 @@ DATA: list[dict[str, Any]] = [
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER": {
                         "active": True,
                         "inactiveTimeout": 6000,
                         "activeInterval": 30000,
                         "exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -204,10 +184,9 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "FLOW-TRACKER: \n"
-                "Expected `6000` as the inactive timeout, but found `60000` instead.\nExpected `30000` as the interval, but found `300000` instead.\n",
-                "HARDWARE-TRACKER: \n"
-                "Expected `60000` as the inactive timeout, but found `6000` instead.\nExpected `300000` as the interval, but found `30000` instead.\n",
+                "Flow Tracker: FLOW-TRACKER, Inactive Timeout: 6000, Active Interval: 30000 - Incorrect timers - Inactive Timeout: 60000, OnActive Interval: 300000",
+                "Flow Tracker: HARDWARE-TRACKER, Inactive Timeout: 60000, Active Interval: 300000 - Incorrect timers - "
+                "Inactive Timeout: 6000, OnActive Interval: 30000",
             ],
         },
     },
@@ -225,12 +204,7 @@ DATA: list[dict[str, Any]] = [
                             "CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000},
                             "CVP-FLOW": {"localIntf": "Loopback0", "templateInterval": 3600000},
                         },
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER": {
                         "active": True,
                         "inactiveTimeout": 6000,
@@ -239,7 +213,7 @@ DATA: list[dict[str, Any]] = [
                             "CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000},
                             "Hardware-flow": {"localIntf": "Loopback10", "templateInterval": 3600000},
                         },
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -265,15 +239,11 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "FLOW-TRACKER: \n"
-                "Exporter `CVP-FLOW`: \n"
-                "Expected `Loopback10` as the local interface, but found `Loopback0` instead.\n"
-                "Expected `3500000` as the template interval, but found `3600000` instead.\n",
-                "HARDWARE-TRACKER: \n"
-                "Exporter `Hardware-flow`: \n"
-                "Expected `Loopback99` as the local interface, but found `Loopback10` instead.\n"
-                "Expected `3000000` as the template interval, but found `3600000` instead.\n"
-                "Exporter `Reverse-flow` is not configured.\n",
+                "Flow Tracker: FLOW-TRACKER, Exporter: CVP-FLOW - Incorrect local interface - Expected: Loopback10, Actual: Loopback0",
+                "Flow Tracker: FLOW-TRACKER, Exporter: CVP-FLOW - Incorrect template interval - Expected: 3500000, Actual: 3600000",
+                "Flow Tracker: HARDWARE-TRACKER, Exporter: Hardware-flow - Incorrect local interface - Expected: Loopback99, Actual: Loopback10",
+                "Flow Tracker: HARDWARE-TRACKER, Exporter: Hardware-flow - Incorrect template interval - Expected: 3000000, Actual: 3600000",
+                "Flow Tracker: HARDWARE-TRACKER, Exporter: Reverse-flow - Not configured",
             ],
         },
     },
@@ -288,34 +258,19 @@ DATA: list[dict[str, Any]] = [
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "FLOW-TRIGGER": {
                         "active": False,
                         "inactiveTimeout": 60000,
                         "activeInterval": 300000,
                         "exporters": {"CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-FLOW": {
                         "active": True,
                         "inactiveTimeout": 6000,
                         "activeInterval": 30000,
                         "exporters": {"CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000}},
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "FLOW-TRACKER2": {
                         "active": True,
                         "inactiveTimeout": 60000,
@@ -324,12 +279,7 @@ DATA: list[dict[str, Any]] = [
                             "CV-TELEMETRY": {"localIntf": "Loopback0", "templateInterval": 3600000},
                             "CVP-FLOW": {"localIntf": "Loopback0", "templateInterval": 3600000},
                         },
-                    }
-                },
-                "running": True,
-            },
-            {
-                "trackers": {
+                    },
                     "HARDWARE-TRACKER2": {
                         "active": True,
                         "inactiveTimeout": 6000,
@@ -338,7 +288,7 @@ DATA: list[dict[str, Any]] = [
                             "CVP-TELEMETRY": {"localIntf": "Loopback10", "templateInterval": 3600000},
                             "Hardware-flow": {"localIntf": "Loopback10", "templateInterval": 3600000},
                         },
-                    }
+                    },
                 },
                 "running": True,
             },
@@ -374,17 +324,15 @@ DATA: list[dict[str, Any]] = [
         "expected": {
             "result": "failure",
             "messages": [
-                "Hardware flow tracker `FLOW-Sample` is not configured.",
-                "Hardware flow tracker `FLOW-TRIGGER` is not active.",
-                "HARDWARE-FLOW: \n"
-                "Expected `60000` as the inactive timeout, but found `6000` instead.\nExpected `300000` as the interval, but found `30000` instead.\n",
-                "FLOW-TRACKER2: \nExporter `CVP-FLOW`: \n"
-                "Expected `Loopback10` as the local interface, but found `Loopback0` instead.\n"
-                "Expected `3500000` as the template interval, but found `3600000` instead.\n",
-                "HARDWARE-TRACKER2: \nExporter `Hardware-flow`: \n"
-                "Expected `Loopback99` as the local interface, but found `Loopback10` instead.\n"
-                "Expected `3000000` as the template interval, but found `3600000` instead.\n"
-                "Exporter `Reverse-flow` is not configured.\n",
+                "Flow Tracker: FLOW-Sample - Not found",
+                "Flow Tracker: FLOW-TRIGGER - Disabled",
+                "Flow Tracker: HARDWARE-FLOW, Inactive Timeout: 60000, Active Interval: 300000 - Incorrect timers - "
+                "Inactive Timeout: 6000, OnActive Interval: 30000",
+                "Flow Tracker: FLOW-TRACKER2, Exporter: CVP-FLOW - Incorrect local interface - Expected: Loopback10, Actual: Loopback0",
+                "Flow Tracker: FLOW-TRACKER2, Exporter: CVP-FLOW - Incorrect template interval - Expected: 3500000, Actual: 3600000",
+                "Flow Tracker: HARDWARE-TRACKER2, Exporter: Hardware-flow - Incorrect local interface - Expected: Loopback99, Actual: Loopback10",
+                "Flow Tracker: HARDWARE-TRACKER2, Exporter: Hardware-flow - Incorrect template interval - Expected: 3000000, Actual: 3600000",
+                "Flow Tracker: HARDWARE-TRACKER2, Exporter: Reverse-flow - Not configured",
             ],
         },
     },