@@ -59,136 +59,148 @@ class IfAttributesMock:
59
59
60
60
return device
61
61
62
+ def _test_parse_device_info (self , fixture_name ):
63
+ """
64
+ Helper method to test parse_device_info() for a single JSON fixture.
65
+ """
66
+ data = load_json_fixture (fixture_name )
67
+ device_info = data ["device_info" ]
68
+
69
+ device = self .create_mock_device_from_json (device_info )
70
+ metrics = parse_device_info (device )
71
+
72
+ dev_name = device_info ["name" ]
73
+ dev_iface = device_info ["interface" ]
74
+ dev_serial = device_info ["serial" ].lower ()
75
+
76
+ # The device_info line should exist for every device
77
+ # e.g. device_info{disk="/dev/...",type="...",serial_number="..."} 1
78
+ device_info_found = any (
79
+ line .startswith ("device_info{" ) and
80
+ f'disk="{ dev_name } "' in line and
81
+ f'type="{ dev_iface } "' in line and
82
+ f'serial_number="{ dev_serial } "' in line
83
+ for line in metrics
84
+ )
85
+ self .assertTrue (
86
+ device_info_found ,
87
+ f"Expected a device_info metric line for { dev_name } but didn't find it."
88
+ )
89
+
90
+ # If smart_capable is true, we expect device_smart_available = 1
91
+ if device_info .get ("smart_capable" ):
92
+ smart_available_found = any (
93
+ line .startswith ("device_smart_available{" ) and
94
+ f'disk="{ dev_name } "' in line and
95
+ f'serial_number="{ dev_serial } "' in line and
96
+ line .endswith (" 1" )
97
+ for line in metrics
98
+ )
99
+ self .assertTrue (
100
+ smart_available_found ,
101
+ f"Expected device_smart_available=1 for { dev_name } , not found."
102
+ )
103
+
104
+ # If smart_enabled is true, we expect device_smart_enabled = 1
105
+ if device_info .get ("smart_enabled" ):
106
+ smart_enabled_found = any (
107
+ line .startswith ("device_smart_enabled{" ) and
108
+ f'disk="{ dev_name } "' in line and
109
+ line .endswith (" 1" )
110
+ for line in metrics
111
+ )
112
+ self .assertTrue (
113
+ smart_enabled_found ,
114
+ f"Expected device_smart_enabled=1 for { dev_name } , not found."
115
+ )
116
+
117
+ # device_smart_healthy if assessment in [PASS, WARN, FAIL]
118
+ # PASS => 1, otherwise => 0
119
+ assessment = device_info .get ("assessment" , "" ).upper ()
120
+ if assessment in ["PASS" , "WARN" , "FAIL" ]:
121
+ expected_val = 1 if assessment == "PASS" else 0
122
+ smart_healthy_found = any (
123
+ line .startswith ("device_smart_healthy{" ) and
124
+ f'disk="{ dev_name } "' in line and
125
+ line .endswith (f" { expected_val } " )
126
+ for line in metrics
127
+ )
128
+ self .assertTrue (
129
+ smart_healthy_found ,
130
+ f"Expected device_smart_healthy={ expected_val } for { dev_name } , not found."
131
+ )
132
+
62
133
def test_parse_device_info (self ):
63
134
"""
64
135
Test parse_device_info() for every JSON fixture in ./drives/.
65
- We do subTest() so each fixture is tested individually.
136
+ Each fixture is tested individually with clear error reporting .
66
137
"""
67
138
for fixture_path in self .fixture_files :
68
139
fixture_name = os .path .basename (fixture_path )
69
- with self .subTest (msg = f"Testing device_info with { fixture_name } " ):
70
- data = load_json_fixture (fixture_name )
71
- device_info = data ["device_info" ]
72
-
73
- device = self .create_mock_device_from_json (device_info )
74
- metrics = parse_device_info (device )
140
+ with self .subTest (fixture = fixture_name ):
141
+ self ._test_parse_device_info (fixture_name )
75
142
76
- dev_name = device_info ["name" ]
77
- dev_iface = device_info ["interface" ]
78
- dev_serial = device_info ["serial" ].lower ()
79
-
80
- # The device_info line should exist for every device
81
- # e.g. device_info{disk="/dev/...",type="...",serial_number="..."} 1
82
- device_info_found = any (
83
- line .startswith ("device_info{" ) and
84
- f'disk="{ dev_name } "' in line and
85
- f'type="{ dev_iface } "' in line and
86
- f'serial_number="{ dev_serial } "' in line
87
- for line in metrics
143
+ def _test_parse_if_attributes (self , fixture_name ):
144
+ """
145
+ Helper method to test parse_if_attributes() for a single JSON fixture.
146
+ """
147
+ data = load_json_fixture (fixture_name )
148
+ device_info = data ["device_info" ]
149
+ if_attrs = data .get ("if_attributes" , {})
150
+
151
+ device = self .create_mock_device_from_json (device_info , if_attrs )
152
+ metrics = parse_if_attributes (device )
153
+
154
+ dev_name = device_info ["name" ]
155
+ dev_iface = device_info ["interface" ]
156
+ dev_serial = device_info ["serial" ].lower ()
157
+
158
+ # For each numeric attribute in JSON, if it's in SMARTMON_ATTRS,
159
+ # we expect a line in the script's output.
160
+ for attr_key , attr_val in if_attrs .items ():
161
+ # Convert from e.g. "criticalWarning" -> "critical_warning"
162
+ snake_key = re .sub (r'(?<!^)(?=[A-Z])' , '_' , attr_key ).lower ()
163
+
164
+ if isinstance (attr_val , (int , float )) and snake_key in SMARTMON_ATTRS :
165
+ # We expect e.g. critical_warning{disk="/dev/..."} <value>
166
+ expected_line = (
167
+ f"{ snake_key } {{disk=\" { dev_name } \" ,type=\" { dev_iface } \" ,serial_number=\" { dev_serial } \" }} { attr_val } "
88
168
)
89
- self .assertTrue (
90
- device_info_found ,
91
- f"Expected a device_info metric line for { dev_name } but didn't find it."
169
+ self .assertIn (
170
+ expected_line ,
171
+ metrics ,
172
+ f"Expected metric '{ expected_line } ' for attribute '{ attr_key } ' not found."
173
+ )
174
+ else :
175
+ # If it's not in SMARTMON_ATTRS or not numeric,
176
+ # we do NOT expect a line with that name+value
177
+ unexpected_line = (
178
+ f"{ snake_key } {{disk=\" { dev_name } \" ,type=\" { dev_iface } \" ,serial_number=\" { dev_serial } \" }} { attr_val } "
179
+ )
180
+ self .assertNotIn (
181
+ unexpected_line ,
182
+ metrics ,
183
+ f"Unexpected metric '{ unexpected_line } ' found for { attr_key } ."
92
184
)
93
185
94
- # If smart_capable is true, we expect device_smart_available = 1
95
- if device_info .get ("smart_capable" ):
96
- smart_available_found = any (
97
- line .startswith ("device_smart_available{" ) and
98
- f'disk="{ dev_name } "' in line and
99
- f'serial_number="{ dev_serial } "' in line and
100
- line .endswith (" 1" )
101
- for line in metrics
102
- )
103
- self .assertTrue (
104
- smart_available_found ,
105
- f"Expected device_smart_available=1 for { dev_name } , not found."
106
- )
107
-
108
- # If smart_enabled is true, we expect device_smart_enabled = 1
109
- if device_info .get ("smart_enabled" ):
110
- smart_enabled_found = any (
111
- line .startswith ("device_smart_enabled{" ) and
112
- f'disk="{ dev_name } "' in line and
113
- line .endswith (" 1" )
114
- for line in metrics
115
- )
116
- self .assertTrue (
117
- smart_enabled_found ,
118
- f"Expected device_smart_enabled=1 for { dev_name } , not found."
119
- )
120
-
121
- # device_smart_healthy if assessment in [PASS, WARN, FAIL]
122
- # PASS => 1, otherwise => 0
123
- assessment = device_info .get ("assessment" , "" ).upper ()
124
- if assessment in ["PASS" , "WARN" , "FAIL" ]:
125
- expected_val = 1 if assessment == "PASS" else 0
126
- smart_healthy_found = any (
127
- line .startswith ("device_smart_healthy{" ) and
128
- f'disk="{ dev_name } "' in line and
129
- line .endswith (f" { expected_val } " )
130
- for line in metrics
131
- )
132
- self .assertTrue (
133
- smart_healthy_found ,
134
- f"Expected device_smart_healthy={ expected_val } for { dev_name } , not found."
135
- )
186
+ # Also ensure that non-numeric or disallowed attributes do not appear
187
+ # For instance "notInSmartmonAttrs" should never appear.
188
+ for line in metrics :
189
+ self .assertNotIn (
190
+ "not_in_smartmon_attrs" ,
191
+ line ,
192
+ f"'notInSmartmonAttrs' attribute unexpectedly found in metric line: { line } "
193
+ )
136
194
137
195
def test_parse_if_attributes (self ):
138
196
"""
139
197
Test parse_if_attributes() for every JSON fixture in ./drives/.
140
- We do subTest() so each fixture is tested individually.
198
+ Each fixture is tested individually with clear error reporting .
141
199
"""
142
200
for fixture_path in self .fixture_files :
143
201
fixture_name = os .path .basename (fixture_path )
144
- with self .subTest (msg = f"Testing if_attributes with { fixture_name } " ):
145
- data = load_json_fixture (fixture_name )
146
- device_info = data ["device_info" ]
147
- if_attrs = data .get ("if_attributes" , {})
148
-
149
- device = self .create_mock_device_from_json (device_info , if_attrs )
150
- metrics = parse_if_attributes (device )
151
-
152
- dev_name = device_info ["name" ]
153
- dev_iface = device_info ["interface" ]
154
- dev_serial = device_info ["serial" ].lower ()
155
-
156
- # For each numeric attribute in JSON, if it's in SMARTMON_ATTRS,
157
- # we expect a line in the script's output.
158
- for attr_key , attr_val in if_attrs .items ():
159
- # Convert from e.g. "criticalWarning" -> "critical_warning"
160
- snake_key = re .sub (r'(?<!^)(?=[A-Z])' , '_' , attr_key ).lower ()
161
-
162
- if isinstance (attr_val , (int , float )) and snake_key in SMARTMON_ATTRS :
163
- # We expect e.g. critical_warning{disk="/dev/..."} <value>
164
- expected_line = (
165
- f"{ snake_key } {{disk=\" { dev_name } \" ,type=\" { dev_iface } \" ,serial_number=\" { dev_serial } \" }} { attr_val } "
166
- )
167
- self .assertIn (
168
- expected_line ,
169
- metrics ,
170
- f"Expected metric '{ expected_line } ' for attribute '{ attr_key } ' not found."
171
- )
172
- else :
173
- # If it's not in SMARTMON_ATTRS or not numeric,
174
- # we do NOT expect a line with that name+value
175
- unexpected_line = (
176
- f"{ snake_key } {{disk=\" { dev_name } \" ,type=\" { dev_iface } \" ,serial_number=\" { dev_serial } \" }} { attr_val } "
177
- )
178
- self .assertNotIn (
179
- unexpected_line ,
180
- metrics ,
181
- f"Unexpected metric '{ unexpected_line } ' found for { attr_key } ."
182
- )
183
-
184
- # Also ensure that non-numeric or disallowed attributes do not appear
185
- # For instance "notInSmartmonAttrs" should never appear.
186
- for line in metrics :
187
- self .assertNotIn (
188
- "not_in_smartmon_attrs" ,
189
- line ,
190
- f"'notInSmartmonAttrs' attribute unexpectedly found in metric line: { line } "
191
- )
202
+ with self .subTest (fixture = fixture_name ):
203
+ self ._test_parse_if_attributes (fixture_name )
192
204
193
205
@patch ("smartmon.run_command" )
194
206
@patch ("smartmon.DeviceList" )
0 commit comments