-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest_api_integration.py
More file actions
164 lines (112 loc) · 4.7 KB
/
Copy pathtest_api_integration.py
File metadata and controls
164 lines (112 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""
API integration tests — full HTTP round-trip via Flask test_client.
Covers /api/projects, /api/projects/<name>/sessions, /api/sessions/<name>/<id>,
and /api/search (Week 3 Tuesday, 8pt).
Fixtures (`client`, `client_empty`, `client_thinking`) live in tests/conftest.py.
"""
from __future__ import annotations
import pytest
from app import CSP_POLICY
from tests.conftest import assert_error_response as _assert_error_shape
# --- / (SPA shell) ---
def test_root_sets_csp_header(client):
resp = client.get("/")
assert resp.status_code == 200
assert resp.headers.get("Content-Security-Policy") == CSP_POLICY
def test_api_routes_set_csp_header(client):
resp = client.get("/api/projects")
assert resp.status_code == 200
assert resp.headers.get("Content-Security-Policy") == CSP_POLICY
# --- /api/projects ---
def test_projects_returns_list(client):
resp = client.get("/api/projects")
assert resp.status_code == 200
data = resp.get_json()
assert isinstance(data, list)
assert len(data) >= 1
project = data[0]
assert "name" in project
assert "path" in project
def test_projects_empty_base_dir(client_empty):
resp = client_empty.get("/api/projects")
assert resp.status_code == 200
assert resp.get_json() == []
# --- /api/projects/<project_name>/sessions ---
def test_project_sessions_list(client):
resp = client.get("/api/projects/test-project/sessions")
assert resp.status_code == 200
sessions = resp.get_json()
assert isinstance(sessions, list)
assert len(sessions) >= 1
ids = {s["id"] for s in sessions}
assert "session_abc123" in ids
assert "session_def456" in ids
def test_project_sessions_unknown_project(client):
resp = client.get("/api/projects/nonexistent-project/sessions")
assert resp.status_code == 200
assert resp.get_json() == []
# --- /api/sessions/<project_name>/<session_id> ---
def test_session_detail_happy_path(client):
resp = client.get("/api/sessions/test-project/session_abc123")
assert resp.status_code == 200
session = resp.get_json()
assert "messages" in session
assert session["session_id"] == "session_abc123"
assert session["title"] != "Untitled Session"
def test_session_detail_not_found(client):
resp = client.get("/api/sessions/test-project/nonexistent")
assert resp.status_code == 404
_assert_error_shape(resp)
def test_session_detail_includes_thinking_blocks(client_thinking):
resp = client_thinking.get("/api/sessions/test-project/session_think001")
assert resp.status_code == 200
session = resp.get_json()
assert "messages" in session
assistant_msgs = [m for m in session["messages"] if m.get("role") == "assistant"]
assert any(m.get("thinking") == "Considering options carefully." for m in assistant_msgs)
# --- /api/search ---
def test_search_returns_results(client):
resp = client.get("/api/search?q=Hello")
assert resp.status_code == 200
results = resp.get_json()
assert isinstance(results, list)
assert len(results) >= 1
def test_search_empty_query(client):
resp = client.get("/api/search?q=")
assert resp.status_code == 200
assert resp.get_json() == []
def test_search_invalid_limit(client):
"""Regression: bad limit must return 400, not 500."""
resp = client.get("/api/search?q=test&limit=abc")
assert resp.status_code == 400
_assert_error_shape(resp)
def test_search_valid_limit(client):
resp = client.get("/api/search?q=Hello&limit=5")
assert resp.status_code == 200
results = resp.get_json()
assert isinstance(results, list)
assert len(results) <= 5
# --- session summary cache (disk) ---
@pytest.fixture
def summary_cache_db(tmp_path, monkeypatch):
from utils.session_summary_cache import clear_cache, reset_connection_for_tests
db = tmp_path / "session_summary_cache.sqlite"
reset_connection_for_tests(db)
yield db
clear_cache()
def test_project_session_count_matches_list(client, summary_cache_db):
projects = client.get("/api/projects").get_json()
project = next(p for p in projects if p["name"] == "test-project")
sessions = client.get("/api/projects/test-project/sessions").get_json()
assert project["session_count"] == len(sessions)
def test_project_sessions_uses_disk_cache_on_second_request(client, summary_cache_db, monkeypatch):
client.get("/api/projects/test-project/sessions")
calls = 0
def counting_get_cached(path: str):
nonlocal calls
calls += 1
from utils.session_cache import get_cached_session as real_get
return real_get(path)
monkeypatch.setattr("api.projects.get_cached_session", counting_get_cached)
client.get("/api/projects/test-project/sessions")
assert calls == 0