Files
a433c483c1 fix: document bootstrap entrypoints in examples (fixes #71) (#96)
* 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]>
2026-06-15 16:36:35 +01:00

103 lines
3.3 KiB
Python

"""Tests for validators."""
from praisonaiui.schema.models import (
ComponentConfig,
Config,
ContentConfig,
ContentSourceConfig,
RouteConfig,
SiteConfig,
SlotRef,
TemplateConfig,
)
from praisonaiui.schema.validators import ValidationError, ValidationResult, validate_config
class TestValidationResult:
"""Tests for ValidationResult."""
def test_success(self):
"""Test successful validation result."""
result = ValidationResult.success()
assert result.valid is True
assert result.errors == []
def test_failure(self):
"""Test failed validation result."""
errors = [
ValidationError(code=2001, category="validation", message="Test error")
]
result = ValidationResult.failure(errors)
assert result.valid is False
assert len(result.errors) == 1
class TestValidateConfig:
"""Tests for validate_config function."""
def test_valid_config(self, tmp_path):
"""Test validation of a valid config."""
# Create docs directory
docs_dir = tmp_path / "docs"
docs_dir.mkdir()
config = Config(
site=SiteConfig(title="Test"),
content=ContentConfig(docs=ContentSourceConfig(dir="./docs")),
components={"header": ComponentConfig(type="Header", props={})},
templates={
"docs": TemplateConfig(
layout="Default",
slots={"header": SlotRef(ref="header")},
)
},
routes=[RouteConfig(match="/docs/**", template="docs")],
)
result = validate_config(config, tmp_path)
assert result.valid is True
def test_invalid_component_ref(self):
"""Test validation catches invalid component reference."""
config = Config(
site=SiteConfig(title="Test"),
templates={
"docs": TemplateConfig(
layout="Default",
slots={"header": SlotRef(ref="nonexistent")},
)
},
routes=[RouteConfig(match="/docs/**", template="docs")],
)
result = validate_config(config)
assert result.valid is False
assert any(e.code == 2001 for e in result.errors)
def test_invalid_template_ref(self):
"""Test validation catches invalid template reference in routes."""
config = Config(
site=SiteConfig(title="Test"),
templates={"docs": TemplateConfig(layout="Default", slots={})},
routes=[RouteConfig(match="/docs/**", template="nonexistent")],
)
result = validate_config(config)
assert result.valid is False
assert any(e.code == 2002 for e in result.errors)
def test_missing_docs_dir(self, tmp_path):
"""Test validation catches missing docs directory."""
config = Config(
site=SiteConfig(title="Test"),
content=ContentConfig(docs=ContentSourceConfig(dir="./missing")),
templates={"docs": TemplateConfig(layout="Default", slots={})},
routes=[RouteConfig(match="/docs/**", template="docs")],
)
result = validate_config(config, tmp_path)
assert result.valid is False
assert any(e.code == 3001 for e in result.errors)