Repository: aristanetworks/anta (python)

Issue:
Enhancement(anta.tests): Hardware module tests should impose input restrictions on fields using field validators
Currently, some tests are accepting inputs as plain strings. We should implement field validation in these cases.

Example:
```
anta.tests.hardware:
      - VerifyEnvironmentPower:
          states:
            - ok
```


We have possible values for Fan status for example
`'failed', 'ok', 'unknownHwStatus' `

Pull request description:
feat(anta.tests): Hardware module tests should impose input restrictions
Added Strict check for the power supply and power supply fan state.

Fixes #1070

# 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`)
- [ ] I have made corresponding changes to the documentation
- [ ] 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`)


Patch:
diff --git a/anta/custom_types.py b/anta/custom_types.py
index 5c87e29b..2245cb17 100644
--- a/anta/custom_types.py
+++ b/anta/custom_types.py
@@ -396,3 +396,5 @@ RedistributedProtocol = Annotated[
 ]
 RedistributedAfiSafi = Annotated[Literal["v4u", "v4m", "v6u", "v6m"], BeforeValidator(bgp_redistributed_route_proto_abbreviations)]
 NTPStratumLevel = Annotated[int, Field(ge=0, le=16)]
+PowerSupplyFanStatus = Literal["failed", "ok", "unknownHwStatus", "powerLoss", "unsupported"]
+PowerSupplyStatus = Literal["ok", "unknown", "powerLoss", "failed"]


Test patch:
diff --git a/anta/tests/hardware.py b/anta/tests/hardware.py
index 9e0453f9..8bac413d 100644
--- a/anta/tests/hardware.py
+++ b/anta/tests/hardware.py
@@ -9,6 +9,7 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, ClassVar
 
+from anta.custom_types import PowerSupplyFanStatus, PowerSupplyStatus
 from anta.decorators import skip_on_platforms
 from anta.models import AntaCommand, AntaTest
 
@@ -176,7 +177,7 @@ class VerifyEnvironmentCooling(AntaTest):
     class Input(AntaTest.Input):
         """Input model for the VerifyEnvironmentCooling test."""
 
-        states: list[str]
+        states: list[PowerSupplyFanStatus]
         """List of accepted states of fan status."""
 
     @skip_on_platforms(["cEOSLab", "vEOS-lab", "cEOSCloudLab", "vEOS"])
@@ -225,7 +226,7 @@ class VerifyEnvironmentPower(AntaTest):
     class Input(AntaTest.Input):
         """Input model for the VerifyEnvironmentPower test."""
 
-        states: list[str]
+        states: list[PowerSupplyStatus]
         """List of accepted states list of power supplies status."""
 
     @skip_on_platforms(["cEOSLab", "vEOS-lab", "cEOSCloudLab", "vEOS"])
diff --git a/tests/units/anta_tests/test_hardware.py b/tests/units/anta_tests/test_hardware.py
index 972b07f0..15e921e9 100644
--- a/tests/units/anta_tests/test_hardware.py
+++ b/tests/units/anta_tests/test_hardware.py
@@ -395,7 +395,7 @@ DATA: list[dict[str, Any]] = [
                         "status": "ok",
                         "fans": [
                             {
-                                "status": "Not Inserted",
+                                "status": "powerLoss",
                                 "uptime": 1682498935.9121106,
                                 "maxSpeed": 23000,
                                 "lastSpeedStableChangeTime": 1682499092.4665174,
@@ -490,7 +490,7 @@ DATA: list[dict[str, Any]] = [
                 "systemStatus": "coolingOk",
             },
         ],
-        "inputs": {"states": ["ok", "Not Inserted"]},
+        "inputs": {"states": ["ok", "powerLoss"]},
         "expected": {"result": "success"},
     },
     {
@@ -548,7 +548,7 @@ DATA: list[dict[str, Any]] = [
                         "status": "ok",
                         "fans": [
                             {
-                                "status": "down",
+                                "status": "unknownHwStatus",
                                 "uptime": 1682498923.9303148,
                                 "maxSpeed": 17500,
                                 "lastSpeedStableChangeTime": 1682498975.0139885,
@@ -584,7 +584,7 @@ DATA: list[dict[str, Any]] = [
                         "status": "ok",
                         "fans": [
                             {
-                                "status": "Not Inserted",
+                                "status": "powerLoss",
                                 "uptime": 1682498923.9383528,
                                 "maxSpeed": 17500,
                                 "lastSpeedStableChangeTime": 1682498975.0140095,
@@ -623,8 +623,8 @@ DATA: list[dict[str, Any]] = [
                 "systemStatus": "CoolingKo",
             },
         ],
-        "inputs": {"states": ["ok", "Not Inserted"]},
-        "expected": {"result": "failure", "messages": ["Fan Tray: 1 Fan: 1/1 - Invalid state - Expected: ok, Not Inserted Actual: down"]},
+        "inputs": {"states": ["ok", "powerLoss"]},
+        "expected": {"result": "failure", "messages": ["Fan Tray: 1 Fan: 1/1 - Invalid state - Expected: ok, powerLoss Actual: unknownHwStatus"]},
     },
     {
         "name": "failure-power-supply",
@@ -643,7 +643,7 @@ DATA: list[dict[str, Any]] = [
                         "status": "ok",
                         "fans": [
                             {
-                                "status": "down",
+                                "status": "unknownHwStatus",
                                 "uptime": 1682498937.0240965,
                                 "maxSpeed": 23000,
                                 "lastSpeedStableChangeTime": 1682499033.0403435,
@@ -717,7 +717,7 @@ DATA: list[dict[str, Any]] = [
                         "status": "ok",
                         "fans": [
                             {
-                                "status": "Not Inserted",
+                                "status": "powerLoss",
                                 "uptime": 1682498923.9383528,
                                 "maxSpeed": 17500,
                                 "lastSpeedStableChangeTime": 1682498975.0140095,
@@ -756,11 +756,11 @@ DATA: list[dict[str, Any]] = [
                 "systemStatus": "CoolingKo",
             },
         ],
-        "inputs": {"states": ["ok", "Not Inserted"]},
+        "inputs": {"states": ["ok", "powerLoss"]},
         "expected": {
             "result": "failure",
             "messages": [
-                "Power Slot: PowerSupply1 Fan: PowerSupply1/1 - Invalid state - Expected: ok, Not Inserted Actual: down",
+                "Power Slot: PowerSupply1 Fan: PowerSupply1/1 - Invalid state - Expected: ok, powerLoss Actual: unknownHwStatus",
             ],
         },
     },
@@ -827,7 +827,7 @@ DATA: list[dict[str, Any]] = [
                             "TempSensorP1/1": {"status": "ok", "temperature": 0.0},
                         },
                         "fans": {"FanP1/1": {"status": "ok", "speed": 33}},
-                        "state": "Not Inserted",
+                        "state": "powerLoss",
                         "inputCurrent": 0.0,
                         "dominant": False,
                         "inputVoltage": 0.0,
@@ -855,7 +855,7 @@ DATA: list[dict[str, Any]] = [
                 },
             },
         ],
-        "inputs": {"states": ["ok", "Not Inserted"]},
+        "inputs": {"states": ["ok", "powerLoss"]},
         "expected": {"result": "success"},
     },
     {