Skip to content

Commit ad0a5ad

Browse files
authored
[psud] Increase unit test coverage (sonic-net#140)
- Add 100% unit test coverage of `PsuStatus` class in psud. - Add skeleton of class to test `DaemonPsud` class - Add test case for `get_psu_key()` and `try_get()` helper functions - Add checks to import 'mock' from the 'unittest' package if running with Python 3 Overall psud unit test coverage increases from 39% to 51%. Previous unit test coverage: ``` ----------- coverage: platform linux, python 3.7.3-final-0 ----------- Name Stmts Miss Cover ---------------------------------- scripts/psud 381 233 39% Coverage HTML written to dir htmlcov Coverage XML written to file coverage.xml ``` Unit test coverage with this patch: ``` ----------- coverage: platform linux, python 3.7.3-final-0 ----------- Name Stmts Miss Cover ---------------------------------- scripts/psud 381 185 51% Coverage HTML written to dir htmlcov Coverage XML written to file coverage.xml ```
1 parent 81318f7 commit ad0a5ad

File tree

4 files changed

+334
-2
lines changed

4 files changed

+334
-2
lines changed

sonic-psud/setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
'wheel'
2222
],
2323
tests_require=[
24+
'mock>=2.0.0; python_version < "3.3"',
2425
'pytest',
25-
'mock>=2.0.0',
2626
'pytest-cov'
2727
],
2828
classifiers=[

sonic-psud/tests/mock_platform.py

+8
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ def __init__(self, psu_presence, psu_status, psu_name):
3737
self.name = psu_name
3838
self.presence = True
3939
self.psu_status = psu_status
40+
self.status_led_color = self.STATUS_LED_COLOR_OFF
4041

4142
def get_powergood_status(self):
4243
return self.psu_status
4344

45+
def set_status_led(self, color):
46+
self.status_led_color = color
47+
return True
48+
49+
def get_status_led(self):
50+
return self.status_led_color
51+
4452
def set_status(self, status):
4553
self.psu_status = status
4654

sonic-psud/tests/test_PsuStatus.py

+236
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
import os
2+
import sys
3+
from imp import load_source
4+
5+
# TODO: Clean this up once we no longer need to support Python 2
6+
if sys.version_info.major == 3:
7+
from unittest.mock import MagicMock
8+
else:
9+
from mock import MagicMock
10+
11+
from .mock_platform import MockPsu
12+
13+
test_path = os.path.dirname(os.path.abspath(__file__))
14+
modules_path = os.path.dirname(test_path)
15+
scripts_path = os.path.join(modules_path, "scripts")
16+
sys.path.insert(0, modules_path)
17+
18+
os.environ["PSUD_UNIT_TESTING"] = "1"
19+
load_source('psud', scripts_path + '/psud')
20+
from psud import *
21+
22+
23+
class TestPsuStatus(object):
24+
"""
25+
Test cases to cover functionality of PsuStatus class
26+
"""
27+
28+
def test_set_presence(self):
29+
mock_logger = MagicMock()
30+
mock_psu = MockPsu(True, True, "PSU 1")
31+
32+
psu_status = PsuStatus(mock_logger, mock_psu)
33+
assert psu_status.presence == False
34+
35+
# Test toggling presence to True
36+
ret = psu_status.set_presence(True)
37+
assert ret == True
38+
assert psu_status.presence == True
39+
40+
# Test toggling presence to False
41+
ret = psu_status.set_presence(False)
42+
assert ret == True
43+
assert psu_status.presence == False
44+
45+
# Test attempting to set presence to the same as the current value
46+
ret = psu_status.set_presence(False)
47+
assert ret == False
48+
assert psu_status.presence == False
49+
50+
def test_set_power_good(self):
51+
mock_logger = MagicMock()
52+
mock_psu = MockPsu(True, True, "PSU 1")
53+
54+
psu_status = PsuStatus(mock_logger, mock_psu)
55+
assert psu_status.power_good == False
56+
57+
# Test toggling power_good to True
58+
ret = psu_status.set_power_good(True)
59+
assert ret == True
60+
assert psu_status.power_good == True
61+
62+
# Test attempting to set power_good to the same as the current value (return value should be False)
63+
ret = psu_status.set_power_good(True)
64+
assert ret == False
65+
assert psu_status.power_good == True
66+
67+
# Test toggling power_good to False
68+
ret = psu_status.set_power_good(False)
69+
assert ret == True
70+
assert psu_status.power_good == False
71+
72+
# Test attempting to set power_good to the same as the current value (return value should be False)
73+
ret = psu_status.set_power_good(False)
74+
assert ret == False
75+
assert psu_status.power_good == False
76+
77+
def test_set_voltage(self):
78+
mock_logger = MagicMock()
79+
mock_psu = MockPsu(True, True, "PSU 1")
80+
81+
psu_status = PsuStatus(mock_logger, mock_psu)
82+
assert psu_status.voltage_good == False
83+
84+
# Pass in a good voltage
85+
ret = psu_status.set_voltage(12.0, 12.5, 11.5)
86+
assert ret == True
87+
assert psu_status.voltage_good == True
88+
89+
# Pass in a another good voltage successively (return value should be False)
90+
ret = psu_status.set_voltage(11.9, 12.5, 11.5)
91+
assert ret == False
92+
assert psu_status.voltage_good == True
93+
94+
# Pass in a high voltage
95+
ret = psu_status.set_voltage(12.6, 12.5, 11.5)
96+
assert ret == True
97+
assert psu_status.voltage_good == False
98+
99+
# Pass in a another bad voltage successively (return value should be False)
100+
ret = psu_status.set_voltage(12.7, 12.5, 11.5)
101+
assert ret == False
102+
assert psu_status.voltage_good == False
103+
104+
# Pass in a good (high edge case) voltage
105+
ret = psu_status.set_voltage(12.5, 12.5, 11.5)
106+
assert ret == True
107+
assert psu_status.voltage_good == True
108+
109+
# Pass in a low voltage
110+
ret = psu_status.set_voltage(11.4, 12.5, 11.5)
111+
assert ret == True
112+
assert psu_status.voltage_good == False
113+
114+
# Pass in a good (low edge case) voltage
115+
ret = psu_status.set_voltage(11.5, 12.5, 11.5)
116+
assert ret == True
117+
assert psu_status.voltage_good == True
118+
119+
# Test passing parameters as None when voltage_good == True
120+
ret = psu_status.set_voltage(None, 12.5, 11.5)
121+
assert ret == False
122+
assert psu_status.voltage_good == True
123+
ret = psu_status.set_voltage(11.5, None, 11.5)
124+
assert ret == False
125+
assert psu_status.voltage_good == True
126+
ret = psu_status.set_voltage(11.5, 12.5, None)
127+
assert ret == False
128+
assert psu_status.voltage_good == True
129+
130+
# Test passing parameters as None when voltage_good == False
131+
psu_status.voltage_good = False
132+
ret = psu_status.set_voltage(None, 12.5, 11.5)
133+
assert ret == False
134+
assert psu_status.voltage_good == True
135+
psu_status.voltage_good = False
136+
ret = psu_status.set_voltage(11.5, None, 11.5)
137+
assert ret == False
138+
assert psu_status.voltage_good == True
139+
psu_status.voltage_good = False
140+
ret = psu_status.set_voltage(11.5, 12.5, None)
141+
assert ret == False
142+
assert psu_status.voltage_good == True
143+
144+
def test_set_temperature(self):
145+
mock_logger = MagicMock()
146+
mock_psu = MockPsu(True, True, "PSU 1")
147+
148+
psu_status = PsuStatus(mock_logger, mock_psu)
149+
assert psu_status.temperature_good == False
150+
151+
# Pass in a good temperature
152+
ret = psu_status.set_temperature(20.123, 50.0)
153+
assert ret == True
154+
assert psu_status.temperature_good == True
155+
156+
# Pass in a another good temperature successively (return value should be False)
157+
ret = psu_status.set_temperature(31.456, 50.0)
158+
assert ret == False
159+
assert psu_status.temperature_good == True
160+
161+
# Pass in a high temperature
162+
ret = psu_status.set_temperature(50.001, 50.0)
163+
assert ret == True
164+
assert psu_status.temperature_good == False
165+
166+
# Pass in a another bad temperature successively (return value should be False)
167+
ret = psu_status.set_temperature(50.0, 50.0)
168+
assert ret == False
169+
assert psu_status.temperature_good == False
170+
171+
# Pass in a good (high edge case) temperature
172+
ret = psu_status.set_temperature(49.999, 50.0)
173+
assert ret == True
174+
assert psu_status.temperature_good == True
175+
176+
# Test passing parameters as None when temperature_good == True
177+
ret = psu_status.set_temperature(None, 50.0)
178+
assert ret == False
179+
assert psu_status.temperature_good == True
180+
ret = psu_status.set_temperature(20.123, None)
181+
assert ret == False
182+
assert psu_status.temperature_good == True
183+
184+
# Test passing parameters as None when temperature_good == False
185+
psu_status.temperature_good = False
186+
ret = psu_status.set_temperature(None, 50.0)
187+
assert ret == False
188+
assert psu_status.temperature_good == True
189+
psu_status.temperature_good = False
190+
ret = psu_status.set_temperature(20.123, None)
191+
assert ret == False
192+
assert psu_status.temperature_good == True
193+
194+
def test_is_ok(self):
195+
mock_logger = MagicMock()
196+
mock_psu = MockPsu(True, True, "PSU 1")
197+
198+
psu_status = PsuStatus(mock_logger, mock_psu)
199+
psu_status.presence = True
200+
psu_status.power_good = True
201+
psu_status.voltage_good = True
202+
psu_status.temperature_good = True
203+
ret = psu_status.is_ok()
204+
assert ret == True
205+
206+
psu_status.presence = False
207+
ret = psu_status.is_ok()
208+
assert ret == False
209+
210+
psu_status.presence = True
211+
ret = psu_status.is_ok()
212+
assert ret == True
213+
214+
psu_status.power_good = False
215+
ret = psu_status.is_ok()
216+
assert ret == False
217+
218+
psu_status.power_good = True
219+
ret = psu_status.is_ok()
220+
assert ret == True
221+
222+
psu_status.voltage_good = False
223+
ret = psu_status.is_ok()
224+
assert ret == False
225+
226+
psu_status.voltage_good = True
227+
ret = psu_status.is_ok()
228+
assert ret == True
229+
230+
psu_status.temperature_good = False
231+
ret = psu_status.is_ok()
232+
assert ret == False
233+
234+
psu_status.temperature_good = True
235+
ret = psu_status.is_ok()
236+
assert ret == True

sonic-psud/tests/test_psud.py

+89-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
import sys
33
from imp import load_source
44

5-
from mock import Mock, MagicMock, patch
5+
# TODO: Clean this up once we no longer need to support Python 2
6+
if sys.version_info.major == 3:
7+
from unittest.mock import Mock, MagicMock, patch
8+
else:
9+
from mock import Mock, MagicMock, patch
610
from sonic_py_common import daemon_base
711

812
from .mock_platform import MockChassis, MockPsu, MockFanDrawer, MockModule
@@ -169,3 +173,87 @@ def test_psuchassis_check_power_budget():
169173
assert float(fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) > float(fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD])
170174
assert chassis_info.master_status_good == True
171175
assert MockPsu.get_status_master_led() == MockPsu.STATUS_LED_COLOR_GREEN
176+
177+
178+
def test_get_psu_key():
179+
assert get_psu_key(0) == PSU_INFO_KEY_TEMPLATE.format(0)
180+
assert get_psu_key(1) == PSU_INFO_KEY_TEMPLATE.format(1)
181+
182+
183+
def test_try_get():
184+
# Test a proper, working callback
185+
GOOD_CALLBACK_RETURN_VALUE = "This is a test"
186+
187+
def callback1():
188+
return GOOD_CALLBACK_RETURN_VALUE
189+
190+
ret = try_get(callback1)
191+
assert ret == GOOD_CALLBACK_RETURN_VALUE
192+
193+
# Ensure try_get returns default value if callback returns None
194+
DEFAULT_VALUE = "Default value"
195+
196+
def callback2():
197+
return None
198+
199+
ret = try_get(callback2, default=DEFAULT_VALUE)
200+
assert ret == DEFAULT_VALUE
201+
202+
# Ensure try_get returns default value if callback returns None
203+
def callback3():
204+
raise NotImplementedError
205+
206+
ret = try_get(callback3, default=DEFAULT_VALUE)
207+
assert ret == DEFAULT_VALUE
208+
209+
210+
class TestDaemonPsud(object):
211+
"""
212+
Test cases to cover functionality in DaemonPsud class
213+
"""
214+
215+
def test_set_psu_led(self):
216+
mock_logger = MagicMock()
217+
mock_psu = MockPsu(True, True, "PSU 1")
218+
psu_status = PsuStatus(mock_logger, mock_psu)
219+
220+
daemon_psud = DaemonPsud(SYSLOG_IDENTIFIER)
221+
222+
psu_status.presence = True
223+
psu_status.power_good = True
224+
psu_status.voltage_good = True
225+
psu_status.temperature_good = True
226+
daemon_psud._set_psu_led(mock_psu, psu_status)
227+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_GREEN
228+
229+
psu_status.presence = False
230+
daemon_psud._set_psu_led(mock_psu, psu_status)
231+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_RED
232+
233+
psu_status.presence = True
234+
daemon_psud._set_psu_led(mock_psu, psu_status)
235+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_GREEN
236+
237+
psu_status.power_good = False
238+
daemon_psud._set_psu_led(mock_psu, psu_status)
239+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_RED
240+
241+
psu_status.power_good = True
242+
daemon_psud._set_psu_led(mock_psu, psu_status)
243+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_GREEN
244+
245+
psu_status.voltage_good = False
246+
daemon_psud._set_psu_led(mock_psu, psu_status)
247+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_RED
248+
249+
psu_status.voltage_good = True
250+
daemon_psud._set_psu_led(mock_psu, psu_status)
251+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_GREEN
252+
253+
psu_status.temperature_good = False
254+
daemon_psud._set_psu_led(mock_psu, psu_status)
255+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_RED
256+
257+
psu_status.temperature_good = True
258+
daemon_psud._set_psu_led(mock_psu, psu_status)
259+
assert mock_psu.get_status_led() == mock_psu.STATUS_LED_COLOR_GREEN

0 commit comments

Comments
 (0)