import routes.api_scenario_run as api_run class DummyUniqueViolation(Exception): pgcode = "23505" class DummyCursor: def __init__(self, fail_on_execute=None, fetchone_value=None): self._fail_on_execute = fail_on_execute self._fetchone_value = fetchone_value def execute(self, *args, **kwargs): if self._fail_on_execute is not None: raise self._fail_on_execute def fetchone(self): return self._fetchone_value def close(self): return None class DummyConn: def __init__(self, fail_on_execute=None, fetchone_value=None): self._fail_on_execute = fail_on_execute self._fetchone_value = fetchone_value self.committed = False self.rolled_back = False def cursor(self): return DummyCursor(self._fail_on_execute, self._fetchone_value) def commit(self): self.committed = True def rollback(self): self.rolled_back = True def _patch_common_happy(monkeypatch): monkeypatch.setattr(api_run, "get_client_id", lambda: "cid") monkeypatch.setattr(api_run, "get_stand", lambda: "test") monkeypatch.setattr(api_run, "get_definition", lambda _id, _cid, _stand: { "id": _id, "name": "scenario-a", "version": 7, "steps": [{"service_id": 1, "operation": "create", "params": {}}], }) monkeypatch.setattr(api_run, "get_token_info", lambda: {"email": "u@example.com"}) def test_run_returns_503_when_lock_check_is_none(app_client, monkeypatch): _patch_common_happy(monkeypatch) monkeypatch.setattr(api_run, "lock_check", lambda _cid, _stand: None) resp = app_client.post("/api/scenario/run", json={"definition_id": 1}) assert resp.status_code == 503 assert resp.get_json()["error"] == "DB unavailable" def test_run_returns_409_when_lock_check_is_false(app_client, monkeypatch): _patch_common_happy(monkeypatch) monkeypatch.setattr(api_run, "lock_check", lambda _cid, _stand: False) resp = app_client.post("/api/scenario/run", json={"definition_id": 1}) assert resp.status_code == 409 assert "already running" in resp.get_json()["error"].lower() def test_run_returns_409_on_unique_violation(app_client, monkeypatch): _patch_common_happy(monkeypatch) monkeypatch.setattr(api_run, "lock_check", lambda _cid, _stand: True) conn = DummyConn(fail_on_execute=DummyUniqueViolation()) monkeypatch.setattr(api_run, "get_conn", lambda: conn) monkeypatch.setattr(api_run, "put_conn", lambda _conn: None) # Must not start a background thread in this branch. monkeypatch.setattr(api_run, "get_client", lambda: object()) resp = app_client.post("/api/scenario/run", json={"definition_id": 1}) assert resp.status_code == 409 assert "already running" in resp.get_json()["error"].lower() assert conn.rolled_back is True