-
Notifications
You must be signed in to change notification settings - Fork 0
Wait for dbus and FEATURE subscriptions #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ | |
| from health_checker.sysmonitor import Sysmonitor | ||
| from health_checker.sysmonitor import MonitorStateDbTask | ||
| from health_checker.sysmonitor import MonitorSystemBusTask | ||
| from health_checker import sysmonitor as sysmonitor_module | ||
|
|
||
| def load_source(modname, filename): | ||
| loader = importlib.machinery.SourceFileLoader(modname, filename) | ||
|
|
@@ -1148,6 +1149,7 @@ def test_monitor_sysbus_task(): | |
| assert sysmon._task_thread is not None | ||
| sysmon.task_stop() | ||
|
|
||
| @patch('health_checker.sysmonitor.Sysmonitor._wait_for_monitor_subscriptions', MagicMock()) | ||
| @patch('health_checker.sysmonitor.MonitorSystemBusTask.subscribe_sysbus', MagicMock()) | ||
| @patch('health_checker.sysmonitor.MonitorStateDbTask.subscribe_statedb', MagicMock()) | ||
| def test_system_service(): | ||
|
|
@@ -1157,6 +1159,73 @@ def test_system_service(): | |
| sysmon.task_stop() | ||
|
|
||
|
|
||
| def test_wait_for_monitor_subscriptions_completes_when_both_events_signaled(): | ||
| """_wait_for_monitor_subscriptions returns once dbus and STATE_DB listeners have signaled ready.""" | ||
| sysmon = Sysmonitor() | ||
| dbus_ready = threading.Event() | ||
| statedb_ready = threading.Event() | ||
| dbus_ready.set() | ||
| statedb_ready.set() | ||
| sysmon._wait_for_monitor_subscriptions(dbus_ready, statedb_ready) | ||
|
|
||
|
|
||
| @patch.object(sysmonitor_module, 'SUBSCRIPTION_READY_TIMEOUT_SEC', 0.05) | ||
| def test_wait_for_monitor_subscriptions_system_exit_when_dbus_not_ready(): | ||
| sysmon = Sysmonitor() | ||
| dbus_ready = threading.Event() | ||
| statedb_ready = threading.Event() | ||
| statedb_ready.set() | ||
| try: | ||
| sysmon._wait_for_monitor_subscriptions(dbus_ready, statedb_ready) | ||
| except SystemExit as exc: | ||
| assert exc.code == 1 | ||
| else: | ||
| assert False, 'expected SystemExit when dbus ready event is never set' | ||
|
|
||
|
|
||
| @patch.object(sysmonitor_module, 'SUBSCRIPTION_READY_TIMEOUT_SEC', 0.05) | ||
| def test_wait_for_monitor_subscriptions_system_exit_when_statedb_not_ready(): | ||
| sysmon = Sysmonitor() | ||
| dbus_ready = threading.Event() | ||
| statedb_ready = threading.Event() | ||
| dbus_ready.set() | ||
| try: | ||
| sysmon._wait_for_monitor_subscriptions(dbus_ready, statedb_ready) | ||
| except SystemExit as exc: | ||
| assert exc.code == 1 | ||
| else: | ||
| assert False, 'expected SystemExit when STATE_DB ready event is never set' | ||
|
|
||
|
|
||
| def test_monitor_statedb_subscribe_sets_subscription_ready_event(): | ||
| """FEATURE subscriber sets subscription_ready after SubscriberStateTable is registered.""" | ||
| ready = threading.Event() | ||
| task = MonitorStateDbTask(myQ, subscription_ready=ready) | ||
| task.task_stopping_event.set() | ||
| with patch('health_checker.sysmonitor.swsscommon.DBConnector', MagicMock()), \ | ||
| patch('health_checker.sysmonitor.swsscommon.SubscriberStateTable', MagicMock(return_value=MagicMock())), \ | ||
| patch('health_checker.sysmonitor.swsscommon.Select', MagicMock(return_value=MagicMock())): | ||
| task.subscribe_statedb() | ||
| assert ready.is_set() | ||
|
|
||
|
|
||
| def test_monitor_system_bus_subscribe_sets_subscription_ready_event(): | ||
| """systemd Manager Subscribe + JobRemoved hook registers before MainLoop.run(); ready is set.""" | ||
| ready = threading.Event() | ||
| task = MonitorSystemBusTask(myQ, subscription_ready=ready) | ||
| with patch('dbus.mainloop.glib.DBusGMainLoop', MagicMock()), \ | ||
| patch('dbus.SystemBus', MagicMock()), \ | ||
| patch('dbus.Interface') as mock_interface, \ | ||
| patch('gi.repository.GLib.MainLoop') as mock_main_loop: | ||
| manager = MagicMock() | ||
| mock_interface.return_value = manager | ||
| mock_main_loop.return_value.run = MagicMock() | ||
| task.subscribe_sysbus() | ||
|
Comment on lines
+1216
to
+1223
|
||
| manager.Subscribe.assert_called_once() | ||
| manager.connect_to_signal.assert_called_once_with('JobRemoved', task.on_job_removed) | ||
| assert ready.is_set() | ||
|
|
||
|
|
||
| @patch('sonic_py_common.device_info.get_device_runtime_metadata', MagicMock(return_value=device_runtime_metadata)) | ||
| def test_get_service_from_feature_table(): | ||
| sysmon = Sysmonitor() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_wait_for_monitor_subscriptions()callssys.exit(1)on timeout, butSysmonitor.system_service()runs inside the Sysmonitor worker thread (started viaSysmonitor.task_run()inscripts/healthd).sys.exit()from a non-main thread only raisesSystemExitin that thread and will not terminate the healthd process, leaving the daemon running without sysmonitor (and potentially leaving monitor threads running). Consider propagating the failure to the main thread (e.g., raise an exception thatThreadTaskBasereports, set a shared stop/fatal event thathealthdchecks and then exits, or use a process-level exit likeos._exit(1)if that’s the intended behavior).