111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
import asyncio
|
|
import uuid
|
|
import time
|
|
from typing import Dict, Optional
|
|
|
|
from app.config import (
|
|
CONTAINER_HOST,
|
|
CONTAINER_RUNTIME,
|
|
UERANSIM_CONTAINER_NAME,
|
|
UERANSIM_ENV_FILE,
|
|
UERANSIM_IMAGE,
|
|
UERANSIM_NETWORK_MODE,
|
|
UERANSIM_PRIVILEGED,
|
|
)
|
|
|
|
_tasks: Dict[str, dict] = {}
|
|
|
|
|
|
def create_task() -> str:
|
|
task_id = str(uuid.uuid4())
|
|
_tasks[task_id] = {
|
|
"id": task_id,
|
|
"status": "pending",
|
|
"logs": [],
|
|
"created": time.time(),
|
|
}
|
|
return task_id
|
|
|
|
|
|
def get_task(task_id: str) -> Optional[dict]:
|
|
return _tasks.get(task_id)
|
|
|
|
|
|
async def run_test(task_id: str) -> None:
|
|
task = _tasks[task_id]
|
|
task["status"] = "running"
|
|
|
|
def log(msg: str, type: str = "info") -> None:
|
|
task["logs"].append({"msg": msg, "type": type, "ts": time.strftime("%H:%M:%S")})
|
|
|
|
runtime_cmd = [CONTAINER_RUNTIME]
|
|
if CONTAINER_HOST:
|
|
runtime_cmd.extend(["--host", CONTAINER_HOST])
|
|
|
|
log(f"▸ Checking UERANSIM image via {CONTAINER_RUNTIME}…", "run")
|
|
check = await asyncio.create_subprocess_exec(
|
|
*runtime_cmd, "images", "-q", UERANSIM_IMAGE,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
)
|
|
out, _ = await check.communicate()
|
|
if not out.strip():
|
|
log("✗ UERANSIM image not found.", "err")
|
|
log(" Build it with `docker compose build ueransim` or set MARVIS_UERANSIM_IMAGE.", "err")
|
|
task["status"] = "error"
|
|
return
|
|
|
|
log(" UERANSIM image ready", "ok")
|
|
log("▸ Starting test container — allow up to 60s…", "run")
|
|
|
|
try:
|
|
run_cmd = [*runtime_cmd, "run", "--rm", "--name", UERANSIM_CONTAINER_NAME]
|
|
if UERANSIM_NETWORK_MODE:
|
|
run_cmd.append(f"--network={UERANSIM_NETWORK_MODE}")
|
|
if UERANSIM_PRIVILEGED:
|
|
run_cmd.append("--privileged")
|
|
run_cmd.extend([
|
|
"--env-file", UERANSIM_ENV_FILE,
|
|
UERANSIM_IMAGE,
|
|
])
|
|
|
|
proc = await asyncio.create_subprocess_exec(
|
|
*run_cmd,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.STDOUT,
|
|
)
|
|
try:
|
|
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=90)
|
|
except asyncio.TimeoutError:
|
|
proc.kill()
|
|
log("✗ Test timed out after 90s — container killed", "err")
|
|
task["status"] = "error"
|
|
return
|
|
|
|
for line in stdout.decode(errors="replace").splitlines():
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
if "ERROR" in line:
|
|
log(line, "err")
|
|
elif "PASSED" in line or "established" in line or "successful" in line:
|
|
log(line, "ok")
|
|
elif "WARNING" in line:
|
|
log(line, "warn")
|
|
else:
|
|
log(line, "info")
|
|
|
|
if proc.returncode == 0:
|
|
log("✓ Emulated data session completed successfully", "ok")
|
|
task["status"] = "done"
|
|
elif proc.returncode == 2:
|
|
log(f"⚠ Credentials not configured — edit {UERANSIM_ENV_FILE}", "warn")
|
|
task["status"] = "error"
|
|
else:
|
|
log(f"✗ Test exited with code {proc.returncode}", "err")
|
|
task["status"] = "error"
|
|
|
|
except Exception as exc:
|
|
log(f"✗ Unexpected error: {exc}", "err")
|
|
task["status"] = "error"
|