Skip to content

Commit 461fa69

Browse files
vitthalmagadumgmulocpre-commit-ci[bot]
authored
fix(anta.tests): Cleaning up flow-tracking tests module (#964)
* Refactored VerifyHardwareFlowTrackerStatus test * addressed review comments: updated failure msga, test doc * reverted the latest revision * Addressed review comments: updated docstring * Update anta/tests/flow_tracking.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Apply suggestions from code review --------- Co-authored-by: Guillaume Mulocher <gmulocher@arista.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent e09488b commit 461fa69

File tree

5 files changed

+185
-198
lines changed

5 files changed

+185
-198
lines changed

anta/input_models/flow_tracking.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright (c) 2023-2025 Arista Networks, Inc.
2+
# Use of this source code is governed by the Apache License 2.0
3+
# that can be found in the LICENSE file.
4+
"""Module containing input models for flow tracking tests."""
5+
6+
from __future__ import annotations
7+
8+
from pydantic import BaseModel, ConfigDict
9+
10+
11+
class FlowTracker(BaseModel):
12+
"""Flow Tracking model representing the tracker details."""
13+
14+
model_config = ConfigDict(extra="forbid")
15+
name: str
16+
"""The name of the flow tracker."""
17+
record_export: RecordExport | None = None
18+
"""Configuration for record export, specifying details about timeouts."""
19+
exporters: list[Exporter] | None = None
20+
"""A list of exporters associated with the flow tracker."""
21+
22+
def __str__(self) -> str:
23+
"""Return a human-readable string representation of the FlowTracker for reporting.
24+
25+
Examples
26+
--------
27+
Flow Tracker: FLOW-TRACKER
28+
29+
"""
30+
return f"Flow Tracker: {self.name}"
31+
32+
33+
class RecordExport(BaseModel):
34+
"""Model representing the record export configuration for a flow tracker."""
35+
36+
model_config = ConfigDict(extra="forbid")
37+
on_inactive_timeout: int
38+
"""The timeout in milliseconds for exporting flow records when the flow becomes inactive."""
39+
on_interval: int
40+
"""The interval in milliseconds for exporting flow records."""
41+
42+
def __str__(self) -> str:
43+
"""Return a human-readable string representation of the RecordExport for reporting.
44+
45+
Examples
46+
--------
47+
Inactive Timeout: 60000, Active Interval: 300000
48+
49+
"""
50+
return f"Inactive Timeout: {self.on_inactive_timeout}, Active Interval: {self.on_interval}"
51+
52+
53+
class Exporter(BaseModel):
54+
"""Model representing the exporter used for flow record export."""
55+
56+
model_config = ConfigDict(extra="forbid")
57+
name: str
58+
"""The name of the exporter."""
59+
local_interface: str
60+
"""The local interface used by the exporter to send flow records."""
61+
template_interval: int
62+
"""The template interval, in milliseconds, for the exporter to refresh the flow template."""
63+
64+
def __str__(self) -> str:
65+
"""Return a human-readable string representation of the Exporter for reporting.
66+
67+
Examples
68+
--------
69+
Exporter: CVP-TELEMETRY
70+
71+
"""
72+
return f"Exporter: {self.name}"

anta/tests/flow_tracking.py

Lines changed: 60 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,13 @@
99

1010
from typing import ClassVar
1111

12-
from pydantic import BaseModel
13-
1412
from anta.decorators import skip_on_platforms
13+
from anta.input_models.flow_tracking import FlowTracker
1514
from anta.models import AntaCommand, AntaTemplate, AntaTest
16-
from anta.tools import get_failed_logs
17-
15+
from anta.tools import get_value
1816

19-
def validate_record_export(record_export: dict[str, str], tracker_info: dict[str, str]) -> str:
20-
"""Validate the record export configuration against the tracker info.
21-
22-
Parameters
23-
----------
24-
record_export
25-
The expected record export configuration.
26-
tracker_info
27-
The actual tracker info from the command output.
2817

29-
Returns
30-
-------
31-
str
32-
A failure message if the record export configuration does not match, otherwise blank string.
33-
"""
34-
failed_log = ""
35-
actual_export = {"inactive timeout": tracker_info.get("inactiveTimeout"), "interval": tracker_info.get("activeInterval")}
36-
expected_export = {"inactive timeout": record_export.get("on_inactive_timeout"), "interval": record_export.get("on_interval")}
37-
if actual_export != expected_export:
38-
failed_log = get_failed_logs(expected_export, actual_export)
39-
return failed_log
40-
41-
42-
def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str, str]) -> str:
18+
def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str, str]) -> list[str]:
4319
"""Validate the exporter configurations against the tracker info.
4420
4521
Parameters
@@ -51,36 +27,52 @@ def validate_exporters(exporters: list[dict[str, str]], tracker_info: dict[str,
5127
5228
Returns
5329
-------
54-
str
55-
Failure message if any exporter configuration does not match.
30+
list
31+
List of failure messages for any exporter configuration that does not match.
5632
"""
57-
failed_log = ""
33+
failure_messages = []
5834
for exporter in exporters:
59-
exporter_name = exporter["name"]
35+
exporter_name = exporter.name
6036
actual_exporter_info = tracker_info["exporters"].get(exporter_name)
6137
if not actual_exporter_info:
62-
failed_log += f"\nExporter `{exporter_name}` is not configured."
38+
failure_messages.append(f"{exporter} - Not configured")
6339
continue
40+
local_interface = actual_exporter_info["localIntf"]
41+
template_interval = actual_exporter_info["templateInterval"]
6442

