8000 refactor(anta.tests): Nicer result failure messages PTP, software test module by geetanjalimanegslab · Pull Request #1038 · aristanetworks/anta · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

refactor(anta.tests): Nicer result failure messages PTP, software test module #1038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 12 additions & 19 deletions anta/tests/ptp.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


class VerifyPtpModeStatus(AntaTest):
"""Verifies that the device is configured as a Precision Time Protocol (PTP) Boundary Clock (BC).
"""Verifies that the device is configured as a PTP Boundary Clock.

Expected Results
----------------
Expand All @@ -33,7 +33,6 @@ class VerifyPtpModeStatus(AntaTest):
```
"""

description = "Verifies that the device is configured as a PTP Boundary Clock."
categories: ClassVar[list[str]] = ["ptp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ptp", revision=2)]

Expand All @@ -48,13 +47,13 @@ def test(self) -> None:
return

if ptp_mode != "ptpBoundaryClock":
self.result.is_failure(f"The device is not configured as a PTP Boundary Clock: '{ptp_mode}'")
self.result.is_failure(f"Not configured as a PTP Boundary Clock - Actual: {ptp_mode}")
else:
self.result.is_success()


class VerifyPtpGMStatus(AntaTest):
"""Verifies that the device is locked to a valid Precision Time Protocol (PTP) Grandmaster (GM).
"""Verifies that the device is locked to a valid PTP Grandmaster.

To test PTP failover, re-run the test with a secondary GMID configured.

Expand All @@ -79,7 +78,6 @@ class Input(AntaTest.Input):
gmid: str
"""Identifier of the Grandmaster to which the device should be locked."""

description = "Verifies that the device is locked to a valid PTP Grandmaster."
categories: ClassVar[list[str]] = ["ptp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ptp", revision=2)]

Expand All @@ -102,7 +100,7 @@ def test(self) -> None:


class VerifyPtpLockStatus(AntaTest):
"""Verifies that the device was locked to the upstream Precision Time Protocol (PTP) Grandmaster (GM) in the last minute.
"""Verifies that the device was locked to the upstream PTP GM in the last minute.

Expected Results
----------------
Expand All @@ -118,7 +116,6 @@ class VerifyPtpLockStatus(AntaTest):
```
"""

description = "Verifies that the device was locked to the upstream PTP GM in the last minute."
categories: ClassVar[list[str]] = ["ptp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ptp", revision=2)]

Expand All @@ -136,13 +133,13 @@ def test(self) -> None:
time_difference = ptp_clock_summary["currentPtpSystemTime"] - ptp_clock_summary["lastSyncTime"]

if time_difference >= threshold:
self.result.is_failure(f"The device lock is more than {threshold}s old: {time_difference}s")
self.result.is_failure(f"Lock is more than {threshold}s old - Actual: {time_difference}s")
else:
self.result.is_success()


class VerifyPtpOffset(AntaTest):
"""Verifies that the Precision Time Protocol (PTP) timing offset is within +/- 1000ns from the master clock.
"""Verifies that the PTP timing offset is within +/- 1000ns from the master clock.

Expected Results
----------------
Expand All @@ -158,7 +155,6 @@ class VerifyPtpOffset(AntaTest):
```
"""

description = "Verifies that the PTP timing offset is within +/- 1000ns from the master clock."
categories: ClassVar[list[str]] = ["ptp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ptp monitor", revision=1)]

Expand All @@ -167,9 +163,9 @@ class VerifyPtpOffset(AntaTest):
def test(self) -> None:
"""Main test function for VerifyPtpOffset."""
threshold = 1000
offset_interfaces: dict[str, list[int]] = {}
self.result.is_success()
command_output = self.instance_commands[0].json_output

offset_interfaces: dict[str, list[int]] = {}
if not command_output["ptpMonitorData"]:
self.result.is_skipped("PTP is not configured")
return
Expand All @@ -178,14 +174,12 @@ def test(self) -> None:
if abs(interface["offsetFromMaster"]) > threshold:
offset_interfaces.setdefault(interface["intf"], []).append(interface["offsetFromMaster"])

if offset_interfaces:
self.result.is_failure(f"The device timing offset from master is greater than +/- {threshold}ns: {offset_interfaces}")
else:
self.result.is_success()
for interface, data in offset_interfaces.items():
self.result.is_failure(f"Interface: {interface} - Timing offset from master is greater than +/- {threshold}ns: Actual: {', '.join(map(str, data))}")


class VerifyPtpPortModeStatus(AntaTest):
"""Verifies that all interfaces are in a valid Precision Time Protocol (PTP) state.
"""Verifies the PTP interfaces state.

The interfaces can be in one of the following state: Master, Slave, Passive, or Disabled.

