mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-30 10:52:15 +00:00
``TestMemoryRoutes.test_search`` and ``test_stats`` assert the status code is in ``(200, 500)``. That list dates from the initial commit; #527 later made the memory routes raise 503 when the native ``openjarvis_rust`` extension is missing, so both tests now fail on any checkout where the extension has not been built — which is every contributor who has not run ``maturin develop``. The failure is spurious: these two tests only check that the routes are wired up, and their own comment ("May fail if SQLite not set up, that's ok") says an unavailable backend is tolerated. 503 is exactly that case, and it is already asserted deliberately in ``TestMemoryRustMissing`` directly below. Add 503 to the tolerated set via a named constant, so the reason is stated once rather than repeated as a bare literal. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
150 lines
5.1 KiB
Python
150 lines
5.1 KiB
Python
"""Tests for extended API routes."""
|
|
|
|
import pytest
|
|
|
|
fastapi = pytest.importorskip("fastapi")
|
|
from fastapi import FastAPI # noqa: E402
|
|
from fastapi.testclient import TestClient # noqa: E402
|
|
|
|
from openjarvis.server.api_routes import include_all_routes # noqa: E402
|
|
|
|
|
|
def _make_app():
|
|
app = FastAPI()
|
|
include_all_routes(app)
|
|
return app
|
|
|
|
|
|
class TestAgentRoutes:
|
|
def test_list_agents(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/agents")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "registered" in data
|
|
assert "running" in data
|
|
|
|
def test_create_agent(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.post("/v1/agents", json={"agent_type": "simple"})
|
|
# May succeed or fail depending on agent_tools availability
|
|
assert resp.status_code in (200, 501)
|
|
|
|
def test_kill_nonexistent(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.delete("/v1/agents/nonexistent")
|
|
assert resp.status_code in (404, 501)
|
|
|
|
|
|
class TestMemoryRoutes:
|
|
# 503 is the documented response when the native ``openjarvis_rust``
|
|
# extension is absent from the venv (see TestMemoryRustMissing below).
|
|
# These tests are only asserting "the route is wired up", so a backend
|
|
# that cannot be built is tolerated the same way a 500 is.
|
|
_BACKEND_OPTIONAL = (200, 500, 503)
|
|
|
|
def test_search(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.post("/v1/memory/search", json={"query": "test"})
|
|
# May fail if SQLite not set up, that's ok
|
|
assert resp.status_code in self._BACKEND_OPTIONAL
|
|
|
|
def test_stats(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/memory/stats")
|
|
assert resp.status_code in self._BACKEND_OPTIONAL
|
|
|
|
|
|
class TestMemoryRustMissing:
|
|
"""Regression for #502: when the native ``openjarvis_rust`` extension is
|
|
missing from the serving venv, memory ops must surface a CLEAR, ACTIONABLE
|
|
error — never the misleading "Failed to index path" or a 200 silent no-op.
|
|
"""
|
|
|
|
@staticmethod
|
|
def _client(monkeypatch):
|
|
# Force the same failure mode as a venv without the compiled extension.
|
|
def _boom():
|
|
raise ImportError("No module named 'openjarvis_rust'")
|
|
|
|
import openjarvis._rust_bridge as bridge
|
|
|
|
monkeypatch.setattr(bridge, "get_rust_module", _boom)
|
|
return TestClient(_make_app())
|
|
|
|
def test_store_is_not_a_silent_noop(self, monkeypatch):
|
|
client = self._client(monkeypatch)
|
|
resp = client.post("/v1/memory/store", json={"content": "hi"})
|
|
# Must NOT return the old 200 {"status":"stored","note":"no backend..."}.
|
|
assert resp.status_code == 503
|
|
detail = resp.json()["detail"]
|
|
assert "openjarvis_rust" in detail
|
|
assert "maturin develop" in detail
|
|
|
|
def test_index_surfaces_actionable_detail(self, monkeypatch, tmp_path):
|
|
(tmp_path / "note.txt").write_text("hello world some content here")
|
|
client = self._client(monkeypatch)
|
|
resp = client.post("/v1/memory/index", json={"path": str(tmp_path)})
|
|
assert resp.status_code == 503
|
|
detail = resp.json()["detail"]
|
|
# The frontend reads this `detail`; it must point at the real cause,
|
|
# not blame the indexed path.
|
|
assert "openjarvis_rust" in detail
|
|
assert detail != "Failed to index path"
|
|
assert detail != "No memory backend available"
|
|
|
|
def test_config_reports_unavailable(self, monkeypatch):
|
|
client = self._client(monkeypatch)
|
|
resp = client.get("/v1/memory/config")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
# Must not falsely report a healthy backend when none could be built.
|
|
assert data["available"] is False
|
|
assert "openjarvis_rust" in (data["detail"] or "")
|
|
|
|
|
|
class TestBudgetRoutes:
|
|
def test_get_budget(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/budget")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "limits" in data
|
|
assert "usage" in data
|
|
|
|
def test_set_limits(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.put("/v1/budget/limits", json={"max_tokens_per_day": 100000})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["limits"]["max_tokens_per_day"] == 100000
|
|
|
|
|
|
class TestMetricsRoute:
|
|
def test_metrics_endpoint(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/metrics")
|
|
assert resp.status_code == 200
|
|
assert "openjarvis" in resp.text or "No metrics" in resp.text
|
|
|
|
|
|
class TestSkillRoutes:
|
|
def test_list_skills(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/skills")
|
|
assert resp.status_code == 200
|
|
assert "skills" in resp.json()
|
|
|
|
|
|
class TestSessionRoutes:
|
|
def test_list_sessions(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/sessions")
|
|
assert resp.status_code == 200
|
|
|
|
|
|
class TestTraceRoutes:
|
|
def test_list_traces(self):
|
|
client = TestClient(_make_app())
|
|
resp = client.get("/v1/traces")
|
|
assert resp.status_code == 200
|