102 lines
3.7 KiB
Python
102 lines
3.7 KiB
Python
from datetime import UTC, datetime, timedelta
|
|
|
|
from backend.app.connectors import gitea_actions
|
|
from backend.app.connectors.gitea_actions import GiteaActionsConnector
|
|
from backend.app.core.config import settings
|
|
|
|
|
|
def _configure(monkeypatch) -> GiteaActionsConnector:
|
|
monkeypatch.setitem(settings.apis, "GITEA_URL", "https://gitea.test")
|
|
monkeypatch.setitem(settings.apis, "GITEA_ADMIN_TOKEN", "fixture-secret")
|
|
monkeypatch.setitem(
|
|
settings.apis,
|
|
"GITEA_RUNNER_TARGETS_JSON",
|
|
'{"linux-validation":"itworx-validation-runner-2",'
|
|
'"mcp-validation":"itworx-security-runner"}',
|
|
)
|
|
monkeypatch.setattr(gitea_actions, "_CACHE", None)
|
|
return GiteaActionsConnector()
|
|
|
|
|
|
def _requests(created_at: str, *, busy: bool = False):
|
|
def fake_request(path, params=None):
|
|
params = params or {}
|
|
if path.endswith("/runners"):
|
|
return {
|
|
"total_count": 1,
|
|
"runners": [
|
|
{
|
|
"id": 17,
|
|
"name": "validation-secondary",
|
|
"status": "online",
|
|
"busy": busy,
|
|
"disabled": False,
|
|
"labels": ["linux-validation", "ubuntu-latest"],
|
|
}
|
|
],
|
|
}
|
|
if params.get("status") == "queued":
|
|
return {
|
|
"total_count": 1,
|
|
"jobs": [
|
|
{
|
|
"id": 91,
|
|
"name": "full",
|
|
"status": "queued",
|
|
"created_at": created_at,
|
|
"labels": ["linux-validation"],
|
|
}
|
|
],
|
|
}
|
|
return {"total_count": 0, "jobs": []}
|
|
|
|
return fake_request
|
|
|
|
|
|
def test_old_unassigned_job_on_idle_matching_runner_is_recovery_candidate(monkeypatch):
|
|
connector = _configure(monkeypatch)
|
|
created_at = (datetime.now(UTC) - timedelta(minutes=12)).isoformat()
|
|
monkeypatch.setattr(connector, "_request", _requests(created_at))
|
|
|
|
result = connector.snapshot(refresh=True)
|
|
|
|
assert result["severity"] == "critical"
|
|
assert result["queue"]["items"][0]["reason"] == "awaiting_scheduler_assignment"
|
|
assert result["queue"]["staleAssignmentRunnerLabels"] == ["linux-validation"]
|
|
assert result["recommendedAction"] == {
|
|
"intent": "runner.recover",
|
|
"target": "itworx-validation-runner-2",
|
|
"requiresApproval": False,
|
|
"autoExecute": True,
|
|
"reason": "Gitea Actions scheduler left a compatible idle runner unassigned for at least ten minutes.",
|
|
"evidence": {
|
|
"jobId": 91,
|
|
"label": "linux-validation",
|
|
"minimumAgeSeconds": 600,
|
|
},
|
|
}
|
|
|
|
|
|
def test_recent_unassigned_job_does_not_trigger_recovery(monkeypatch):
|
|
connector = _configure(monkeypatch)
|
|
created_at = (datetime.now(UTC) - timedelta(minutes=2)).isoformat()
|
|
monkeypatch.setattr(connector, "_request", _requests(created_at))
|
|
|
|
result = connector.snapshot(refresh=True)
|
|
|
|
assert result["queue"]["items"][0]["reason"] == "awaiting_scheduler_assignment"
|
|
assert result["queue"]["staleAssignmentRunnerLabels"] == []
|
|
assert result["recommendedAction"] is None
|
|
|
|
|
|
def test_busy_matching_runner_is_never_restarted_for_waiting_queue(monkeypatch):
|
|
connector = _configure(monkeypatch)
|
|
created_at = (datetime.now(UTC) - timedelta(minutes=12)).isoformat()
|
|
monkeypatch.setattr(connector, "_request", _requests(created_at, busy=True))
|
|
|
|
result = connector.snapshot(refresh=True)
|
|
|
|
assert result["queue"]["items"][0]["reason"] == "all_matching_runners_are_busy"
|
|
assert result["queue"]["staleAssignmentRunnerLabels"] == []
|
|
assert result["recommendedAction"] is None
|