Expand All @@ -202,7 +196,6 @@ class VerifyPtpPortModeStatus(AntaTest):
```
"""

description = "Verifies the PTP interfaces state."
categories: ClassVar[list[str]] = ["ptp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ptp", revision=2)]

Expand All @@ -227,4 +220,4 @@ def test(self) -> None:
if not invalid_interfaces:
self.result.is_success()
else:
self.result.is_failure(f"The following interface(s) are not in a valid PTP state: '{invalid_interfaces}'")
self.result.is_failure(f"The following interface(s) are not in a valid PTP state: {', '.join(invalid_interfaces)}")
29 changes: 13 additions & 16 deletions anta/tests/software.py
10000
Original file line numberDiff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


class VerifyEOSVersion(AntaTest):
"""Verifies that the device is running one of the allowed EOS version.
"""Verifies the EOS version of the device.

Expected Results
----------------
Expand All @@ -34,7 +34,6 @@ class VerifyEOSVersion(AntaTest):
```
"""

description = "Verifies the EOS version of the device."
categories: ClassVar[list[str]] = ["software"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show version", revision=1)]

Expand All @@ -48,14 +47,13 @@ class Input(AntaTest.Input):
def test(self) -> None:
"""Main test function for VerifyEOSVersion."""
command_output = self.instance_commands[0].json_output
if command_output["version"] in self.inputs.versions:
self.result.is_success()
else:
self.result.is_failure(f'device is running version "{command_output["version"]}" not in expected versions: {self.inputs.versions}')
self.result.is_success()
if command_output["version"] not in self.inputs.versions:
self.result.is_failure(f"EOS version mismatch - Actual: {command_output['version']} not in Expected: {', '.join(self.inputs.versions)}")


class VerifyTerminAttrVersion(AntaTest):
"""Verifies that he device is running one of the allowed TerminAttr version.
"""Verifies the TerminAttr version of the device.

Expected Results
----------------
Expand All @@ -73,7 +71,6 @@ class VerifyTerminAttrVersion(AntaTest):
```
"""

