109 lines
3.0 KiB
Python
109 lines
3.0 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Shared smoke test runner for hermes-agent.
|
||
|
|
Fast checks that catch obvious breakage without maintenance burden.
|
||
|
|
|
||
|
|
Usage as CLI:
|
||
|
|
python -m devkit.smoke_test
|
||
|
|
python -m devkit.smoke_test --verbose
|
||
|
|
|
||
|
|
Usage as module:
|
||
|
|
from devkit.smoke_test import run_smoke_tests
|
||
|
|
results = run_smoke_tests()
|
||
|
|
"""
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import importlib
|
||
|
|
import json
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Any, Dict, List
|
||
|
|
|
||
|
|
|
||
|
|
HERMES_ROOT = Path(__file__).resolve().parent.parent
|
||
|
|
|
||
|
|
|
||
|
|
def _test_imports() -> Dict[str, Any]:
|
||
|
|
modules = [
|
||
|
|
"hermes_constants",
|
||
|
|
"hermes_state",
|
||
|
|
"cli",
|
||
|
|
"tools.skills_sync",
|
||
|
|
"tools.skills_hub",
|
||
|
|
]
|
||
|
|
errors = []
|
||
|
|
for mod in modules:
|
||
|
|
try:
|
||
|
|
importlib.import_module(mod)
|
||
|
|
except Exception as e:
|
||
|
|
errors.append({"module": mod, "error": str(e)})
|
||
|
|
return {
|
||
|
|
"name": "core_imports",
|
||
|
|
"status": "ok" if not errors else "fail",
|
||
|
|
"errors": errors,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def _test_cli_entrypoints() -> Dict[str, Any]:
|
||
|
|
entrypoints = [
|
||
|
|
[sys.executable, "-m", "cli", "--help"],
|
||
|
|
]
|
||
|
|
errors = []
|
||
|
|
for cmd in entrypoints:
|
||
|
|
try:
|
||
|
|
subprocess.run(cmd, capture_output=True, text=True, check=True, cwd=HERMES_ROOT)
|
||
|
|
except subprocess.CalledProcessError as e:
|
||
|
|
errors.append({"cmd": cmd, "error": f"exit {e.returncode}"})
|
||
|
|
except Exception as e:
|
||
|
|
errors.append({"cmd": cmd, "error": str(e)})
|
||
|
|
return {
|
||
|
|
"name": "cli_entrypoints",
|
||
|
|
"status": "ok" if not errors else "fail",
|
||
|
|
"errors": errors,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def _test_green_path_e2e() -> Dict[str, Any]:
|
||
|
|
"""One bare green-path E2E: terminal_tool echo hello."""
|
||
|
|
try:
|
||
|
|
from tools.terminal_tool import terminal
|
||
|
|
result = terminal(command="echo hello")
|
||
|
|
output = result.get("output", "")
|
||
|
|
if "hello" in output.lower():
|
||
|
|
return {"name": "green_path_e2e", "status": "ok", "output": output.strip()}
|
||
|
|
return {"name": "green_path_e2e", "status": "fail", "error": f"Unexpected output: {output}"}
|
||
|
|
except Exception as e:
|
||
|
|
return {"name": "green_path_e2e", "status": "fail", "error": str(e)}
|
||
|
|
|
||
|
|
|
||
|
|
def run_smoke_tests(verbose: bool = False) -> Dict[str, Any]:
|
||
|
|
tests = [
|
||
|
|
_test_imports(),
|
||
|
|
_test_cli_entrypoints(),
|
||
|
|
_test_green_path_e2e(),
|
||
|
|
]
|
||
|
|
failed = [t for t in tests if t["status"] != "ok"]
|
||
|
|
result = {
|
||
|
|
"overall": "ok" if not failed else "fail",
|
||
|
|
"tests": tests,
|
||
|
|
"failed_count": len(failed),
|
||
|
|
}
|
||
|
|
if verbose:
|
||
|
|
print(json.dumps(result, indent=2))
|
||
|
|
return result
|
||
|
|
|
||
|
|
|
||
|
|
def main(argv: List[str] = None) -> int:
|
||
|
|
argv = argv or sys.argv[1:]
|
||
|
|
parser = argparse.ArgumentParser(description="Smoke test runner")
|
||
|
|
parser.add_argument("--verbose", action="store_true")
|
||
|
|
args = parser.parse_args(argv)
|
||
|
|
|
||
|
|
result = run_smoke_tests(verbose=True)
|
||
|
|
return 0 if result["overall"] == "ok" else 1
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
sys.exit(main())
|