65-
expected_exporter_data = {"local interface": exporter["local_interface"], "template interval": exporter["template_interval"]}
66-
actual_exporter_data = {"local interface": actual_exporter_info["localIntf"], "template interval": actual_exporter_info["templateInterval"]}
43+
if local_interface != exporter.local_interface:
44+
failure_messages.append(f"{exporter} - Incorrect local interface - Expected: {exporter.local_interface}, Actual: {local_interface}")
6745

68-
if expected_exporter_data != actual_exporter_data:
69-
failed_msg = get_failed_logs(expected_exporter_data, actual_exporter_data)
70-
failed_log += f"\nExporter `{exporter_name}`: {failed_msg}"
71-
return failed_log
46+
if template_interval != exporter.template_interval:
47+
failure_messages.append(f"{exporter} - Incorrect template interval - Expected: {exporter.template_interval}, Actual: {template_interval}")
48+
return failure_messages
7249

7350

7451
class VerifyHardwareFlowTrackerStatus(AntaTest):
75-
"""Verifies if hardware flow tracking is running and an input tracker is active.
52+
"""Verifies the hardware flow tracking state.
53+
54+
This test performs the following checks:
7655
77-
This test optionally verifies the tracker interval/timeout and exporter configuration.
56+
1. Confirms that hardware flow tracking is running.
57+
2. For each specified flow tracker:
58+
- Confirms that the tracker is active.
59+
- Optionally, checks the tracker interval/timeout configuration.
60+
- Optionally, verifies the tracker exporter configuration
7861
7962
Expected Results
8063
----------------
81-
* Success: The test will pass if hardware flow tracking is running and an input tracker is active.
82-
* Failure: The test will fail if hardware flow tracking is not running, an input tracker is not active,
83-
or the tracker interval/timeout and exporter configuration does not match the expected values.
64+
* Success: The test will pass if all of the following conditions are met:
65+
- Hardware flow tracking is running.
66+
- For each specified flow tracker:
67+
- The flow tracker is active.
68+
- The tracker interval/timeout matches the expected values, if provided.
69+
- The exporter configuration matches the expected values, if provided.
70+
* Failure: The test will fail if any of the following conditions are met:
71+
- Hardware flow tracking is not running.
72+
- For any specified flow tracker:
73+
- The flow tracker is not active.
74+
- The tracker interval/timeout does not match the expected values, if provided.
75+
- The exporter configuration does not match the expected values, if provided.
8476
8577
Examples
8678
--------
@@ -99,94 +91,51 @@ class VerifyHardwareFlowTrackerStatus(AntaTest):
9991
```
10092
"""
10193

102-
description = (
103-
"Verifies if hardware flow tracking is running and an input tracker is active. Optionally verifies the tracker interval/timeout and exporter configuration."
104-
)
10594
categories: ClassVar[list[str]] = ["flow tracking"]
106-
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show flow tracking hardware tracker {name}", revision=1)]
95+
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show flow tracking hardware", revision=1)]
10796

10897
class Input(AntaTest.Input):
10998
"""Input model for the VerifyHardwareFlowTrackerStatus test."""
11099

111100
trackers: list[FlowTracker]
112101
"""List of flow trackers to verify."""
113102

114-
class FlowTracker(BaseModel):
115-
"""Detail of a flow tracker."""
116-
117-
name: str
118-
"""Name of the flow tracker."""
119-
120-
record_export: RecordExport | None = None
121-
"""Record export configuration for the flow tracker."""
122-
123-
exporters: list[Exporter] | None = None
124-
"""List of exporters for the flow tracker."""
125-
126-
class RecordExport(BaseModel):
127-
"""Record export configuration."""
128-
129-
on_inactive_timeout: int
130-
"""Timeout in milliseconds for exporting records when inactive."""
131-
132-
on_interval: int
133-
"""Interval in milliseconds for exporting records."""
134-
135-
class Exporter(BaseModel):
136-
"""Detail of an exporter."""
137-
138-
name: str
139-
"""Name of the exporter."""
140-
141-
local_interface: str
142-
"""Local interface used by the exporter."""
143-
144-
template_interval: int
145-
"""Template interval in milliseconds for the exporter."""
146-
147-
def render(self, template: AntaTemplate) -> list[AntaCommand]:
148-
"""Render the template for each hardware tracker."""
149-
return [template.render(name=tracker.name) for tracker in self.inputs.trackers]
150-
151103
@skip_on_platforms(["cEOSLab", "vEOS-lab"])
152104
@AntaTest.anta_test
153105
def test(self) -> None:
154106
"""Main test function for VerifyHardwareFlowTrackerStatus."""
155107
self.result.is_success()
156-
for command, tracker_input in zip(self.instance_commands, self.inputs.trackers):
157-
hardware_tracker_name = command.params.name
158-
record_export = tracker_input.record_export.model_dump() if tracker_input.record_export else None
159-
exporters = [exporter.model_dump() for exporter in tracker_input.exporters] if tracker_input.exporters else None
160-
command_output = command.json_output
161108

162-
# Check if hardware flow tracking is configured
163-
if not command_output.get("running"):
164-
self.result.is_failure("Hardware flow tracking is not running.")
165-
return
109+
command_output = self.instance_commands[0].json_output
110+
# Check if hardware flow tracking is configured
111+
if not command_output.get("running"):
112+
self.result.is_failure("Hardware flow tracking is not running.")
113+
return
166114

115+
for tracker in self.inputs.trackers:
167116
# Check if the input hardware tracker is configured
168-
tracker_info = command_output["trackers"].get(hardware_tracker_name)
169-
if not tracker_info:
170-
self.result.is_failure(f"Hardware flow tracker `{hardware_tracker_name}` is not configured.")
117+
if not (tracker_info := get_value(command_output["trackers"], f"{tracker.name}")):
118+
self.result.is_failure(f"{tracker} - Not found")
171119
continue
172120

173121
# Check if the input hardware tracker is active
174122
if not tracker_info.get("active"):
175-
self.result.is_failure(f"Hardware flow tracker `{hardware_tracker_name}` is not active.")
123+
self.result.is_failure(f"{tracker} - Disabled")
176124
continue
177125

178126
# Check the input hardware tracker timeouts
179-
failure_msg = ""
180-
if record_export:
181-
record_export_failure = validate_record_export(record_export, tracker_info)
182-
if record_export_failure:
183-
failure_msg += record_export_failure
184-
185-
# Check the input hardware tracker exporters' configuration
186-
if exporters:
187-
exporters_failure = validate_exporters(exporters, tracker_info)
188-
if exporters_failure:
189-
failure_msg += exporters_failure
190-
191-
if failure_msg:
192-
self.result.is_failure(f"{hardware_tracker_name}: {failure_msg}\n")
127+
if tracker.record_export:
128+
inactive_interval = tracker.record_export.on_inactive_timeout
129+
on_interval = tracker.record_export.on_interval
130+
act_inactive = tracker_info.get("inactiveTimeout")
131+
act_interval = tracker_info.get("activeInterval")
132+
if not all([inactive_interval == act_inactive, on_interval == act_interval]):
133+
self.result.is_failure(
134+
f"{tracker}, {tracker.record_export} - Incorrect timers - Inactive Timeout: {act_inactive}, OnActive Interval: {act_interval}"
135+
)
136+
137+
# Check the input hardware tracker exporters configuration
138+
if tracker.exporters:
139+
failure_messages = validate_exporters(tracker.exporters, tracker_info)
140+
for message in failure_messages:
141+
self.result.is_failure(f"{tracker}, {message}")

docs/api/tests.flow_tracking.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ anta_title: ANTA catalog for flow tracking tests
77
~ that can be found in the LICENSE file.
88
-->
99

10+
# Tests
11+
1012
::: anta.tests.flow_tracking
1113
options:
1214
show_root_heading: false
@@ -18,3 +20,19 @@ anta_title: ANTA catalog for flow tracking tests
1820
filters:
1921
- "!test"
2022
- "!render"
23+
- "!validate_exporters"
24+
25+
# Input models
26+
27+
::: anta.input_models.flow_tracking
28+
29+
options:
30+
show_root_heading: false
31+
show_root_toc_entry: false
32+
show_bases: false
33+
anta_hide_test_module_description: true
34+
merge_init_into_class: false
35+
show_labels: true
36+
filters:
37+
- "!^__init__"
38+
- "!^__str__"

examples/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ anta.tests.field_notices:
162162
# Verifies if the device is exposed to FN0072, and if the issue has been mitigated.
163163
anta.tests.flow_tracking:
164164
- VerifyHardwareFlowTrackerStatus:
165-
# Verifies if hardware flow tracking is running and an input tracker is active. Optionally verifies the tracker interval/timeout and exporter configuration.
165+
# Verifies the hardware flow tracking state.
166166
trackers:
167167
- name: FLOW-TRACKER
168168
record_export:

0 commit comments

Comments
 (0)