Skip to content

Commit 4775629

Browse files
authored
Merge pull request #2343 from Jdubrick/add-saved-prompts-tests
RHIDP-14311: add integration tests for saved prompts
2 parents 4d393e8 + c621824 commit 4775629

1 file changed

Lines changed: 283 additions & 0 deletions

File tree

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
"""Integration tests for the /v1/saved-prompts REST API endpoints."""
2+
3+
import pytest
4+
from fastapi import HTTPException, Request, status
5+
from sqlalchemy.orm import Session
6+
7+
from app.endpoints.saved_prompts import (
8+
create_saved_prompts_handler,
9+
delete_saved_prompts_handler,
10+
get_saved_prompts_config_handler,
11+
list_saved_prompts_handler,
12+
)
13+
from authentication.interface import AuthTuple
14+
from configuration import AppConfig
15+
from models.api.requests import SavedPromptCreateRequest
16+
from models.api.responses.successful import SavedPromptResponse
17+
from tests.integration.conftest import (
18+
TEST_NON_EXISTENT_ID,
19+
TEST_OTHER_USER_ID,
20+
)
21+
22+
23+
@pytest.fixture(name="other_auth")
24+
def other_auth_fixture() -> AuthTuple:
25+
"""Auth tuple for a different user than noop default auth."""
26+
return (TEST_OTHER_USER_ID, "other-user", True, "test_token")
27+
28+
29+
async def create_prompt_via_handler(
30+
request: Request,
31+
auth: AuthTuple,
32+
name: str,
33+
content: str,
34+
) -> SavedPromptResponse:
35+
"""Create a saved prompt through the real create handler.
36+
37+
Parameters:
38+
request: FastAPI request for authorization middleware.
39+
auth: Authenticated user tuple.
40+
name: Prompt display name.
41+
content: Prompt body.
42+
43+
Returns:
44+
SavedPromptResponse from the create handler.
45+
"""
46+
return await create_saved_prompts_handler(
47+
request=request,
48+
body=SavedPromptCreateRequest(name=name, content=content),
49+
auth=auth,
50+
)
51+
52+
53+
@pytest.mark.asyncio
54+
async def test_get_saved_prompts_config_returns_limits(
55+
test_config: AppConfig,
56+
test_request: Request,
57+
test_auth: AuthTuple,
58+
) -> None:
59+
"""Config endpoint returns saved-prompts limits from loaded configuration."""
60+
expected = test_config.configuration.saved_prompts
61+
62+
response = await get_saved_prompts_config_handler(
63+
auth=test_auth,
64+
request=test_request,
65+
)
66+
67+
assert response.max_prompts_per_user == expected.max_prompts_per_user
68+
assert response.max_display_name_length == expected.max_display_name_length
69+
assert response.max_content_length == expected.max_content_length
70+
71+
72+
@pytest.mark.asyncio
73+
async def test_list_saved_prompts_empty_for_new_user(
74+
test_config: AppConfig,
75+
test_request: Request,
76+
test_auth: AuthTuple,
77+
patch_db_session: Session,
78+
) -> None:
79+
"""List returns an empty prompts array when the user has no saved prompts."""
80+
_ = test_config
81+
_ = patch_db_session
82+
83+
response = await list_saved_prompts_handler(
84+
auth=test_auth,
85+
request=test_request,
86+
)
87+
88+
assert response.prompts == []
89+
90+
91+
@pytest.mark.asyncio
92+
async def test_create_saved_prompt_persists_and_is_listable(
93+
test_config: AppConfig,
94+
test_request: Request,
95+
test_auth: AuthTuple,
96+
patch_db_session: Session,
97+
) -> None:
98+
"""Create returns prompt fields and the owning user can list it."""
99+
_ = test_config
100+
_ = patch_db_session
101+
102+
created = await create_prompt_via_handler(
103+
request=test_request,
104+
auth=test_auth,
105+
name="Deploy to staging",
106+
content="Help me write a deployment checklist",
107+
)
108+
109+
assert created.id
110+
assert created.name == "Deploy to staging"
111+
assert created.content == "Help me write a deployment checklist"
112+
assert created.created_at is not None
113+
assert created.updated_at is not None
114+
115+
listed = await list_saved_prompts_handler(
116+
auth=test_auth,
117+
request=test_request,
118+
)
119+
assert len(listed.prompts) == 1
120+
assert listed.prompts[0].id == created.id
121+
assert listed.prompts[0].name == "Deploy to staging"
122+
123+
124+
@pytest.mark.asyncio
125+
async def test_list_saved_prompts_isolates_users(
126+
test_config: AppConfig,
127+
test_request: Request,
128+
test_auth: AuthTuple,
129+
other_auth: AuthTuple,
130+
patch_db_session: Session,
131+
) -> None:
132+
"""List returns only the caller's prompts."""
133+
_ = test_config
134+
_ = patch_db_session
135+
136+
owned = await create_prompt_via_handler(
137+
request=test_request,
138+
auth=test_auth,
139+
name="owned-prompt",
140+
content="owned body",
141+
)
142+
other = await create_prompt_via_handler(
143+
request=test_request,
144+
auth=other_auth,
145+
name="other-user-prompt",
146+
content="should not appear",
147+
)
148+
149+
listed = await list_saved_prompts_handler(
150+
auth=test_auth,
151+
request=test_request,
152+
)
153+
154+
ids = [p.id for p in listed.prompts]
155+
assert owned.id in ids
156+
assert other.id not in ids
157+
158+
159+
@pytest.mark.asyncio
160+
async def test_create_saved_prompt_returns_422_when_limit_exceeded(
161+
test_config: AppConfig,
162+
test_request: Request,
163+
test_auth: AuthTuple,
164+
other_auth: AuthTuple,
165+
patch_db_session: Session,
166+
) -> None:
167+
"""Create returns 422 after the configured per-user maximum is reached."""
168+
_ = patch_db_session
169+
test_config.configuration.saved_prompts.max_prompts_per_user = 1
170+
171+
await create_prompt_via_handler(
172+
request=test_request,
173+
auth=test_auth,
174+
name="one",
175+
content="body one",
176+
)
177+
178+
other_created = await create_prompt_via_handler(
179+
request=test_request,
180+
auth=other_auth,
181+
name="other-user-one",
182+
content="other user body",
183+
)
184+
assert other_created.id
185+
186+
with pytest.raises(HTTPException) as exc_info:
187+
await create_prompt_via_handler(
188+
request=test_request,
189+
auth=test_auth,
190+
name="two",
191+
content="body two",
192+
)
193+
194+
assert exc_info.value.status_code == status.HTTP_422_UNPROCESSABLE_CONTENT
195+
196+
197+
@pytest.mark.asyncio
198+
async def test_delete_own_saved_prompt_removes_it_from_list(
199+
test_config: AppConfig,
200+
test_request: Request,
201+
test_auth: AuthTuple,
202+
patch_db_session: Session,
203+
) -> None:
204+
"""Deleting an owned prompt returns deleted=True and removes it from list."""
205+
_ = test_config
206+
_ = patch_db_session
207+
208+
created = await create_prompt_via_handler(
209+
request=test_request,
210+
auth=test_auth,
211+
name="to-delete",
212+
content="temporary",
213+
)
214+
215+
deleted = await delete_saved_prompts_handler(
216+
request=test_request,
217+
prompt_id=created.id,
218+
auth=test_auth,
219+
)
220+
assert deleted.deleted is True
221+
assert deleted.prompt_id == created.id
222+
223+
listed = await list_saved_prompts_handler(
224+
auth=test_auth,
225+
request=test_request,
226+
)
227+
assert listed.prompts == []
228+
229+
230+
@pytest.mark.asyncio
231+
async def test_delete_missing_saved_prompt_returns_deleted_false(
232+
test_config: AppConfig,
233+
test_request: Request,
234+
test_auth: AuthTuple,
235+
patch_db_session: Session,
236+
) -> None:
237+
"""Deleting a non-existent valid id returns deleted=False (idempotent)."""
238+
_ = test_config
239+
_ = patch_db_session
240+
241+
deleted = await delete_saved_prompts_handler(
242+
request=test_request,
243+
prompt_id=TEST_NON_EXISTENT_ID,
244+
auth=test_auth,
245+
)
246+
247+
assert deleted.deleted is False
248+
assert deleted.prompt_id == TEST_NON_EXISTENT_ID
249+
250+
251+
@pytest.mark.asyncio
252+
async def test_delete_other_users_saved_prompt_returns_403(
253+
test_config: AppConfig,
254+
test_request: Request,
255+
test_auth: AuthTuple,
256+
other_auth: AuthTuple,
257+
patch_db_session: Session,
258+
) -> None:
259+
"""Deleting another user's prompt raises HTTP 403."""
260+
_ = test_config
261+
_ = patch_db_session
262+
263+
other_prompt = await create_prompt_via_handler(
264+
request=test_request,
265+
auth=other_auth,
266+
name="owned-by-other",
267+
content="secret",
268+
)
269+
270+
with pytest.raises(HTTPException) as exc_info:
271+
await delete_saved_prompts_handler(
272+
request=test_request,
273+
prompt_id=other_prompt.id,
274+
auth=test_auth,
275+
)
276+
277+
assert exc_info.value.status_code == status.HTTP_403_FORBIDDEN
278+
279+
remaining = await list_saved_prompts_handler(
280+
auth=other_auth,
281+
request=test_request,
282+
)
283+
assert any(prompt.id == other_prompt.id for prompt in remaining.prompts)

0 commit comments

Comments
 (0)