Skip to content

Commit

Permalink
refactor(anta.tests): Nicer result failure messages MLAG test module (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vitthalmagadum authored Feb 25, 2025
1 parent 202f614 commit 9ba0284
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 79 deletions.
116 changes: 71 additions & 45 deletions anta/tests/mlag.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ class VerifyMlagStatus(AntaTest):
Expected Results
----------------
* Success: The test will pass if the MLAG state is 'active', negotiation status is 'connected',
peer-link status and local interface status are 'up'.
* Failure: The test will fail if the MLAG state is not 'active', negotiation status is not 'connected',
peer-link status or local interface status are not 'up'.
* Success: The test will pass if the MLAG state is 'active', negotiation status is 'connected', peer-link status and local interface status are 'up'.
* Failure: The test will fail if the MLAG state is not 'active', negotiation status is not 'connected', peer-link status or local interface status are not 'up'.
* Skipped: The test will be skipped if MLAG is 'disabled'.
Examples
Expand All @@ -42,21 +40,25 @@ class VerifyMlagStatus(AntaTest):
@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMlagStatus."""
self.result.is_success()
command_output = self.instance_commands[0].json_output

# Skipping the test if MLAG is disabled
if command_output["state"] == "disabled":
self.result.is_skipped("MLAG is disabled")
return
keys_to_verify = ["state", "negStatus", "localIntfStatus", "peerLinkStatus"]
verified_output = {key: get_value(command_output, key) for key in keys_to_verify}
if (
verified_output["state"] == "active"
and verified_output["negStatus"] == "connected"
and verified_output["localIntfStatus"] == "up"
and verified_output["peerLinkStatus"] == "up"
):
self.result.is_success()
else:
self.result.is_failure(f"MLAG status is not OK: {verified_output}")

# Verifies the negotiation status
if (neg_status := command_output["negStatus"]) != "connected":
self.result.is_failure(f"MLAG negotiation status mismatch - Expected: connected Actual: {neg_status}")

# Verifies the local interface interface status
if (intf_state := command_output["localIntfStatus"]) != "up":
self.result.is_failure(f"Operational state of the MLAG local interface is not correct - Expected: up Actual: {intf_state}")

# Verifies the peerLinkStatus
if (peer_link_state := command_output["peerLinkStatus"]) != "up":
self.result.is_failure(f"Operational state of the MLAG peer link is not correct - Expected: up Actual: {peer_link_state}")


class VerifyMlagInterfaces(AntaTest):
Expand All @@ -82,14 +84,19 @@ class VerifyMlagInterfaces(AntaTest):
@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMlagInterfaces."""
self.result.is_success()
command_output = self.instance_commands[0].json_output

# Skipping the test if MLAG is disabled
if command_output["state"] == "disabled":
self.result.is_skipped("MLAG is disabled")
return
if command_output["mlagPorts"]["Inactive"] == 0 and command_output["mlagPorts"]["Active-partial"] == 0:
self.result.is_success()
else:
self.result.is_failure(f"MLAG status is not OK: {command_output['mlagPorts']}")

# Verifies the Inactive and Active-partial ports
inactive_ports = command_output["mlagPorts"]["Inactive"]
partial_active_ports = command_output["mlagPorts"]["Active-partial"]
if inactive_ports != 0 or partial_active_ports != 0:
self.result.is_failure(f"MLAG status is not ok - Inactive Ports: {inactive_ports} Partial Active Ports: {partial_active_ports}")


class VerifyMlagConfigSanity(AntaTest):
Expand All @@ -116,16 +123,21 @@ class VerifyMlagConfigSanity(AntaTest):
@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMlagConfigSanity."""
self.result.is_success()
command_output = self.instance_commands[0].json_output

# Skipping the test if MLAG is disabled
if command_output["mlagActive"] is False:
self.result.is_skipped("MLAG is disabled")
return
keys_to_verify = ["globalConfiguration", "interfaceConfiguration"]
verified_output = {key: get_value(command_output, key) for key in keys_to_verify}
if not any(verified_output.values()):
self.result.is_success()
else:
self.result.is_failure(f"MLAG config-sanity returned inconsistencies: {verified_output}")

# Verifies the globalConfiguration config-sanity
if get_value(command_output, "globalConfiguration"):
self.result.is_failure("MLAG config-sanity found in global configuration")

# Verifies the interfaceConfiguration config-sanity
if get_value(command_output, "interfaceConfiguration"):
self.result.is_failure("MLAG config-sanity found in interface configuration")


class VerifyMlagReloadDelay(AntaTest):
Expand Down Expand Up @@ -161,17 +173,21 @@ class Input(AntaTest.Input):
@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMlagReloadDelay."""
self.result.is_success()
command_output = self.instance_commands[0].json_output

# Skipping the test if MLAG is disabled
if command_output["state"] == "disabled":
self.result.is_skipped("MLAG is disabled")
return
keys_to_verify = ["reloadDelay", "reloadDelayNonMlag"]
verified_output = {key: get_value(command_output, key) for key in keys_to_verify}
if verified_output["reloadDelay"] == self.inputs.reload_delay and verified_output["reloadDelayNonMlag"] == self.inputs.reload_delay_non_mlag:
self.result.is_success()

else:
self.result.is_failure(f"The reload-delay parameters are not configured properly: {verified_output}")
# Verifies the reloadDelay
if (reload_delay := get_value(command_output, "reloadDelay")) != self.inputs.reload_delay:
self.result.is_failure(f"MLAG reload-delay mismatch - Expected: {self.inputs.reload_delay}s Actual: {reload_delay}s")

# Verifies the reloadDelayNonMlag
if (non_mlag_reload_delay := get_value(command_output, "reloadDelayNonMlag")) != self.inputs.reload_delay_non_mlag:
self.result.is_failure(f"Delay for non-MLAG ports mismatch - Expected: {self.inputs.reload_delay_non_mlag}s Actual: {non_mlag_reload_delay}s")


class VerifyMlagDualPrimary(AntaTest):
Expand Down Expand Up @@ -214,25 +230,37 @@ class Input(AntaTest.Input):
@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMlagDualPrimary."""
self.result.is_success()
errdisabled_action = "errdisableAllInterfaces" if self.inputs.errdisabled else "none"
command_output = self.instance_commands[0].json_output

# Skipping the test if MLAG is disabled
if command_output["state"] == "disabled":
self.result.is_skipped("MLAG is disabled")
return

# Verifies the dualPrimaryDetectionState
if command_output["dualPrimaryDetectionState"] == "disabled":
self.result.is_failure("Dual-primary detection is disabled")
return
keys_to_verify = ["detail.dualPrimaryDetectionDelay", "detail.dualPrimaryAction", "dualPrimaryMlagRecoveryDelay", "dualPrimaryNonMlagRecoveryDelay"]
verified_output = {key: get_value(command_output, key) for key in keys_to_verify}
if (
verified_output["detail.dualPrimaryDetectionDelay"] == self.inputs.detection_delay
and verified_output["detail.dualPrimaryAction"] == errdisabled_action
and verified_output["dualPrimaryMlagRecoveryDelay"] == self.inputs.recovery_delay
and verified_output["dualPrimaryNonMlagRecoveryDelay"] == self.inputs.recovery_delay_non_mlag
):
self.result.is_success()
else:
self.result.is_failure(f"The dual-primary parameters are not configured properly: {verified_output}")

# Verifies the dualPrimaryAction
if (primary_action := get_value(command_output, "detail.dualPrimaryAction")) != errdisabled_action:
self.result.is_failure(f"Dual-primary action mismatch - Expected: {errdisabled_action} Actual: {primary_action}")

# Verifies the dualPrimaryDetectionDelay
if (detection_delay := get_value(command_output, "detail.dualPrimaryDetectionDelay")) != self.inputs.detection_delay:
self.result.is_failure(f"Dual-primary detection delay mismatch - Expected: {self.inputs.detection_delay} Actual: {detection_delay}")

# Verifies the dualPrimaryMlagRecoveryDelay
if (recovery_delay := get_value(command_output, "dualPrimaryMlagRecoveryDelay")) != self.inputs.recovery_delay:
self.result.is_failure(f"Dual-primary MLAG recovery delay mismatch - Expected: {self.inputs.recovery_delay} Actual: {recovery_delay}")

# Verifies the dualPrimaryNonMlagRecoveryDelay
if (recovery_delay_non_mlag := get_value(command_output, "dualPrimaryNonMlagRecoveryDelay")) != self.inputs.recovery_delay_non_mlag:
self.result.is_failure(
f"Dual-primary non MLAG recovery delay mismatch - Expected: {self.inputs.recovery_delay_non_mlag} Actual: {recovery_delay_non_mlag}"
)


class VerifyMlagPrimaryPriority(AntaTest):
Expand Down Expand Up @@ -282,6 +310,4 @@ def test(self) -> None:

# Check primary priority
if primary_priority != self.inputs.primary_priority:
self.result.is_failure(
f"The primary priority does not match expected. Expected `{self.inputs.primary_priority}`, but found `{primary_priority}` instead.",
)
self.result.is_failure(f"MLAG primary priority mismatch - Expected: {self.inputs.primary_priority} Actual: {primary_priority}")
87 changes: 53 additions & 34 deletions tests/units/anta_tests/test_mlag.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,33 @@
"expected": {"result": "skipped", "messages": ["MLAG is disabled"]},
},
{
"name": "failure",
"name": "failure-negotiation-status",
"test": VerifyMlagStatus,
"eos_data": [{"state": "active", "negStatus": "connecting", "peerLinkStatus": "up", "localIntfStatus": "up"}],
"inputs": None,
"expected": {
"result": "failure",
"messages": ["MLAG negotiation status mismatch - Expected: connected Actual: connecting"],
},
},
{
"name": "failure-local-interface",
"test": VerifyMlagStatus,
"eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "up", "localIntfStatus": "down"}],
"inputs": None,
"expected": {
"result": "failure",
"messages": ["Operational state of the MLAG local interface is not correct - Expected: up Actual: down"],
},
},
{
"name": "failure-peer-link",
"test": VerifyMlagStatus,
"eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "down", "localIntfStatus": "up"}],
"inputs": None,
"expected": {
"result": "failure",
"messages": ["MLAG status is not OK: {'state': 'active', 'negStatus': 'connected', 'localIntfStatus': 'up', 'peerLinkStatus': 'down'}"],
"messages": ["Operational state of the MLAG peer link is not correct - Expected: up Actual: down"],
},
},
{
Expand Down Expand Up @@ -74,7 +94,7 @@
"inputs": None,
"expected": {
"result": "failure",
"messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 0, 'Active-partial': 1, 'Active-full': 1}"],
"messages": ["MLAG status is not ok - Inactive Ports: 0 Partial Active Ports: 1"],
},
},
{
Expand All @@ -89,7 +109,7 @@
"inputs": None,
"expected": {
"result": "failure",
"messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 1, 'Active-partial': 1, 'Active-full': 1}"],
"messages": ["MLAG status is not ok - Inactive Ports: 1 Partial Active Ports: 1"],
},
},
{
Expand Down Expand Up @@ -124,12 +144,7 @@
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"MLAG config-sanity returned inconsistencies: "
"{'globalConfiguration': {'mlag': {'globalParameters': "
"{'dual-primary-detection-delay': {'localValue': '0', 'peerValue': '200'}}}}, "
"'interfaceConfiguration': {}}",
],
"messages": ["MLAG config-sanity found in global configuration"],
},
},
{
Expand All @@ -146,12 +161,7 @@
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"MLAG config-sanity returned inconsistencies: "
"{'globalConfiguration': {}, "
"'interfaceConfiguration': {'trunk-native-vlan mlag30': "
"{'interface': {'Port-Channel30': {'localValue': '123', 'peerValue': '3700'}}}}}",
],
"messages": ["MLAG config-sanity found in interface configuration"],
},
},
{
Expand All @@ -177,7 +187,10 @@
"test": VerifyMlagReloadDelay,
"eos_data": [{"state": "active", "reloadDelay": 400, "reloadDelayNonMlag": 430}],
"inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330},
"expected": {"result": "failure", "messages": ["The reload-delay parameters are not configured properly: {'reloadDelay': 400, 'reloadDelayNonMlag': 430}"]},
"expected": {
"result": "failure",
"messages": ["MLAG reload-delay mismatch - Expected: 300s Actual: 400s", "Delay for non-MLAG ports mismatch - Expected: 330s Actual: 430s"],
},
},
{
"name": "success",
Expand Down Expand Up @@ -236,13 +249,8 @@
"expected": {
"result": "failure",
"messages": [
(
"The dual-primary parameters are not configured properly: "
"{'detail.dualPrimaryDetectionDelay': 300, "
"'detail.dualPrimaryAction': 'none', "
"'dualPrimaryMlagRecoveryDelay': 160, "
"'dualPrimaryNonMlagRecoveryDelay': 0}"
),
"Dual-primary detection delay mismatch - Expected: 200 Actual: 300",
"Dual-primary MLAG recovery delay mismatch - Expected: 60 Actual: 160",
],
},
},
Expand All @@ -262,15 +270,26 @@
"inputs": {"detection_delay": 200, "errdisabled": True, "recovery_delay": 60, "recovery_delay_non_mlag": 0},
"expected": {
"result": "failure",
"messages": [
(
"The dual-primary parameters are not configured properly: "
"{'detail.dualPrimaryDetectionDelay': 200, "
"'detail.dualPrimaryAction': 'none', "
"'dualPrimaryMlagRecoveryDelay': 60, "
"'dualPrimaryNonMlagRecoveryDelay': 0}"
),
],
"messages": ["Dual-primary action mismatch - Expected: errdisableAllInterfaces Actual: none"],
},
},
{
"name": "failure-wrong-non-mlag-delay",
"test": VerifyMlagDualPrimary,
"eos_data": [
{
"state": "active",
"dualPrimaryDetectionState": "configured",
"dualPrimaryPortsErrdisabled": False,
"dualPrimaryMlagRecoveryDelay": 60,
"dualPrimaryNonMlagRecoveryDelay": 120,
"detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "errdisableAllInterfaces"},
},
],
"inputs": {"detection_delay": 200, "errdisabled": True, "recovery_delay": 60, "recovery_delay_non_mlag": 60},
"expected": {
"result": "failure",
"messages": ["Dual-primary non MLAG recovery delay mismatch - Expected: 60 Actual: 120"],
},
},
{
Expand Down Expand Up @@ -325,7 +344,7 @@
"inputs": {"primary_priority": 1},
"expected": {
"result": "failure",
"messages": ["The device is not set as MLAG primary.", "The primary priority does not match expected. Expected `1`, but found `32767` instead."],
"messages": ["The device is not set as MLAG primary.", "MLAG primary priority mismatch - Expected: 1 Actual: 32767"],
},
},
]

0 comments on commit 9ba0284

Please sign in to comment.