mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-07 05:56:17 -10:00
* feat: standardize bootstrap entrypoint to 'aiui run app.py' across examples Standardizes platform bootstrap patterns across examples per issue #71: - Update examples README table to use 'aiui run app.py' consistently - Update docstrings in examples 10, 12, 19-21 to show 'aiui run' instead of 'python app.py' - Remove fragmented bootstrap approaches (uvicorn.run, asyncio patterns) - Enforce single bootstrap SSOT as designed in CLI Co-authored-by: Mervin Praison <[email protected]> * feat: consolidate bootstrap entrypoints - auto-detect gateway apps (fixes #71) - Add bootstrap detection in CLI run command - Auto-detect gateway pattern (async main + AIUIGateway imports) - Auto-switch to praisonai backend for gateway apps - Delegate to user-defined main() when present - Remove sys.path hacks from example 14 - Update examples README to show unified aiui run entrypoint - Add BOOTSTRAP.md documentation for migration patterns Co-authored-by: Mervin Praison <[email protected]> * fix: resolve critical bootstrap entrypoint issues - Fix AST parsing bug in gateway auto-detection (cli.py:1419) - Revert background bots (email-bot, agentmail-bot) to python app.py - Revert custom UI apps (agent-dashboard) to python app.py - Update README.md to reflect correct run commands - Fix import formatting and remove unused imports These changes ensure that: 1. Gateway auto-detection works correctly by properly checking ast.alias.name 2. Background bots execute their __main__ blocks and don't start unnecessary web servers 3. Custom UI apps register their custom routes in __main__ blocks 4. Documentation matches actual working run commands 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Mervin Praison <[email protected]> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Mervin Praison <[email protected]> Co-authored-by: Mervin Praison <[email protected]> Co-authored-by: Cursor <[email protected]>
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
"""Tests for the `aiui doctor` CLI command."""
|
|
import json
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from praisonaiui.cli import app
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
class TestDoctorCLI:
|
|
"""Unit tests for the doctor CLI command."""
|
|
|
|
def test_doctor_help(self):
|
|
"""Doctor command help text is accessible."""
|
|
result = runner.invoke(app, ["doctor", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "diagnostic" in result.output.lower()
|
|
|
|
def test_doctor_server_unreachable(self):
|
|
"""Doctor handles unreachable server gracefully."""
|
|
result = runner.invoke(app, ["doctor", "--server", "http://localhost:19999"])
|
|
# Should not crash, all checks should show as failed
|
|
assert "fail" in result.output.lower() or "Server Health" in result.output
|
|
|
|
def test_doctor_json_output(self):
|
|
"""Doctor --json produces valid JSON."""
|
|
result = runner.invoke(
|
|
app, ["doctor", "--server", "http://localhost:19999", "--json"]
|
|
)
|
|
# Parse the JSON output
|
|
data = json.loads(result.output)
|
|
assert "checks" in data
|
|
assert "summary" in data
|
|
assert isinstance(data["checks"], list)
|
|
assert "passed" in data["summary"]
|
|
assert "warnings" in data["summary"]
|
|
assert "failed" in data["summary"]
|
|
|
|
def test_doctor_all_checks_present(self):
|
|
"""Doctor output includes all 7 checks."""
|
|
result = runner.invoke(app, ["doctor", "--server", "http://localhost:19999"])
|
|
# All checks should appear even if failed
|
|
expected_checks = [
|
|
"Server Health",
|
|
"Provider",
|
|
"Gateway",
|
|
"Features",
|
|
"Config",
|
|
"Datastore",
|
|
"Channels",
|
|
]
|
|
output_lower = result.output.lower()
|
|
for check in expected_checks:
|
|
assert check.lower() in output_lower, f"Missing check: {check}"
|
|
|
|
def test_doctor_json_has_seven_checks(self):
|
|
"""Doctor --json returns exactly 7 checks."""
|
|
result = runner.invoke(
|
|
app, ["doctor", "--server", "http://localhost:19999", "--json"]
|
|
)
|
|
data = json.loads(result.output)
|
|
assert len(data["checks"]) == 7, f"Expected 7 checks, got {len(data['checks'])}"
|
|
|
|
def test_doctor_summary_counts(self):
|
|
"""Doctor --json summary counts are correct."""
|
|
result = runner.invoke(
|
|
app, ["doctor", "--server", "http://localhost:19999", "--json"]
|
|
)
|
|
data = json.loads(result.output)
|
|
summary = data["summary"]
|
|
total = summary["passed"] + summary["warnings"] + summary["failed"]
|
|
assert total == 7, f"Summary counts should total 7, got {total}"
|
|
|
|
def test_doctor_check_structure(self):
|
|
"""Each check in --json output has required fields."""
|
|
result = runner.invoke(
|
|
app, ["doctor", "--server", "http://localhost:19999", "--json"]
|
|
)
|
|
data = json.loads(result.output)
|
|
for check in data["checks"]:
|
|
assert "name" in check, "Check missing 'name' field"
|
|
assert "status" in check, "Check missing 'status' field"
|
|
assert "detail" in check, "Check missing 'detail' field"
|
|
assert check["status"] in ("pass", "warn", "fail"), f"Invalid status: {check['status']}"
|