diff --git a/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py b/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py index 3b380bad34f0..7a0090264cae 100644 --- a/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py +++ b/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py @@ -25,6 +25,8 @@ class ThermalManagerBase(object): _run_thermal_algorithm_at_boot_up = None + _running = True + @classmethod def initialize(cls): """ @@ -43,6 +45,14 @@ def deinitialize(cls): """ pass + @classmethod + def stop(cls): + """ + Stop thermal manager. + :return: + """ + cls._running = False + @classmethod def start_thermal_control_algorithm(cls): """ @@ -169,6 +179,8 @@ def run_policy(cls, chassis): cls._collect_thermal_information(chassis) for policy in cls._policy_dict.values(): + if not cls._running: + return if policy.is_match(cls._thermal_info_dict): policy.do_action(cls._thermal_info_dict) @@ -180,6 +192,8 @@ def _collect_thermal_information(cls, chassis): :return: """ for thermal_info in cls._thermal_info_dict.values(): + if not cls._running: + return thermal_info.collect(chassis) @classmethod diff --git a/tests/thermal_manager_test.py b/tests/thermal_manager_test.py new file mode 100644 index 000000000000..6259c60e6c29 --- /dev/null +++ b/tests/thermal_manager_test.py @@ -0,0 +1,102 @@ +import os +import sys + +# TODO: Clean this up once we no longer need to support Python 2 +if sys.version_info.major == 3: + from unittest import mock +else: + import mock + +from sonic_platform_base.sonic_thermal_control import thermal_manager_base as tmb +from sonic_platform_base.sonic_thermal_control import thermal_info_base +from sonic_platform_base.sonic_thermal_control import thermal_action_base +from sonic_platform_base.sonic_thermal_control import thermal_condition_base +from sonic_platform_base.sonic_thermal_control import thermal_json_object + + +@thermal_json_object.thermal_json_object('some_info') +class MockThermalInfo(thermal_info_base.ThermalPolicyInfoBase): + pass + + +@thermal_json_object.thermal_json_object('action1') +class MockThermalAction1(thermal_action_base.ThermalPolicyActionBase): + def load_from_json(self, json_obj): + self.speed = int(json_obj['speed']) + + +@thermal_json_object.thermal_json_object('action2') +class MockThermalAction2(thermal_action_base.ThermalPolicyActionBase): + def load_from_json(self, json_obj): + self.enable = bool(json_obj['enable']) + + +@thermal_json_object.thermal_json_object('condition1') +class MockThermalCondition1(thermal_condition_base.ThermalPolicyConditionBase): + pass + + +@thermal_json_object.thermal_json_object('condition2') +class MockThermalCondition2(thermal_condition_base.ThermalPolicyConditionBase): + pass + + +class MockChassis: + pass + + +class TestThermalManagerBase: + @classmethod + def setup_class(cls): + tests_dir = os.path.dirname(os.path.abspath(__file__)) + tmb.ThermalManagerBase.load(os.path.join(tests_dir, 'thermal_policy.json')) + + def test_load_policy(self): + assert tmb.ThermalManagerBase._fan_speed_when_suspend == 60 + assert tmb.ThermalManagerBase._run_thermal_algorithm_at_boot_up + + assert 'some_info' in tmb.ThermalManagerBase._thermal_info_dict + some_info = tmb.ThermalManagerBase._thermal_info_dict['some_info'] + assert isinstance(some_info, MockThermalInfo) + + assert 'policy1' in tmb.ThermalManagerBase._policy_dict + assert 'policy2' in tmb.ThermalManagerBase._policy_dict + policy1 = tmb.ThermalManagerBase._policy_dict['policy1'] + assert MockThermalCondition1 in policy1.conditions + assert isinstance(policy1.conditions[MockThermalCondition1], MockThermalCondition1) + assert MockThermalAction1 in policy1.actions + assert isinstance(policy1.actions[MockThermalAction1], MockThermalAction1) + policy2 = tmb.ThermalManagerBase._policy_dict['policy2'] + assert MockThermalCondition2 in policy2.conditions + assert isinstance(policy2.conditions[MockThermalCondition2], MockThermalCondition2) + assert MockThermalAction2 in policy2.actions + assert isinstance(policy2.actions[MockThermalAction2], MockThermalAction2) + + def test_run_policy(self): + MockThermalInfo.collect = mock.MagicMock() + MockThermalCondition1.is_match = mock.MagicMock(return_value=False) + MockThermalCondition2.is_match = mock.MagicMock(return_value=True) + MockThermalAction1.execute = mock.MagicMock() + MockThermalAction2.execute = mock.MagicMock() + + chassis = MockChassis() + tmb.ThermalManagerBase.run_policy(chassis) + assert MockThermalInfo.collect.call_count == 1 + assert MockThermalCondition1.is_match.call_count == 1 + assert MockThermalCondition2.is_match.call_count == 1 + assert MockThermalAction1.execute.call_count == 0 + assert MockThermalAction2.execute.call_count == 1 + + MockThermalInfo.collect.reset_mock() + MockThermalCondition1.is_match.reset_mock() + MockThermalCondition2.is_match.reset_mock() + tmb.ThermalManagerBase.stop() + tmb.ThermalManagerBase.run_policy(chassis) + assert MockThermalInfo.collect.call_count == 0 + assert MockThermalCondition1.is_match.call_count == 0 + assert MockThermalCondition2.is_match.call_count == 0 + + tmb.ThermalManagerBase._collect_thermal_information = mock.MagicMock() + tmb.ThermalManagerBase.run_policy(chassis) + assert MockThermalCondition1.is_match.call_count == 0 + assert MockThermalCondition2.is_match.call_count == 0 diff --git a/tests/thermal_policy.json b/tests/thermal_policy.json new file mode 100644 index 000000000000..38a62f61205b --- /dev/null +++ b/tests/thermal_policy.json @@ -0,0 +1,41 @@ +{ + "thermal_control_algorithm": { + "run_at_boot_up": "true", + "fan_speed_when_suspend": "60" + }, + "info_types": [ + { + "type": "some_info" + } + ], + "policies": [ + { + "name": "policy1", + "conditions": [ + { + "type": "condition1" + } + ], + "actions": [ + { + "type": "action1", + "speed": "100" + } + ] + }, + { + "name": "policy2", + "conditions": [ + { + "type": "condition2" + } + ], + "actions": [ + { + "type": "action2", + "enable": "False" + } + ] + } + ] +} \ No newline at end of file