tests/test_numinit_signals.py
back to source
"""Shell-floor TERM/INT handlers exist and name the halt.
Does not claim real PID-1 SIGCHLD discipline — only that the floor installs
traps and that a TERM kills the process with the documented message.
"""
import os
import shutil
import subprocess
import unittest
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
NUMINIT = os.path.join(ROOT, "boot", "numinit.sh").replace("\\", "/")
def _bash():
found = shutil.which("bash")
if found:
return found
for candidate in (
r"C:\Program Files\Git\bin\bash.exe",
r"C:\Program Files\Git\usr\bin\bash.exe",
"/usr/bin/bash",
"/bin/bash"):
if os.path.isfile(candidate):
return candidate
raise unittest.SkipTest("bash not found")
class TestSignalFloor(unittest.TestCase):
def test_source_installs_term_and_int_traps(self):
full = (
'NUMOS_SOURCE_ONLY=1 . "%s"; '
'trap -p TERM; trap -p INT'
) % NUMINIT
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
# Sourcing with SOURCE_ONLY does not install traps (by design — they
# wrap main). Assert the handler functions exist instead.
full = (
'NUMOS_SOURCE_ONLY=1 . "%s"; '
'type numos_on_term; type numos_on_int'
) % NUMINIT
proc = subprocess.run(
[_bash(), "-c", full], capture_output=True, text=True, env=env)
self.assertEqual(proc.returncode, 0, proc.stderr)
self.assertIn("numos_on_term", proc.stdout)
self.assertIn("numos_on_int", proc.stdout)
def test_term_handler_prints_named_halt_and_exits(self):
# Invoke the handler body directly. Delivering real SIGTERM through
# Git Bash on Windows is platform-noise; residual #2 still names that
# the shell floor is not static-binary PID-1 discipline.
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; numos_on_term' % NUMINIT
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
proc = subprocess.run(
[_bash(), "-c", full], capture_output=True, text=True, env=env,
timeout=15)
self.assertEqual(proc.returncode, 143)
self.assertIn("numos: HALT: received SIGTERM", proc.stderr)
def test_int_handler_prints_named_halt_and_exits(self):
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; numos_on_int' % NUMINIT
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
proc = subprocess.run(
[_bash(), "-c", full], capture_output=True, text=True, env=env,
timeout=15)
self.assertEqual(proc.returncode, 130)
self.assertIn("numos: HALT: received SIGINT", proc.stderr)
if __name__ == "__main__":
unittest.main()