Download tests/test_autostart.py from PYTHAI/mindXtrain: direct link, hf CLI and curl.
- Browser
- Download file 9.38 kB
-
https://huggingface.co/PYTHAI/mindXtrain/resolve/main/tests/test_autostart.py
- Command line
-
hf download hf://PYTHAI/mindXtrain/tests/test_autostart.py
-
curl -L -o test_autostart.py https://huggingface.co/PYTHAI/mindXtrain/resolve/main/tests/test_autostart.py
9.38 kB
| """Hands-free CPU autostart, gated on the mindX SEA agent's decision. | |
| `autostart_cpu_training` has two gates: `MINDXTRAIN_AUTOSTART` arms | |
| autonomous mode, and the StrategicEvolutionAgent's decision file is the | |
| actual decider. Tests patch `coach.api._SPAWN` with a fake so the launch | |
| path runs without a subprocess, and point `MINDXTRAIN_SEA_DECISION` at a | |
| temp file so no real mindX install is touched. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import time | |
| from collections.abc import Iterator | |
| from pathlib import Path | |
| from typing import Any | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from mindxtrain.operator import runs as _runs | |
| from mindxtrain.operator.app import app | |
| from mindxtrain.operator.coach import api as coach_api | |
| from mindxtrain.operator.coach import run_metrics as rm | |
| client = TestClient(app) | |
| def _restore(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]: | |
| """Restore the real spawn fn + clear all autostart/SEA env each test.""" | |
| original = coach_api._SPAWN | |
| for var in ( | |
| "MINDXTRAIN_AUTOSTART", | |
| "MINDXTRAIN_AUTOSTART_RECIPE", | |
| "MINDXTRAIN_SEA_DECISION", | |
| "MINDXTRAIN_MINDX_ROOT", | |
| ): | |
| monkeypatch.delenv(var, raising=False) | |
| yield | |
| coach_api._SPAWN = original | |
| # Drain any runs the fake spawn left "running" — otherwise the | |
| # idempotency check in autostart_cpu_training trips on stale runs | |
| # carried into the next test by the module-global registry. | |
| for run in coach_api._REGISTRY.list_runs(): | |
| if run.status in ("pending", "running"): | |
| coach_api._REGISTRY.publish( | |
| run.id, | |
| _runs.StatusEvent( | |
| run_id=run.id, status="cancelled", message="test teardown", | |
| ), | |
| ) | |
| def _fake_spawn(run: _runs.Run, _cfg: Any, _plan: Any) -> None: | |
| """Stand-in spawn — marks the run running without a subprocess.""" | |
| coach_api._REGISTRY.publish( | |
| run.id, | |
| _runs.StatusEvent(run_id=run.id, status="running", message="fake"), | |
| ) | |
| def _write_decision( | |
| tmp_path: Path, monkeypatch: pytest.MonkeyPatch, **fields: Any, | |
| ) -> Path: | |
| """Write a SEA decision file and point the operator at it.""" | |
| record: dict[str, Any] = { | |
| "recommend": True, | |
| "recipe": None, | |
| "reason": "test recommendation", | |
| "decided_by": "strategic_evolution_agent", | |
| "ts": time.time(), | |
| "ttl_s": 3600, | |
| } | |
| record.update(fields) | |
| path = tmp_path / "training_recommendation.json" | |
| path.write_text(json.dumps(record), encoding="utf-8") | |
| monkeypatch.setenv("MINDXTRAIN_SEA_DECISION", str(path)) | |
| return path | |
| async def _cleanup_samplers() -> None: | |
| """Stop any per-run metrics samplers the launch path started.""" | |
| for tid in list(rm._TASKS): | |
| await rm.stop_metrics_sampler(tid) | |
| # ---- env-driven gates ---------------------------------------------------- | |
| def test_autostart_disabled_by_default() -> None: | |
| assert coach_api.autostart_enabled() is False | |
| def test_autostart_enabled_recognises_truthy( | |
| monkeypatch: pytest.MonkeyPatch, val: str, | |
| ) -> None: | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", val) | |
| assert coach_api.autostart_enabled() is True | |
| def test_autostart_recipe_defaults_to_smoke() -> None: | |
| assert coach_api.autostart_recipe() == "mindx_fallback_qwen3_1_5b_cpu_smoke" | |
| def test_autostart_recipe_honours_override( | |
| monkeypatch: pytest.MonkeyPatch, | |
| ) -> None: | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART_RECIPE", "qwen3_8b_sft_lora") | |
| assert coach_api.autostart_recipe() == "qwen3_8b_sft_lora" | |
| # ---- SEA decision gate --------------------------------------------------- | |
| def test_sea_gate_closed_when_no_decision_file( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| monkeypatch.setenv("MINDXTRAIN_SEA_DECISION", str(tmp_path / "missing.json")) | |
| gate = coach_api.sea_training_gate() | |
| assert gate["open"] is False | |
| assert gate["available"] is False | |
| def test_sea_gate_open_on_fresh_recommendation( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| _write_decision(tmp_path, monkeypatch, recommend=True, reason="corpus grew") | |
| gate = coach_api.sea_training_gate() | |
| assert gate["open"] is True | |
| assert "corpus grew" in gate["reason"] | |
| def test_sea_gate_closed_when_sea_says_no( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| _write_decision(tmp_path, monkeypatch, recommend=False, reason="loss still high") | |
| gate = coach_api.sea_training_gate() | |
| assert gate["open"] is False | |
| assert gate["available"] is True | |
| assert "loss still high" in gate["reason"] | |
| def test_sea_gate_closed_when_recommendation_is_stale( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| _write_decision( | |
| tmp_path, monkeypatch, | |
| recommend=True, ts=time.time() - 10_000, ttl_s=60, | |
| ) | |
| gate = coach_api.sea_training_gate() | |
| assert gate["open"] is False | |
| assert "stale" in gate["reason"] | |
| def test_sea_gate_handles_corrupt_file( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| bad = tmp_path / "training_recommendation.json" | |
| bad.write_text("{not json", encoding="utf-8") | |
| monkeypatch.setenv("MINDXTRAIN_SEA_DECISION", str(bad)) | |
| gate = coach_api.sea_training_gate() | |
| assert gate["open"] is False # unreadable → treated as no decision | |
| # ---- autostart_cpu_training behaviour ------------------------------------ | |
| async def test_autostart_noop_when_disabled() -> None: | |
| """No env flag → returns None, launches nothing.""" | |
| assert await coach_api.autostart_cpu_training() is None | |
| async def test_autostart_noop_when_sea_gate_closed( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| """Autostart armed but SEA has not recommended → no launch.""" | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| monkeypatch.setenv("MINDXTRAIN_SEA_DECISION", str(tmp_path / "missing.json")) | |
| coach_api._SPAWN = _fake_spawn | |
| assert await coach_api.autostart_cpu_training() is None | |
| async def test_autostart_noop_when_sea_declines( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| """SEA decision present but recommend=false → no launch.""" | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| _write_decision(tmp_path, monkeypatch, recommend=False) | |
| coach_api._SPAWN = _fake_spawn | |
| assert await coach_api.autostart_cpu_training() is None | |
| async def test_autostart_launches_when_sea_recommends( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| """Both gates open → the smoke recipe is launched and a Run comes back.""" | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| _write_decision(tmp_path, monkeypatch, recommend=True) | |
| coach_api._SPAWN = _fake_spawn | |
| try: | |
| run = await coach_api.autostart_cpu_training() | |
| assert run is not None | |
| assert run.recipe == "mindx_fallback_qwen3_1_5b_cpu_smoke" | |
| assert run.status == "running" | |
| finally: | |
| await _cleanup_samplers() | |
| async def test_autostart_uses_sea_chosen_recipe( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| """SEA's `recipe` field overrides the MINDXTRAIN_AUTOSTART_RECIPE default.""" | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| _write_decision(tmp_path, monkeypatch, recommend=True, recipe="qwen3_8b_sft_lora") | |
| coach_api._SPAWN = _fake_spawn | |
| try: | |
| run = await coach_api.autostart_cpu_training() | |
| assert run is not None | |
| assert run.recipe == "qwen3_8b_sft_lora" | |
| finally: | |
| await _cleanup_samplers() | |
| async def test_autostart_idempotent_when_run_active( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| """A run already pending/running → autostart skips (no stacked trainers).""" | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| _write_decision(tmp_path, monkeypatch, recommend=True) | |
| coach_api._SPAWN = _fake_spawn | |
| existing = coach_api._REGISTRY.create("qwen3_8b_sft_lora", tmp_path / "r") | |
| assert existing.status == "pending" # counts as active | |
| assert await coach_api.autostart_cpu_training() is None | |
| # ---- /coach/api/sea-decision endpoint ------------------------------------ | |
| def test_sea_decision_endpoint_reports_closed_gate( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| monkeypatch.setenv("MINDXTRAIN_SEA_DECISION", str(tmp_path / "missing.json")) | |
| r = client.get("/coach/api/sea-decision") | |
| assert r.status_code == 200 | |
| body = r.json() | |
| assert body["open"] is False | |
| assert body["autostart_enabled"] is False | |
| assert "decision_path" in body | |
| def test_sea_decision_endpoint_reports_open_gate( | |
| monkeypatch: pytest.MonkeyPatch, tmp_path: Path, | |
| ) -> None: | |
| monkeypatch.setenv("MINDXTRAIN_AUTOSTART", "1") | |
| _write_decision(tmp_path, monkeypatch, recommend=True, reason="dream corpus +340") | |
| r = client.get("/coach/api/sea-decision") | |
| body = r.json() | |
| assert body["open"] is True | |
| assert body["autostart_enabled"] is True | |
| assert "dream corpus +340" in body["reason"] | |
| assert body["decision"]["decided_by"] == "strategic_evolution_agent" | |