Skip to content

Commit 2a0f803

Browse files
authored
Improved unit test coverage of mig lib daemon (#367)
* Use a shared `before_each` init to isolate test configuration etc. Add coverage of several previously missing branches and corner cases. - Direct event helper testing - Signal handler verification - Concurrent event handling - Nap timing accuracy checks - Multiple reset cycles - Error cases like invalid arguments - Various sleep interruption scenarios * Implement a new helper to unregister all registered signals and use it in unit tests to increase isolation and be able to test handling when no handlers where registered. * Added unit test coverage: - Immediate sleep exit with max_secs < nap_secs - Positional argument handling - Negative max_secs handling - Zero max_secs handling - Unregistered signal safety - Consecutive signal handling - Verify explicit unregistration of signal handlers - Test sleep terminating after a condition becomes true - Edge case test for equal max/sleep durations - Test error handling when break conditions raise exceptions - Direct tests of state reset and setting helpers - Integration test with real signal delivery * Switch dummy conf and logger to the default ones from `_provide_configuration`. Move used_signal accounting to class-level. Perhaps we want to maintain it on actual use and add helpers to track active ones eventually. * Address the review comment on PR367 about the edge cases not really being verified by inserting missing `assert`s. * Adjust conflicting handler test to behave as expected with only the last handler assigned being active. * Increase test coverage to 100% with more corner case tests of sleep intervals, unregister, etc. * Remove useless and unused result from `interruptible_sleep`, also called out by pylint.
1 parent 083770f commit 2a0f803

File tree

2 files changed

+512
-29
lines changed

2 files changed

+512
-29
lines changed

mig/lib/daemon.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,23 @@ def register_run_handler(configuration, run_signal=signal.SIGCONT):
6868
signal.signal(run_signal, run_handler)
6969

7070

71+
def unregister_signal_handlers(configuration, target_signals=None):
72+
"""Remove any handlers registered to react on provided target_signals list.
73+
Default to SIGCONT, SIGUSR1 and SIGUSR2 if target_signals is left to None.
74+
"""
75+
if target_signals is None:
76+
target_signals = [signal.SIGCONT, signal.SIGUSR1, signal.SIGUSR2]
77+
for target in target_signals:
78+
original_handler = signal.getsignal(target)
79+
if original_handler:
80+
signal.signal(target, signal.SIG_IGN)
81+
82+
7183
def interruptible_sleep(configuration, max_secs, break_checks, nap_secs=0.1):
7284
"""Idle loop for max_secs or until one or more break_checks succeed"""
73-
assert max_secs >= nap_secs, "Invalid max_secs value smaller than nap_secs"
85+
assert nap_secs > 0.0, "Invalid non-positive nap_secs value"
86+
if max_secs < nap_secs:
87+
return
7488
for _ in range(int(max_secs / nap_secs)):
7589
for check in break_checks:
7690
if check():

0 commit comments

Comments
 (0)