description = "Verifies the TerminAttr version of the device."
categories: ClassVar[list[str]] = ["software"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show version detail", revision=1)]

Expand All @@ -87,11 +84,10 @@ class Input(AntaTest.Input):
def test(self) -> None:
"""Main test function for VerifyTerminAttrVersion."""
command_output = self.instance_commands[0].json_output
self.result.is_success()
command_output_data = command_output["details"]["packages"]["TerminAttr-core"]["version"]
if command_output_data in self.inputs.versions:
self.result.is_success()
else:
self.result.is_failure(f"device is running TerminAttr version {command_output_data} and is not in the allowed list: {self.inputs.versions}")
if command_output_data not in self.inputs.versions:
self.result.is_failure(f"TerminAttr version mismatch - Actual: {command_output_data} not in Expected: {', '.join(self.inputs.versions)}")


class VerifyEOSExtensions(AntaTest):
Expand Down Expand Up @@ -120,6 +116,7 @@ class VerifyEOSExtensions(AntaTest):
def test(self) -> None:
"""Main test function for VerifyEOSExtensions."""
boot_extensions = []
self.result.is_success()
show_extensions_command_output = self.instance_commands[0].json_output
show_boot_extensions_command_output = self.instance_commands[1].json_output
installed_extensions = [
Expand All @@ -131,7 +128,7 @@ def test(self) -> None:
boot_extensions.append(formatted_extension)
installed_extensions.sort()
boot_extensions.sort()
if installed_extensions == boot_extensions:
self.result.is_success()
else:
self.result.is_failure(f"Missing EOS extensions: installed {installed_extensions} / configured: {boot_extensions}")
if installed_extensions != boot_extensions:
str_installed_extensions = ", ".join(installed_extensions) if installed_extensions else "Not found"
str_boot_extensions = ", ".join(boot_extensions) if boot_extensions else "Not found"
self.result.is_failure(f"EOS extensions mismatch - Installed: {str_installed_extensions}, Configured: {str_boot_extensions}")
10 changes: 6 additions & 4 deletions tests/units/anta_tests/test_ptp.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"test": VerifyPtpModeStatus,
"eos_data": [{"ptpMode": "ptpDisabled", "ptpIntfSummaries": {}}],
"inputs": None,
"expected": {"result": "failure", "messages": ["The device is not configured as a PTP Boundary Clock: 'ptpDisabled'"]},
"expected": {"result": "failure", "messages": ["Not configured as a PTP Boundary Clock - Actual: ptpDisabled"]},
},
{
"name": "skipped",
Expand Down Expand Up @@ -158,7 +158,7 @@
}
],
"inputs": None,
"expected": {"result": "failure", "messages": ["The device lock is more than 60s old: 157s"]},
"expected": {"result": "failure", "messages": ["Lock is more than 60s old - Actual: 157s"]},
},
{
"name": "skipped",
Expand Down Expand Up @@ -236,7 +236,9 @@
"inputs": None,
"expected": {
"result": "failure",
"messages": [("The device timing offset from master is greater than +/- 1000ns: {'Ethernet27/1': [1200, -1300]}")],
"messages": [
"Interface: Ethernet27/1 - Timing offset from master is greater than +/- 1000ns: Actual: 1200, -1300",
],
},
},
{
Expand Down Expand Up @@ -335,6 +337,6 @@
}
],
"inputs": None,
"expected": {"result": "failure", "messages": ["The following interface(s) are not in a valid PTP state: '['Ethernet53', 'Ethernet1']'"]},
"expected": {"result": "failure", "messages": ["The following interface(s) are not in a valid PTP state: Ethernet53, Ethernet1"]},
},
]
106 changes: 97 additions & 9 deletions tests/units/anta_tests/test_software.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
},
],
"inputs": {"versions": ["4.27.1F"]},
"expected": {"result": "failure", "messages": ["device is running version \"4.27.0F\" not in expected versions: ['4.27.1F']"]},
"expected": {"result": "failure", "messages": ["EOS version mismatch - Actual: 4.27.0F not in Expected: 4.27.1F"]},
},
{
"name": "success",
Expand Down Expand Up @@ -77,9 +77,8 @@
},
],
"inputs": {"versions": ["v1.17.1", "v1.18.1"]},
"expected": {"result": "failure", "messages": ["device is running TerminAttr version v1.17.0 and is not in the allowed list: ['v1.17.1', 'v1.18.1']"]},
"expected": {"result": "failure", "messages": ["TerminAttr version mismatch - Actual: v1.17.0 not in Expected: v1.17.1, v1.18.1"]},
},
# TODO: add a test with a real extension?
{
"name": "success-no-extensions",
"test": VerifyEOSExtensions,
Expand All @@ -91,11 +90,30 @@
"expected": {"result": "success"},
},
{
"name": "success-empty-extension",
"name": "success-extensions",
"test": VerifyEOSExtensions,
"eos_data": [
{"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]},
{"extensions": [""]},
{
"extensions": {
"AristaCloudGateway-1.0.1-1.swix": {
"version": "1.0.1",
"release": "1",
"presence": "present",
"status": "installed",
"boot": True,
"numPackages": 1,
"error": False,
"vendor": "",
"summary": "Arista Cloud Connect",
"installedSize": 60532424,
"packages": {"AristaCloudGateway-1.0.1-1.x86_64.rpm": {"version": "1.0.1", "release": "1"}},
"description": "An extension for Arista Cloud Connect gateway",
"affectedAgents": [],
"agentsToRestart": [],
},
}
},
{"extensions": ["AristaCloudGateway-1.0.1-1.swix"]},
],
"inputs": None,
"expected": {"result": "success"},
Expand All @@ -104,10 +122,80 @@
"name": "failure",
"test": VerifyEOSExtensions,
"eos_data": [
{"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]},
{"extensions": ["dummy"]},
{
"extensions": {
"AristaCloudGateway-1.0.1-1.swix": {
"version": "1.0.1",
"release": "1",
"presence": "present",
"status": "installed",
"boot": False,
"numPackages": 1,
"error": False,
"vendor": "",
"summary": "Arista Cloud Connect",
"installedSize": 60532424,
"packages": {"AristaCloudGateway-1.0.1-1.x86_64.rpm": {"version": "1.0.1", "release": "1"}},
"description": "An extension for Arista Cloud Connect gateway",
"affectedAgents": [],
"agentsToRestart": [],
},
}
},
{"extensions": []},
],
"inputs": None,
"expected": {"result": "failure", "messages": ["EOS extensions mismatch - Installed: AristaCloudGateway-1.0.1-1.swix, Configured: Not found"]},
},
{
"name": "failure-multiple-extensions",
"test": VerifyEOSExtensions,
"eos_data": [
{
"extensions": {
"AristaCloudGateway-1.0.1-1.swix": {
"version": "1.0.1",
"release": "1",
"presence": "present",
"status": "installed",
"boot": False,
"numPackages": 1,
"error": False,
"vendor": "",
"summary": "Arista Cloud Connect",
"installedSize": 60532424,
"packages": {"AristaCloudGateway-1.0.1-1.x86_64.rpm": {"version": "1.0.1", "release": "1"}},
"description": "An extension for Arista Cloud Connect gateway",
"affectedAgents": [],
"agentsToRestart": [],
},
"EOS-4.33.0F-NDRSensor.swix": {
"version": "4.33.0",
"release": "39050855.4330F",
"presence": "present",
"status": "notInstalled",
"boot": True,
"numPackages": 9,
"error": False,
"statusDetail": "No RPMs are compatible with current EOS version.",
"vendor": "",
"summary": "NDR sensor",
"installedSize": 0,
"packages": {},
"description": "NDR sensor provides libraries to generate flow activity records using DPI\nmetadata and IPFIX flow records.",
"affectedAgents": [],
"agentsToRestart": [],
},
}
},
{"extensions": ["AristaCloudGateway-1.0.1-1.swix", "EOS-4.33.0F-NDRSensor.swix"]},
],
"inputs": None,
"expected": {"result": "failure", "messages": ["Missing EOS extensions: installed [] / configured: ['dummy']"]},
"expected": {
"result": "failure",
"messages": [
"EOS extensions mismatch - Installed: AristaCloudGateway-1.0.1-1.swix, Configured: AristaCloudGateway-1.0.1-1.swix, EOS-4.33.0F-NDRSensor.swix"
],
},
},
]
Loading
0