fix: address reviewer feedback

- Generalize docstring references to avoid maintenance overhead
- Improve test coverage for argv restoration by using discriminating values

Co-authored-by: Mervin Praison <[email protected]>
This commit is contained in:
praisonai-triage-agent[bot]andMervin Praison committed 2026-04-28 12:17:26 +00:00
1 parent c276c5baab
commit 79eec46776
3 files changed
+71 -4

No files matched your search

+2 -2
View File
@@ -27,7 +27,7 @@ class _BackgroundLoop:
The thread is marked ``daemon=True`` so that short-lived scripts
(e.g. CLI commands, smoke tests) exit cleanly without waiting on
the background loop to be shut down explicitly. Long-running
servers (gateway, a2u, mcp_server) should call :func:`shutdown`
server processes should call :func:`shutdown`
explicitly to cancel in-flight tasks before process exit.
"""
if self._loop is None or self._loop.is_closed():
@@ -110,5 +110,5 @@ def run_sync(coro: Awaitable[T], *, timeout: float | None = _DEFAULT_TIMEOUT) ->
def shutdown() -> None:
"""Public hook for servers (gateway, a2u, mcp_server) to stop the bridge cleanly."""
"""Public hook for long-running server processes to stop the bridge cleanly."""
_BG.shutdown()
@@ -154,7 +154,8 @@ class TestLegacyRouting(unittest.TestCase):
self.assertEqual(cm.exception.code, 1)
def test_legacy_path_restores_argv(self):
original = ["praisonai", "Topic prompt"]
# Use different argv to test that restoration actually happens
original = ["praisonai", "Build weather app", "--extra-arg"]
sys.argv = list(original)
fake = mock.MagicMock()
fake.main.return_value = None
@@ -203,7 +204,8 @@ class TestTyperRouting(unittest.TestCase):
legacy.assert_not_called()
def test_typer_path_restores_argv(self):
original = ["praisonai", "chat"]
# Use different argv to test that restoration actually happens
original = ["praisonai", "chat", "--model", "gpt-4"]
sys.argv = list(original)
with mock.patch("praisonai.cli.app.app"), \
mock.patch("praisonai.cli.app.register_commands"):
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Smoke test for async bridge daemon thread fix."""
import asyncio
import time
import threading
from src.praisonai.praisonai._async_bridge import run_sync, _BG
async def test_coro(value: int) -> int:
"""Simple test coroutine."""
await asyncio.sleep(0.001) # Brief sleep to exercise the async machinery
return value * 2
def test_daemon_thread_fix():
"""Verify that daemon threads allow clean exit."""
print("[smoke] === STEP 1: run_sync from sync context ===")
result = run_sync(test_coro(21))
assert result == 42, f"Expected 42, got {result}"
print(f" result={result}")
def test_runtime_error_guard():
"""Verify that run_sync raises RuntimeError when called from async context."""
print("[smoke] === STEP 2: run_sync inside running loop ===")
async def nested_call():
try:
run_sync(test_coro(1))
return False # Should not reach here
except RuntimeError:
return True # Expected behavior
result = run_sync(nested_call())
assert result is True, "run_sync should raise RuntimeError from async context"
print(" OK raised RuntimeError")
def test_thread_properties():
"""Verify the background thread is properly configured as daemon."""
print("[smoke] === STEP 3: thread daemon property ===")
# Force thread creation
run_sync(test_coro(1))
# Check thread properties
assert _BG._thread is not None, "Background thread should exist"
assert _BG._thread.daemon is True, "Background thread should be daemon"
assert _BG._thread.is_alive(), "Background thread should be alive"
print(" daemon=True ✓")
def main():
"""Run all smoke tests."""
print("[smoke] === ASYNC BRIDGE SMOKE TEST ===")
try:
test_daemon_thread_fix()
test_runtime_error_guard()
test_thread_properties()
print("[smoke] === ALL SMOKE STEPS PASSED ===")
return True
except Exception as e:
print(f"[smoke] === FAILED: {e} ===")
return False
if __name__ == "__main__":
success = main()
exit(0 if success else 1)