# 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. """Tests for anta.tests.mlag.py.""" from __future__ import annotations import sys from typing import TYPE_CHECKING, Any from anta.models import AntaTest from anta.result_manager.models import AntaTestStatus from anta.tests.mlag import VerifyMlagConfigSanity, VerifyMlagDualPrimary, VerifyMlagInterfaces, VerifyMlagPrimaryPriority, VerifyMlagReloadDelay, VerifyMlagStatus from tests.units.anta_tests import test if TYPE_CHECKING: from tests.units.anta_tests import AntaUnitTestDataDict DATA: AntaUnitTestDataDict = { (VerifyMlagStatus, "success"): { "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "up", "localIntfStatus": "up"}], "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagStatus, "skipped"): { "eos_data": [{"state": "disabled"}], "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagStatus, "failure-negotiation-status"): { "eos_data": [{"state": "active", "negStatus": "connecting", "peerLinkStatus": "up", "localIntfStatus": "up"}], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["MLAG negotiation status mismatch - Expected: connected Actual: connecting"]}, }, (VerifyMlagStatus, "failure-local-interface"): { "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "up", "localIntfStatus": "down"}], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["Operational state of the MLAG local interface is not correct - Expected: up Actual: down"]}, }, (VerifyMlagStatus, "failure-peer-link"): { "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "down", "localIntfStatus": "up"}], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["Operational state of the MLAG peer link is not correct - Expected: up Actual: down"]}, }, (VerifyMlagInterfaces, "success"): { "eos_data": [{"state": "active", "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 0, "Active-full": 1}}], "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagInterfaces, "skipped"): { "eos_data": [{"state": "disabled"}], "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagInterfaces, "failure-active-partial"): { "eos_data": [{"state": "active", "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 1, "Active-full": 1}}], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["MLAG status is not ok - Inactive Ports: 0 Partial Active Ports: 1"]}, }, (VerifyMlagInterfaces, "failure-inactive"): { "eos_data": [{"state": "active", "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 1, "Active-partial": 1, "Active-full": 1}}], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["MLAG status is not ok - Inactive Ports: 1 Partial Active Ports: 1"]}, }, (VerifyMlagConfigSanity, "success"): { "eos_data": [{"globalConfiguration": {}, "interfaceConfiguration": {}, "mlagActive": True, "mlagConnected": True}], "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagConfigSanity, "skipped"): { "eos_data": [{"mlagActive": False}], "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagConfigSanity, "failure-global"): { "eos_data": [ { "globalConfiguration": {"mlag": {"globalParameters": {"dual-primary-detection-delay": {"localValue": "0", "peerValue": "200"}}}}, "interfaceConfiguration": {}, "mlagActive": True, "mlagConnected": True, } ], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["MLAG config-sanity found in global configuration"]}, }, (VerifyMlagConfigSanity, "failure-interface"): { "eos_data": [ { "globalConfiguration": {}, "interfaceConfiguration": {"trunk-native-vlan mlag30": {"interface": {"Port-Channel30": {"localValue": "123", "peerValue": "3700"}}}}, "mlagActive": True, "mlagConnected": True, } ], "expected": {"result": AntaTestStatus.FAILURE, "messages": ["MLAG config-sanity found in interface configuration"]}, }, (VerifyMlagReloadDelay, "success"): { "eos_data": [{"state": "active", "reloadDelay": 300, "reloadDelayNonMlag": 330}], "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagReloadDelay, "skipped-disabled"): { "eos_data": [{"state": "disabled"}], "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagReloadDelay, "failure"): { "eos_data": [{"state": "active", "reloadDelay": 400, "reloadDelayNonMlag": 430}], "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, "expected": { "result": AntaTestStatus.FAILURE, "messages": ["MLAG reload-delay mismatch - Expected: 300s Actual: 400s", "Delay for non-MLAG ports mismatch - Expected: 330s Actual: 430s"], }, }, (VerifyMlagDualPrimary, "success"): { "eos_data": [ { "state": "active", "dualPrimaryDetectionState": "configured", "dualPrimaryPortsErrdisabled": False, "dualPrimaryMlagRecoveryDelay": 60, "dualPrimaryNonMlagRecoveryDelay": 0, "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"}, } ], "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagDualPrimary, "skipped-disabled"): { "eos_data": [{"state": "disabled"}], "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagDualPrimary, "failure-disabled"): { "eos_data": [{"state": "active", "dualPrimaryDetectionState": "disabled", "dualPrimaryPortsErrdisabled": False}], "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, "expected": {"result": AntaTestStatus.FAILURE, "messages": ["Dual-primary detection is disabled"]}, }, (VerifyMlagDualPrimary, "failure-wrong-timers"): { "eos_data": [ { "state": "active", "dualPrimaryDetectionState": "configured", "dualPrimaryPortsErrdisabled": False, "dualPrimaryMlagRecoveryDelay": 160, "dualPrimaryNonMlagRecoveryDelay": 0, "detail": {"dualPrimaryDetectionDelay": 300, "dualPrimaryAction": "none"}, } ], "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, "expected": { "result": AntaTestStatus.FAILURE, "messages": [ "Dual-primary detection delay mismatch - Expected: 200 Actual: 300", "Dual-primary MLAG recovery delay mismatch - Expected: 60 Actual: 160", ], }, }, (VerifyMlagDualPrimary, "failure-wrong-action"): { "eos_data": [ { "state": "active", "dualPrimaryDetectionState": "configured", "dualPrimaryPortsErrdisabled": False, "dualPrimaryMlagRecoveryDelay": 60, "dualPrimaryNonMlagRecoveryDelay": 0, "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"}, } ], "inputs": {"detection_delay": 200, "errdisabled": True, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, "expected": {"result": AntaTestStatus.FAILURE, "messages": ["Dual-primary action mismatch - Expected: errdisableAllInterfaces Actual: none"]}, }, (VerifyMlagDualPrimary, "failure-wrong-non-mlag-delay"): { "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": AntaTestStatus.FAILURE, "messages": ["Dual-primary non MLAG recovery delay mismatch - Expected: 60 Actual: 120"]}, }, (VerifyMlagPrimaryPriority, "success"): { "eos_data": [{"state": "active", "detail": {"mlagState": "primary", "primaryPriority": 32767}}], "inputs": {"primary_priority": 32767}, "expected": {"result": AntaTestStatus.SUCCESS}, }, (VerifyMlagPrimaryPriority, "skipped-disabled"): { "eos_data": [{"state": "disabled"}], "inputs": {"primary_priority": 32767}, "expected": {"result": AntaTestStatus.SKIPPED, "messages": ["MLAG is disabled"]}, }, (VerifyMlagPrimaryPriority, "failure-not-primary"): { "eos_data": [{"state": "active", "detail": {"mlagState": "secondary", "primaryPriority": 32767}}], "inputs": {"primary_priority": 32767}, "expected": {"result": AntaTestStatus.FAILURE, "messages": ["The device is not set as MLAG primary"]}, }, (VerifyMlagPrimaryPriority, "failure-incorrect-priority"): { "eos_data": [{"state": "active", "detail": {"mlagState": "secondary", "primaryPriority": 32767}}], "inputs": {"primary_priority": 1}, "expected": { "result": AntaTestStatus.FAILURE, "messages": ["The device is not set as MLAG primary", "MLAG primary priority mismatch - Expected: 1 Actual: 32767"], }, }, }