This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
sonic-buildimage/src/system-health/tests/test_system_health.py
Junchao-Mellanox bb41b55f1a [system-health] Make check interval more accurate (#14085)
- Why I did it

Healthd check system status every 60 seconds. However, running checker may take several seconds. Say checker takes X seconds, healthd takes (60 + X) seconds to finish one iteration. This implementation makes sonic-mgmt test case not so stable because the value X is hard to predict and different among different platforms. This PR introduces an interval
compensation mechanism to healthd main loop.

- How I did it

Introduces an interval compensation mechanism to healthd main loop: healthd should wait (60 - X) seconds for next iteration

- How to verify it

Manual test
Unit test
2023-03-19 22:32:43 +08:00

804 lines
31 KiB
Python

"""
Unit test cases for system health checker. The current test case contains:
1. test_user_defined_checker mocks the output of a user defined checker and verify class UserDefinedChecker
2. test_service_checker mocks the output of monit service and verify class ServiceChecker
3. test_hardware_checker mocks the hardware status data in db and verify class HardwareChecker
4. Mocks and tests the system ready status and verify class Sysmonitor
And there are class that are not covered by unit test. These class will be covered by sonic-mgmt regression test.
1. HealthDaemon
2. HealthCheckerManager
3. Config
"""
import copy
import os
import sys
from imp import load_source
from swsscommon import swsscommon
from mock import Mock, MagicMock, patch
from sonic_py_common import device_info
from .mock_connector import MockConnector
swsscommon.SonicV2Connector = MockConnector
test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, 'scripts')
sys.path.insert(0, modules_path)
sys.path.insert(0, scripts_path)
from health_checker import utils
from health_checker.config import Config
from health_checker.hardware_checker import HardwareChecker
from health_checker.health_checker import HealthChecker
from health_checker.manager import HealthCheckerManager
from health_checker.service_checker import ServiceChecker
from health_checker.user_defined_checker import UserDefinedChecker
from health_checker.sysmonitor import Sysmonitor
from health_checker.sysmonitor import MonitorStateDbTask
from health_checker.sysmonitor import MonitorSystemBusTask
load_source('healthd', os.path.join(scripts_path, 'healthd'))
from healthd import HealthDaemon
mock_supervisorctl_output = """
snmpd RUNNING pid 67, uptime 1:03:56
snmp-subagent EXITED Oct 19 01:53 AM
"""
device_info.get_platform = MagicMock(return_value='unittest')
def setup():
if os.path.exists(ServiceChecker.CRITICAL_PROCESS_CACHE):
os.remove(ServiceChecker.CRITICAL_PROCESS_CACHE)
@patch('health_checker.utils.run_command')
def test_user_defined_checker(mock_run):
mock_run.return_value = ''
checker = UserDefinedChecker('')
checker.check(None)
assert checker._info[str(checker)][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
checker.reset()
assert len(checker._info) == 0
mock_run.return_value = '\n\n\n'
checker.check(None)
assert checker._info[str(checker)][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
valid_output = 'MyCategory\nDevice1:OK\nDevice2:Device2 is broken\n'
mock_run.return_value = valid_output
checker.check(None)
assert checker.get_category() == 'MyCategory'
assert 'Device1' in checker._info
assert 'Device2' in checker._info
assert checker._info['Device1'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert checker._info['Device2'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('health_checker.service_checker.ServiceChecker._get_container_folder', MagicMock(return_value=test_path))
@patch('sonic_py_common.multi_asic.is_multi_asic', MagicMock(return_value=False))
@patch('docker.DockerClient')
@patch('health_checker.utils.run_command')
@patch('swsscommon.swsscommon.ConfigDBConnector')
def test_service_checker_single_asic(mock_config_db, mock_run, mock_docker_client):
mock_db_data = MagicMock()
mock_get_table = MagicMock()
mock_db_data.get_table = mock_get_table
mock_config_db.return_value = mock_db_data
mock_get_table.return_value = {
'snmp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
}
}
mock_containers = MagicMock()
mock_snmp_container = MagicMock()
mock_snmp_container.name = 'snmp'
mock_containers.list = MagicMock(return_value=[mock_snmp_container])
mock_docker_client_object = MagicMock()
mock_docker_client.return_value = mock_docker_client_object
mock_docker_client_object.containers = mock_containers
mock_run.return_value = mock_supervisorctl_output
checker = ServiceChecker()
assert checker.get_category() == 'Services'
config = Config()
checker.check(config)
assert 'snmp:snmpd' in checker._info
assert checker._info['snmp:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'snmp:snmp-subagent' in checker._info
assert checker._info['snmp:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
mock_get_table.return_value = {
'new_service': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
},
'snmp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
}
}
mock_ns_container = MagicMock()
mock_ns_container.name = 'new_service'
mock_containers.list = MagicMock(return_value=[mock_snmp_container, mock_ns_container])
checker.check(config)
assert 'new_service' in checker.container_critical_processes
assert 'new_service:snmpd' in checker._info
assert checker._info['new_service:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'new_service:snmp-subagent' in checker._info
assert checker._info['new_service:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
mock_containers.list = MagicMock(return_value=[mock_snmp_container])
checker.check(config)
assert 'new_service' in checker._info
assert checker._info['new_service'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
mock_containers.list = MagicMock(return_value=[mock_snmp_container, mock_ns_container])
mock_run.return_value = None
checker.check(config)
assert 'new_service:snmpd' in checker._info
assert checker._info['new_service:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'new_service:snmp-subagent' in checker._info
assert checker._info['new_service:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
origin_container_critical_processes = copy.deepcopy(checker.container_critical_processes)
checker.save_critical_process_cache()
checker.load_critical_process_cache()
assert origin_container_critical_processes == checker.container_critical_processes
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('health_checker.service_checker.ServiceChecker._get_container_folder', MagicMock(return_value=test_path))
@patch('health_checker.utils.run_command', MagicMock(return_value=mock_supervisorctl_output))
@patch('sonic_py_common.multi_asic.get_num_asics', MagicMock(return_value=3))
@patch('sonic_py_common.multi_asic.is_multi_asic', MagicMock(return_value=True))
@patch('sonic_py_common.multi_asic.get_namespace_list', MagicMock(return_value=[str(x) for x in range(3)]))
@patch('sonic_py_common.multi_asic.get_current_namespace', MagicMock(return_value=''))
@patch('docker.DockerClient')
@patch('swsscommon.swsscommon.ConfigDBConnector')
def test_service_checker_multi_asic(mock_config_db, mock_docker_client):
mock_db_data = MagicMock()
mock_db_data.get_table = MagicMock()
mock_config_db.return_value = mock_db_data
mock_db_data.get_table.return_value = {
'snmp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'True',
}
}
mock_containers = MagicMock()
mock_snmp_container = MagicMock()
mock_snmp_container.name = 'snmp'
list_return_value = [mock_snmp_container]
for i in range(3):
mock_container = MagicMock()
mock_container.name = 'snmp' + str(i)
list_return_value.append(mock_container)
mock_containers.list = MagicMock(return_value=list_return_value)
mock_docker_client_object = MagicMock()
mock_docker_client.return_value = mock_docker_client_object
mock_docker_client_object.containers = mock_containers
checker = ServiceChecker()
config = Config()
checker.check(config)
assert 'snmp' in checker.container_critical_processes
assert 'snmp:snmpd' in checker._info
assert checker._info['snmp:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'snmp0:snmpd' in checker._info
assert checker._info['snmp0:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'snmp1:snmpd' in checker._info
assert checker._info['snmp1:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'snmp2:snmpd' in checker._info
assert checker._info['snmp2:snmpd'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'snmp:snmp-subagent' in checker._info
assert checker._info['snmp:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'snmp0:snmp-subagent' in checker._info
assert checker._info['snmp0:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'snmp1:snmp-subagent' in checker._info
assert checker._info['snmp1:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'snmp2:snmp-subagent' in checker._info
assert checker._info['snmp2:snmp-subagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
@patch('swsscommon.swsscommon.ConfigDBConnector', MagicMock())
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('health_checker.service_checker.ServiceChecker.check_by_monit', MagicMock())
@patch('docker.DockerClient')
@patch('swsscommon.swsscommon.ConfigDBConnector.get_table')
def test_service_checker_no_critical_process(mock_get_table, mock_docker_client):
mock_get_table.return_value = {
'snmp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'True',
}
}
mock_containers = MagicMock()
mock_containers.list = MagicMock(return_value=[])
mock_docker_client_object = MagicMock()
mock_docker_client.return_value = mock_docker_client_object
mock_docker_client_object.containers = mock_containers
checker = ServiceChecker()
config = Config()
checker.check(config)
assert 'system' in checker._info
assert checker._info['system'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
@patch('health_checker.service_checker.ServiceChecker.check_services', MagicMock())
@patch('health_checker.utils.run_command')
def test_service_checker_check_by_monit(mock_run):
return_value = 'Monit 5.20.0 uptime: 3h 54m\n' \
'Service Name Status Type\n' \
'sonic Running System\n' \
'sonic1 Not running System\n' \
'telemetry Does not exist Process\n' \
'orchagent Running Process\n' \
'root-overlay Accessible Filesystem\n' \
'var-log Is not accessible Filesystem\n'
mock_run.side_effect = ['active', return_value]
checker = ServiceChecker()
config = Config()
checker.check(config)
assert 'sonic' in checker._info
assert checker._info['sonic'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'sonic1' in checker._info
assert checker._info['sonic1'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'orchagent' in checker._info
assert checker._info['orchagent'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'telemetry' in checker._info
assert checker._info['telemetry'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'root-overlay' in checker._info
assert checker._info['root-overlay'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'var-log' in checker._info
assert checker._info['var-log'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
def test_hardware_checker():
MockConnector.data.update({
'TEMPERATURE_INFO|ASIC': {
'temperature': '20',
'high_threshold': '21'
}
})
MockConnector.data.update({
'FAN_INFO|fan1': {
'presence': 'True',
'status': 'True',
'speed': '60',
'speed_target': '60',
'speed_tolerance': '20'
},
'FAN_INFO|fan2': {
'presence': 'False',
'status': 'True',
'speed': '60',
'speed_target': '60',
'speed_tolerance': '20'
},
'FAN_INFO|fan3': {
'presence': 'True',
'status': 'False',
'speed': '60',
'speed_target': '60',
'speed_tolerance': '20'
},
'FAN_INFO|fan4': {
'presence': 'True',
'status': 'True',
'speed': '20',
'speed_target': '60',
'speed_tolerance': '20'
}
})
MockConnector.data.update({
'PSU_INFO|PSU 1': {
'presence': 'True',
'status': 'True',
'temp': '55',
'temp_threshold': '100',
'voltage': '10',
'voltage_min_threshold': '8',
'voltage_max_threshold': '15',
},
'PSU_INFO|PSU 2': {
'presence': 'False',
'status': 'True',
'temp': '55',
'temp_threshold': '100',
'voltage': '10',
'voltage_min_threshold': '8',
'voltage_max_threshold': '15',
},
'PSU_INFO|PSU 3': {
'presence': 'True',
'status': 'False',
'temp': '55',
'temp_threshold': '100',
'voltage': '10',
'voltage_min_threshold': '8',
'voltage_max_threshold': '15',
},
'PSU_INFO|PSU 4': {
'presence': 'True',
'status': 'True',
'temp': '101',
'temp_threshold': '100',
'voltage': '10',
'voltage_min_threshold': '8',
'voltage_max_threshold': '15',
},
'PSU_INFO|PSU 5': {
'presence': 'True',
'status': 'True',
'temp': '55',
'temp_threshold': '100',
'voltage': '10',
'voltage_min_threshold': '12',
'voltage_max_threshold': '15',
},
'PSU_INFO|PSU 6': {
'presence': 'True',
'status': 'True',
'temp': '55',
'temp_threshold': '100',
'voltage': '12',
'voltage_min_threshold': '12',
'voltage_max_threshold': '15',
'power_overload': 'True',
'power': '101.0',
'power_critical_threshold': '100.0',
'power_warning_suppress_threshold': '90.0'
},
'PSU_INFO|PSU 7': {
'presence': 'True',
'status': 'True',
'temp': '55',
'temp_threshold': '100',
'voltage': '12',
'voltage_min_threshold': '12',
'voltage_max_threshold': '15',
'power_overload': 'True',
'power': '101.0'
}
})
checker = HardwareChecker()
assert checker.get_category() == 'Hardware'
config = Config()
checker.check(config)
assert 'ASIC' in checker._info
assert checker._info['ASIC'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'fan1' in checker._info
assert checker._info['fan1'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'fan2' in checker._info
assert checker._info['fan2'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'fan3' in checker._info
assert checker._info['fan3'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'fan4' in checker._info
assert checker._info['fan4'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 1' in checker._info
assert checker._info['PSU 1'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_OK
assert 'PSU 2' in checker._info
assert checker._info['PSU 2'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 3' in checker._info
assert checker._info['PSU 3'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 4' in checker._info
assert checker._info['PSU 4'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 5' in checker._info
assert checker._info['PSU 5'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 6' in checker._info
assert checker._info['PSU 6'][HealthChecker.INFO_FIELD_OBJECT_MSG] == 'power of PSU 6 (101.0w) exceeds threshold (100.0w)'
assert checker._info['PSU 6'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert 'PSU 7' in checker._info
assert checker._info['PSU 7'][HealthChecker.INFO_FIELD_OBJECT_STATUS] == HealthChecker.STATUS_NOT_OK
assert checker._info['PSU 7'][HealthChecker.INFO_FIELD_OBJECT_MSG] == 'power of PSU 7 exceeds threshold but power or power_critical_threshold is invalid'
def test_config():
config = Config()
config._config_file = os.path.join(test_path, Config.CONFIG_FILE)
assert config.config_file_exists()
config.load_config()
assert config.interval == 60
assert 'dummy_service' in config.ignore_services
assert 'psu.voltage' in config.ignore_devices
assert len(config.user_defined_checkers) == 0
assert config.get_led_color('fault') == 'orange'
assert config.get_led_color('normal') == 'green'
assert config.get_led_color('booting') == 'orange_blink'
assert config.get_bootup_timeout() == 300
config._reset()
assert not config.ignore_services
assert not config.ignore_devices
assert not config.user_defined_checkers
assert not config.config_data
assert config.get_led_color('fault') == 'red'
assert config.get_led_color('normal') == 'green'
assert config.get_led_color('booting') == 'orange_blink'
config._last_mtime = 1
config._config_file = 'notExistFile'
config.load_config()
assert not config._last_mtime
@patch('swsscommon.swsscommon.ConfigDBConnector', MagicMock())
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('health_checker.service_checker.ServiceChecker.check', MagicMock())
@patch('health_checker.hardware_checker.HardwareChecker.check', MagicMock())
@patch('health_checker.user_defined_checker.UserDefinedChecker.check', MagicMock())
@patch('swsscommon.swsscommon.ConfigDBConnector.get_table', MagicMock())
@patch('health_checker.user_defined_checker.UserDefinedChecker.get_category', MagicMock(return_value='UserDefine'))
@patch('health_checker.user_defined_checker.UserDefinedChecker.get_info')
@patch('health_checker.service_checker.ServiceChecker.get_info')
@patch('health_checker.hardware_checker.HardwareChecker.get_info')
def test_manager(mock_hw_info, mock_service_info, mock_udc_info):
chassis = MagicMock()
chassis.set_status_led = MagicMock()
manager = HealthCheckerManager()
manager.config.user_defined_checkers = ['some check']
assert len(manager._checkers) == 2
mock_hw_info.return_value = {
'ASIC': {
'type': 'ASIC',
'message': '',
'status': 'OK'
},
'fan1': {
'type': 'Fan',
'message': '',
'status': 'OK'
},
}
mock_service_info.return_value = {
'snmp:snmpd': {
'type': 'Process',
'message': '',
'status': 'OK'
}
}
mock_udc_info.return_value = {
'udc': {
'type': 'Database',
'message': '',
'status': 'OK'
}
}
stat = manager.check(chassis)
assert 'Services' in stat
assert stat['Services']['snmp:snmpd']['status'] == 'OK'
assert 'Hardware' in stat
assert stat['Hardware']['ASIC']['status'] == 'OK'
assert stat['Hardware']['fan1']['status'] == 'OK'
assert 'UserDefine' in stat
assert stat['UserDefine']['udc']['status'] == 'OK'
mock_hw_info.side_effect = RuntimeError()
mock_service_info.side_effect = RuntimeError()
mock_udc_info.side_effect = RuntimeError()
stat = manager.check(chassis)
assert 'Internal' in stat
assert stat['Internal']['ServiceChecker']['status'] == 'Not OK'
assert stat['Internal']['HardwareChecker']['status'] == 'Not OK'
assert stat['Internal']['UserDefinedChecker - some check']['status'] == 'Not OK'
chassis.set_status_led.side_effect = NotImplementedError()
manager._set_system_led(chassis, manager.config, 'normal')
chassis.set_status_led.side_effect = RuntimeError()
manager._set_system_led(chassis, manager.config, 'normal')
def test_utils():
output = utils.run_command('some invalid command')
assert not output
output = utils.run_command('ls')
assert output
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('sonic_py_common.multi_asic.is_multi_asic', MagicMock(return_value=False))
@patch('docker.DockerClient')
@patch('health_checker.utils.run_command')
@patch('swsscommon.swsscommon.ConfigDBConnector')
def test_get_all_service_list(mock_config_db, mock_run, mock_docker_client):
mock_db_data = MagicMock()
mock_get_table = MagicMock()
mock_db_data.get_table = mock_get_table
mock_config_db.return_value = mock_db_data
mock_get_table.return_value = {
'radv': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
},
'bgp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
},
'pmon': {
'state': 'disabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
}
}
sysmon = Sysmonitor()
print("mock get table:{}".format(mock_get_table.return_value))
result = sysmon.get_all_service_list()
print("result get all service list:{}".format(result))
assert 'radv.service' in result
assert 'pmon.service' not in result
@patch('swsscommon.swsscommon.ConfigDBConnector.connect', MagicMock())
@patch('sonic_py_common.multi_asic.is_multi_asic', MagicMock(return_value=False))
@patch('docker.DockerClient')
@patch('health_checker.utils.run_command')
@patch('swsscommon.swsscommon.ConfigDBConnector')
def test_get_app_ready_status(mock_config_db, mock_run, mock_docker_client):
mock_db_data = MagicMock()
mock_get_table = MagicMock()
mock_db_data.get_table = mock_get_table
mock_config_db.return_value = mock_db_data
mock_get_table.return_value = {
'radv': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
'check_up_status': 'True'
},
'bgp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
'check_up_status': 'True'
},
'snmp': {
'state': 'enabled',
'has_global_scope': 'True',
'has_per_asic_scope': 'False',
'check_up_status': 'False'
}
}
MockConnector.data.update({
'FEATURE|radv': {
'up_status': 'True',
'fail_reason': '-',
'update_time': '-'
},
'FEATURE|bgp': {
'up_status': 'False',
'fail_reason': 'some error',
'update_time': '-'
}})
sysmon = Sysmonitor()
result = sysmon.get_app_ready_status('radv')
print(result)
assert 'Up' in result
result = sysmon.get_app_ready_status('bgp')
print(result)
assert 'Down' in result
result = sysmon.get_app_ready_status('snmp')
print(result)
assert 'Up' in result
mock_srv_props={
'mock_radv.service':{'Type': 'simple', 'Result': 'success', 'Id': 'mock_radv.service', 'LoadState': 'loaded', 'ActiveState': 'active', 'SubState': 'running', 'UnitFileState': 'enabled'},
'mock_bgp.service':{'Type': 'simple', 'Result': 'success', 'Id': 'mock_bgp.service', 'LoadState': 'loaded', 'ActiveState': 'inactive', 'SubState': 'dead', 'UnitFileState': 'enabled'}
}
@patch('health_checker.sysmonitor.Sysmonitor.get_all_service_list', MagicMock(return_value=['mock_snmp.service', 'mock_bgp.service', 'mock_ns.service']))
@patch('health_checker.sysmonitor.Sysmonitor.run_systemctl_show', MagicMock(return_value=mock_srv_props['mock_bgp.service']))
@patch('health_checker.sysmonitor.Sysmonitor.get_app_ready_status', MagicMock(return_value=('Down','-','-')))
@patch('health_checker.sysmonitor.Sysmonitor.post_unit_status', MagicMock())
def test_check_unit_status():
sysmon = Sysmonitor()
sysmon.check_unit_status('mock_bgp.service')
assert 'mock_bgp.service' in sysmon.dnsrvs_name
@patch('health_checker.sysmonitor.Sysmonitor.run_systemctl_show', MagicMock(return_value=mock_srv_props['mock_radv.service']))
@patch('health_checker.sysmonitor.Sysmonitor.get_app_ready_status', MagicMock(return_value=('Up','-','-')))
@patch('health_checker.sysmonitor.Sysmonitor.post_unit_status', MagicMock())
def test_get_unit_status_ok():
sysmon = Sysmonitor()
result = sysmon.get_unit_status('mock_radv.service')
print("get_unit_status:{}".format(result))
assert result == 'OK'
@patch('health_checker.sysmonitor.Sysmonitor.run_systemctl_show', MagicMock(return_value=mock_srv_props['mock_bgp.service']))
@patch('health_checker.sysmonitor.Sysmonitor.get_app_ready_status', MagicMock(return_value=('Up','-','-')))
@patch('health_checker.sysmonitor.Sysmonitor.post_unit_status', MagicMock())
def test_get_unit_status_not_ok():
sysmon = Sysmonitor()
result = sysmon.get_unit_status('mock_bgp.service')
print("get_unit_status:{}".format(result))
assert result == 'NOT OK'
@patch('health_checker.sysmonitor.Sysmonitor.get_all_service_list', MagicMock(return_value=['mock_snmp.service', 'mock_ns.service']))
@patch('health_checker.sysmonitor.Sysmonitor.get_unit_status', MagicMock(return_value= 'OK'))
@patch('health_checker.sysmonitor.Sysmonitor.publish_system_status', MagicMock())
@patch('health_checker.sysmonitor.Sysmonitor.post_unit_status', MagicMock())
@patch('health_checker.sysmonitor.Sysmonitor.get_app_ready_status', MagicMock(return_value='Up'))
def test_get_all_system_status_ok():
sysmon = Sysmonitor()
result = sysmon.get_all_system_status()
print("result:{}".format(result))
assert result == 'UP'
@patch('health_checker.sysmonitor.Sysmonitor.get_all_service_list', MagicMock(return_value=['mock_snmp.service', 'mock_ns.service']))
@patch('health_checker.sysmonitor.Sysmonitor.get_unit_status', MagicMock(return_value= 'NOT OK'))
@patch('health_checker.sysmonitor.Sysmonitor.publish_system_status', MagicMock())
@patch('health_checker.sysmonitor.Sysmonitor.post_unit_status', MagicMock())
@patch('health_checker.sysmonitor.Sysmonitor.get_app_ready_status', MagicMock(return_value='Up'))
def test_get_all_system_status_not_ok():
sysmon = Sysmonitor()
result = sysmon.get_all_system_status()
print("result:{}".format(result))
assert result == 'DOWN'
def test_post_unit_status():
sysmon = Sysmonitor()
sysmon.post_unit_status("mock_bgp", 'OK', 'Down', 'mock reason', '-')
result = swsscommon.SonicV2Connector.get_all(MockConnector, 0, 'ALL_SERVICE_STATUS|mock_bgp')
print(result)
assert result['service_status'] == 'OK'
assert result['app_ready_status'] == 'Down'
assert result['fail_reason'] == 'mock reason'
def test_post_system_status():
sysmon = Sysmonitor()
sysmon.post_system_status("UP")
result = swsscommon.SonicV2Connector.get(MockConnector, 0, "SYSTEM_READY|SYSTEM_STATE", 'Status')
print("post system status result:{}".format(result))
assert result == "UP"
@patch('health_checker.sysmonitor.Sysmonitor.publish_system_status', MagicMock())
@patch('health_checker.sysmonitor.Sysmonitor.post_system_status', test_post_system_status())
@patch('health_checker.sysmonitor.Sysmonitor.print_console_message', MagicMock())
def test_publish_system_status():
sysmon = Sysmonitor()
sysmon.publish_system_status('UP')
result = swsscommon.SonicV2Connector.get(MockConnector, 0, "SYSTEM_READY|SYSTEM_STATE", 'Status')
assert result == "UP"
@patch('health_checker.sysmonitor.Sysmonitor.get_all_system_status', test_get_all_system_status_ok())
@patch('health_checker.sysmonitor.Sysmonitor.publish_system_status', test_publish_system_status())
def test_update_system_status():
sysmon = Sysmonitor()
sysmon.update_system_status()
result = swsscommon.SonicV2Connector.get(MockConnector, 0, "SYSTEM_READY|SYSTEM_STATE", 'Status')
assert result == "UP"
from sonic_py_common.task_base import ProcessTaskBase
import multiprocessing
mpmgr = multiprocessing.Manager()
myQ = mpmgr.Queue()
def test_monitor_statedb_task():
sysmon = MonitorStateDbTask(myQ)
sysmon.SubscriberStateTable = MagicMock()
sysmon.task_run()
assert sysmon._task_process is not None
sysmon.task_stop()
@patch('health_checker.sysmonitor.MonitorSystemBusTask.subscribe_sysbus', MagicMock())
def test_monitor_sysbus_task():
sysmon = MonitorSystemBusTask(myQ)
sysmon.SubscriberStateTable = MagicMock()
sysmon.task_run()
assert sysmon._task_process is not None
sysmon.task_stop()
@patch('health_checker.sysmonitor.MonitorSystemBusTask.subscribe_sysbus', MagicMock())
@patch('health_checker.sysmonitor.MonitorStateDbTask.subscribe_statedb', MagicMock())
def test_system_service():
sysmon = Sysmonitor()
sysmon.task_run()
assert sysmon._task_process is not None
sysmon.task_stop()
def test_get_service_from_feature_table():
sysmon = Sysmonitor()
sysmon.config_db = MagicMock()
sysmon.config_db.get_table = MagicMock()
sysmon.config_db.get_table.side_effect = [
{
'bgp': {},
'swss': {}
},
{
'bgp': {'state': 'enabled'},
'swss': {'state': 'disabled'}
}
]
dir_list = []
sysmon.get_service_from_feature_table(dir_list)
assert 'bgp.service' in dir_list
assert 'swss.service' not in dir_list
@patch('healthd.time.time')
def test_healthd_check_interval(mock_time):
daemon = HealthDaemon()
manager = MagicMock()
manager.check = MagicMock()
manager.config = MagicMock()
chassis = MagicMock()
daemon._process_stat = MagicMock()
daemon.stop_event = MagicMock()
daemon.stop_event.wait = MagicMock()
daemon.stop_event.wait.return_value = False
manager.config.interval = 60
mock_time.side_effect = [0, 3, 0, 61, 0, 1]
assert daemon._run_checker(manager, chassis)
daemon.stop_event.wait.assert_called_with(57)
assert daemon._run_checker(manager, chassis)
daemon.stop_event.wait.assert_called_with(1)
daemon.stop_event.wait.return_value = True
assert not daemon._run_checker(manager, chassis)