Private
Public Access
Merge branch 'tier2/phase2_4_5_call_site_completion_20260621' into tier2/code_path_audit_20260607
This commit is contained in:
@@ -19,9 +19,23 @@ from src.commands import registry
|
||||
def test_palette_starts_hidden(live_gui: Any) -> None:
|
||||
"""On startup, the palette should be closed."""
|
||||
client = ApiHookClient()
|
||||
# Force-close the palette first: live_gui is session-scoped so other
|
||||
# tests may have left it open. The contract under test is that the
|
||||
# palette IS closable via the callback, not that it happens to be
|
||||
# closed at this moment. Resetting here makes the assertion meaningful
|
||||
# without depending on test ordering.
|
||||
client.push_event("custom_callback", {
|
||||
"callback": "_toggle_command_palette",
|
||||
"args": [],
|
||||
})
|
||||
deadline = time.time() + 2.0
|
||||
while time.time() < deadline:
|
||||
if client.get_value("show_command_palette") is False:
|
||||
break
|
||||
time.sleep(0.05)
|
||||
state = client.get_value("show_command_palette")
|
||||
assert state is not None, "show_command_palette should be a gettable field"
|
||||
assert state is False, f"Palette should start hidden, got {state}"
|
||||
assert state is False, f"Palette should be closable, got {state}"
|
||||
|
||||
|
||||
def test_palette_toggles_via_callback(live_gui: Any) -> None:
|
||||
|
||||
@@ -58,12 +58,12 @@ def test_gui2_click_hook_works(live_gui: Any) -> None:
|
||||
time.sleep(1.5)
|
||||
# Verify it was reset
|
||||
assert client.get_value('ai_input') == ""
|
||||
|
||||
def test_gui2_custom_callback_hook_works(live_gui: Any) -> None:
|
||||
"""
|
||||
|
||||
|
||||
Tests that the 'custom_callback' GUI hook is correctly implemented.
|
||||
|
||||
Tests that the 'custom_callback' GUI hook is correctly implemented.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
@@ -75,9 +75,15 @@ def test_gui2_custom_callback_hook_works(live_gui: Any) -> None:
|
||||
}
|
||||
response = client.post_gui(gui_data)
|
||||
assert response == {'status': 'queued'}
|
||||
time.sleep(1.5) # Give gui_2.py time to process its task queue
|
||||
# Assert that the file WAS created and contains the correct data
|
||||
# Poll for the callback to complete (avoids time.sleep race; per workflow anti-pattern)
|
||||
temp_workspace_file = Path('tests/artifacts/temp_callback_output.txt')
|
||||
deadline = time.time() + 10.0
|
||||
while time.time() < deadline:
|
||||
if temp_workspace_file.exists():
|
||||
content = temp_workspace_file.read_text(encoding="utf-8")
|
||||
if content == test_data:
|
||||
return
|
||||
time.sleep(0.1)
|
||||
assert temp_workspace_file.exists(), f"Custom callback was NOT executed, or file path is wrong! Expected: {temp_workspace_file}"
|
||||
with open(temp_workspace_file, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
@@ -56,7 +56,6 @@ def test_logging_e2e(e2e_setup: Any) -> None:
|
||||
assert session_dir.exists(), "New whitelisted session should have been kept"
|
||||
# Extra check: Whitelisted sessions should be kept even if old
|
||||
# Manually backdate the current session
|
||||
registry.data[session_id]['start_time'] = (datetime.now() - timedelta(days=2)).isoformat()
|
||||
registry.save_registry()
|
||||
registry.set_session_start_time(session_id, datetime.now() - timedelta(days=2))
|
||||
pruner.prune()
|
||||
assert session_dir.exists(), "Whitelisted session should be kept even if it is old and small"
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Regression test for the WebSocketServer.broadcast() runtime TypeError bug.
|
||||
|
||||
Phase 5 of any_type_componentization_20260621 changed
|
||||
WebSocketServer.broadcast(channel, payload) -> broadcast(message: WebSocketMessage)
|
||||
but did not update internal callers in src/app_controller.py + src/events.py.
|
||||
This produced worker[queue_fallback] TypeError spam on the GUI thread.
|
||||
|
||||
This test catches the regression and is reused by code_path_audit_20260607
|
||||
as a structural assertion.
|
||||
|
||||
CONVENTION: 1-space indentation. NO COMMENTS.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from src.api_hooks import WebSocketMessage, WebSocketServer
|
||||
|
||||
|
||||
class _MockApp:
|
||||
test_hooks_enabled: bool = True
|
||||
|
||||
|
||||
def _make_server() -> WebSocketServer:
|
||||
return WebSocketServer(_MockApp(), port=9001)
|
||||
|
||||
|
||||
def test_websocket_server_broadcast_signature() -> None:
|
||||
"""WebSocketServer.broadcast must accept a single WebSocketMessage argument (self + message)."""
|
||||
sig = inspect.signature(WebSocketServer.broadcast)
|
||||
params = list(sig.parameters.keys())
|
||||
assert len(params) == 2, f"expected 2 params (self + message), got {len(params)}: {params}"
|
||||
|
||||
|
||||
def test_websocket_server_broadcast_rejects_legacy_2arg_call() -> None:
|
||||
"""Calling broadcast with 2 positional args (legacy signature) must raise TypeError."""
|
||||
server = _make_server()
|
||||
raised = False
|
||||
try:
|
||||
server.broadcast("channel", {"key": "value"})
|
||||
except TypeError:
|
||||
raised = True
|
||||
assert raised, "broadcast should reject legacy 2-arg call"
|
||||
|
||||
|
||||
def test_websocket_server_broadcast_accepts_websocket_message_instance() -> None:
|
||||
"""The new signature accepts a WebSocketMessage instance (no-op when not started)."""
|
||||
server = _make_server()
|
||||
msg = WebSocketMessage(channel="test", payload={"key": "value"})
|
||||
server.broadcast(msg)
|
||||
|
||||
|
||||
def test_internal_callers_use_websocket_message_signature() -> None:
|
||||
"""Grep all internal callers of broadcast() in src/ and assert they use the new signature."""
|
||||
src_root = Path(__file__).resolve().parents[1] / "src"
|
||||
legacy_sites: list[str] = []
|
||||
for py_file in src_root.rglob("*.py"):
|
||||
text = py_file.read_text(encoding="utf-8")
|
||||
for lineno, line in enumerate(text.splitlines(), start=1):
|
||||
if ".broadcast(" not in line:
|
||||
continue
|
||||
if "WebSocketMessage(" in line:
|
||||
continue
|
||||
if 'broadcast("' not in line and "broadcast('" not in line:
|
||||
continue
|
||||
rel = py_file.relative_to(src_root.parent)
|
||||
legacy_sites.append(f"{rel}:{lineno}: {line.strip()}")
|
||||
assert not legacy_sites, "legacy broadcast() callers found:\n" + "\n".join(legacy_sites)
|
||||
Reference in New Issue
Block a user