implemented watcher and rerun logic
This commit is contained in:
+67
-4
@@ -12,6 +12,7 @@ import db
|
||||
import graph
|
||||
from parser import CsvValidationError, parse_target_csv
|
||||
from scheduler import SchedulerTest, compile_schedule, remove_from_active, reset_scheduler_state
|
||||
from watcher import configure_result_watcher, stop_result_watcher
|
||||
|
||||
|
||||
APP_ROOT = Path(__file__).resolve().parent
|
||||
@@ -28,6 +29,41 @@ class SaveSettingsRequest(BaseModel):
|
||||
settings: dict[str, Any]
|
||||
|
||||
|
||||
def _smb_credentials_from_settings(settings: dict[str, Any]) -> dict[str, str]:
|
||||
return {
|
||||
"username": str(settings.get("smbUsername") or "").strip(),
|
||||
"password": str(settings.get("smbPassword") or ""),
|
||||
"domain": str(settings.get("smbDomain") or "").strip(),
|
||||
}
|
||||
|
||||
|
||||
def _runtime_overrides_from_settings(settings: dict[str, Any]) -> dict[str, int]:
|
||||
def _parse_positive_int(value: Any) -> int | None:
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if not value:
|
||||
return None
|
||||
try:
|
||||
parsed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return parsed if parsed > 0 else None
|
||||
|
||||
overrides: dict[str, int] = {}
|
||||
for test_type, key in (
|
||||
("P2P", "p2pRuntimeMinutes"),
|
||||
("COE", "coeRuntimeMinutes"),
|
||||
("P3P", "p3pRuntimeMinutes"),
|
||||
):
|
||||
minutes = _parse_positive_int(settings.get(key))
|
||||
if minutes is not None:
|
||||
overrides[test_type] = minutes
|
||||
|
||||
return overrides
|
||||
|
||||
|
||||
class CompileScheduleRequest(BaseModel):
|
||||
start_date: str | None = Field(default=None, description="YYYY-MM-DD")
|
||||
rule: str = ""
|
||||
@@ -48,7 +84,12 @@ class SaveHolidaysRequest(BaseModel):
|
||||
async def lifespan(application: FastAPI):
|
||||
db.init_db(DB_PATH)
|
||||
graph.reset_graph_state()
|
||||
yield
|
||||
settings = db.read_settings(DB_PATH)
|
||||
configure_result_watcher(settings)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
stop_result_watcher()
|
||||
|
||||
|
||||
app = FastAPI(title="Scheduler API", version="0.1.0", lifespan=lifespan)
|
||||
@@ -69,6 +110,7 @@ def health() -> dict[str, str]:
|
||||
@app.post("/api/settings")
|
||||
def save_settings(request: SaveSettingsRequest) -> dict[str, str]:
|
||||
db.save_settings(request.settings, DB_PATH)
|
||||
configure_result_watcher(db.read_settings(DB_PATH))
|
||||
return {"status": "saved"}
|
||||
|
||||
|
||||
@@ -83,8 +125,16 @@ def load_tests(request: LoadTestsRequest) -> dict[str, Any]:
|
||||
if not csv_path.is_absolute():
|
||||
csv_path = APP_ROOT / csv_path
|
||||
|
||||
settings = db.read_settings(DB_PATH)
|
||||
smb_credentials = _smb_credentials_from_settings(settings)
|
||||
runtime_overrides = _runtime_overrides_from_settings(settings)
|
||||
|
||||
try:
|
||||
parsed = parse_target_csv(csv_path)
|
||||
parsed = parse_target_csv(
|
||||
csv_path,
|
||||
smb_credentials=smb_credentials,
|
||||
runtime_overrides=runtime_overrides,
|
||||
)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except CsvValidationError as exc:
|
||||
@@ -94,7 +144,7 @@ def load_tests(request: LoadTestsRequest) -> dict[str, Any]:
|
||||
reset_scheduler_state()
|
||||
graph.reset_graph_state()
|
||||
all_dut_tests = db.list_tests_for_device(DUT, DB_PATH)
|
||||
graph.build_graph_once(all_dut_tests)
|
||||
graph.build_and_persist_graph(all_dut_tests, DB_PATH)
|
||||
|
||||
return {
|
||||
"loaded_tests": count,
|
||||
@@ -117,6 +167,7 @@ def compile_schedule_endpoint(request: CompileScheduleRequest) -> dict[str, Any]
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail="start_date must be YYYY-MM-DD") from exc
|
||||
|
||||
reset_scheduler_state()
|
||||
stored_tests = db.list_schedulable_tests(DB_PATH, rule=request.rule)
|
||||
if not stored_tests:
|
||||
version = db.create_schedule_version([], DB_PATH)
|
||||
@@ -144,6 +195,10 @@ def compile_schedule_endpoint(request: CompileScheduleRequest) -> dict[str, Any]
|
||||
for t in stored_tests
|
||||
]
|
||||
|
||||
# DB-backed graph retrieval ensures compile works after restart without manual save/load.
|
||||
all_dut_tests = db.list_tests_for_device(DUT, DB_PATH)
|
||||
graph.get_graph(DB_PATH, all_dut_tests)
|
||||
|
||||
holiday_dates = db.list_holidays(DB_PATH)
|
||||
try:
|
||||
entries, completion_date = compile_schedule(
|
||||
@@ -161,7 +216,7 @@ def compile_schedule_endpoint(request: CompileScheduleRequest) -> dict[str, Any]
|
||||
[(e.test_id, e.device, e.scheduled_date, e.shift_index, e.sequence_in_shift) for e in entries],
|
||||
DB_PATH,
|
||||
)
|
||||
|
||||
print(f"Schedule version {version} created with {len(entries)} entries, completion date: {completion_date}")
|
||||
return {
|
||||
"schedule_version": version,
|
||||
"scheduled_tests": len(entries),
|
||||
@@ -169,6 +224,14 @@ def compile_schedule_endpoint(request: CompileScheduleRequest) -> dict[str, Any]
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/tests/rerun")
|
||||
def get_rerun_tests() -> dict[str, Any]:
|
||||
db.mark_overdue_as_rerun(DB_PATH)
|
||||
tests = db.get_rerun_tests(DB_PATH)
|
||||
total_minutes = sum(t["estimated_minutes"] for t in tests)
|
||||
return {"tests": tests, "total_estimated_minutes": total_minutes}
|
||||
|
||||
|
||||
@app.post("/api/holidays")
|
||||
def save_holidays(request: SaveHolidaysRequest) -> dict[str, Any]:
|
||||
dates = [d.strip() for d in request.dates if d.strip()]
|
||||
|
||||
Reference in New Issue
Block a user