""" Tests for the Hook system (HookManager, HookEvent). """ import os import pytest from hooks.hooks import HookEvent, HookEntry, HookManager # --------------------------------------------------------------------------- # Fixtures # --------------------------------------------------------------------------- @pytest.fixture def workspace(tmp_path): return str(tmp_path) @pytest.fixture def manager(workspace): return HookManager(workspace_dir=workspace) def _create_hook(workspace, name, events, enabled=True, handler_code=None): """Helper to create a hook directory with HOOK.md and optional handler.py.""" hook_dir = os.path.join(workspace, "hooks", name) os.makedirs(hook_dir, exist_ok=True) enabled_str = "true" if enabled else "false" events_str = "[" + ", ".join(events) + "]" hook_md = f"""--- name: {name} description: Test hook {name} events: {events_str} enabled: {enabled_str} --- # {name} Test hook documentation. """ with open(os.path.join(hook_dir, "HOOK.md"), "w") as f: f.write(hook_md) if handler_code: with open(os.path.join(hook_dir, "handler.py"), "w") as f: f.write(handler_code) # --------------------------------------------------------------------------- # Tests: HookEvent # --------------------------------------------------------------------------- class TestHookEvent: def test_event_key(self): event = HookEvent(type="gateway", action="startup") assert event.event_key == "gateway:startup" def test_messages_default_empty(self): event = HookEvent(type="command", action="new") assert event.messages == [] # --------------------------------------------------------------------------- # Tests: HookManager discovery # --------------------------------------------------------------------------- class TestHookManagerDiscovery: def test_discover_empty_workspace(self, manager): hooks = manager.discover() assert hooks == [] def test_discover_finds_hooks(self, workspace, manager): _create_hook(workspace, "my-hook", ["gateway:startup"]) hooks = manager.discover() assert len(hooks) == 1 assert hooks[0].name == "my-hook" assert hooks[0].events == ["gateway:startup"] def test_discover_skips_disabled(self, workspace, manager): _create_hook(workspace, "disabled-hook", ["gateway:startup"], enabled=False) hooks = manager.discover() assert len(hooks) == 0 def test_discover_multiple_hooks(self, workspace, manager): _create_hook(workspace, "hook-a", ["gateway:startup"]) _create_hook(workspace, "hook-b", ["command:new"]) hooks = manager.discover() assert len(hooks) == 2 def test_discover_multiple_events(self, workspace, manager): _create_hook(workspace, "multi", ["gateway:startup", "command:new"]) hooks = manager.discover() assert hooks[0].events == ["gateway:startup", "command:new"] # --------------------------------------------------------------------------- # Tests: HookManager trigger # --------------------------------------------------------------------------- class TestHookManagerTrigger: def test_trigger_calls_handler(self, workspace, manager): handler_code = """ results = [] def handle(event): results.append(event.event_key) """ _create_hook(workspace, "test-hook", ["gateway:startup"], handler_code=handler_code) manager.discover() event = HookEvent(type="gateway", action="startup") manager.trigger(event) # Handler was called without error — that's the test def test_trigger_no_matching_hooks(self, manager): event = HookEvent(type="gateway", action="startup") messages = manager.trigger(event) assert messages == [] def test_trigger_handler_error_doesnt_crash(self, workspace, manager): handler_code = """ def handle(event): raise RuntimeError("boom") """ _create_hook(workspace, "bad-hook", ["gateway:startup"], handler_code=handler_code) manager.discover() event = HookEvent(type="gateway", action="startup") # Should not raise manager.trigger(event) def test_trigger_messages(self, workspace, manager): handler_code = """ def handle(event): event.messages.append("hello from hook") """ _create_hook(workspace, "msg-hook", ["gateway:startup"], handler_code=handler_code) manager.discover() event = HookEvent(type="gateway", action="startup") messages = manager.trigger(event) assert "hello from hook" in messages # --------------------------------------------------------------------------- # Tests: Programmatic hooks # --------------------------------------------------------------------------- class TestProgrammaticHooks: def test_register_and_trigger(self, manager): received = [] manager.register("gateway:startup", lambda e: received.append(e.event_key)) event = HookEvent(type="gateway", action="startup") manager.trigger(event) assert received == ["gateway:startup"] def test_unregister(self, manager): received = [] handler = lambda e: received.append(e.event_key) manager.register("gateway:startup", handler) manager.unregister("gateway:startup", handler) manager.trigger(HookEvent(type="gateway", action="startup")) assert received == [] def test_type_level_handler(self, manager): received = [] manager.register("gateway", lambda e: received.append(e.action)) manager.trigger(HookEvent(type="gateway", action="startup")) manager.trigger(HookEvent(type="gateway", action="shutdown")) assert received == ["startup", "shutdown"]