import importlib.util import json from pathlib import Path from types import SimpleNamespace import unittest spec = importlib.util.spec_from_file_location('observe', Path(__file__).resolve().parents[1]/'tools/observe_host_clock.py') module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) class ObservationTests(unittest.TestCase): def response(self, code=0, text='NTPSynchronized=yes\n'): return SimpleNamespace(returncode=0, stdout=json.dumps({'commands': {'clock': {'returncode':code,'stdout':text}}})) def test_reported_sync_is_not_accuracy_or_authority(self): result=module.observe('railiance01', runner=lambda *a, **k:self.response()) self.assertTrue(result['synchronized_reported']) self.assertIsNone(result['authority_usable']) def test_failed_clock_command_remains_unknown(self): result=module.observe('railiance01',runner=lambda *a, **k:self.response(1)) self.assertIsNone(result['synchronized_reported']) def test_missing_sync_property_remains_unknown(self): result=module.observe('railiance01',runner=lambda *a, **k:self.response(0, '')) self.assertIsNone(result['synchronized_reported']) def test_ssh_failure_refuses_success_without_echoing_stderr(self): with self.assertRaisesRegex(ValueError,'SSH inventory failed'): module.observe('railiance01',runner=lambda *a, **k:SimpleNamespace(returncode=255,stderr='not-for-evidence')) def test_host_cannot_inject_options_or_shell(self): for host in ['-oProxyCommand=bad','host;bad','host bad','$(bad)']: with self.subTest(host=host), self.assertRaises(ValueError): module.observe(host,runner=lambda *a, **k:self.fail('network called')) def test_transport_uses_fixed_read_only_script(self): def run(argv, **kwargs): self.assertEqual(argv[-2:], ['railiance01','python3 -']) self.assertEqual(kwargs['input'],module.REMOTE) self.assertNotIn('shell',kwargs) return self.response() module.observe('railiance01',runner=run)