Skip to content

Commit 77de4e2

Browse files
authored
Update test_files_api.py
1 parent 05f43ab commit 77de4e2

1 file changed

Lines changed: 42 additions & 3 deletions

File tree

‎tests/test_files_api.py‎

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,39 @@ def test_delete_unknown_file_404(self, client: TestClient) -> None:
118118
res = client.delete(f"/conversations/{conversation_id}/files/file_nope", headers=headers)
119119
assert res.status_code == 404
120120

121+
def test_upload_over_limit_413_and_leaves_no_partial(
122+
self, client: TestClient, monkeypatch: pytest.MonkeyPatch
123+
) -> None:
124+
"""The size cap is enforced while streaming, and the partial file
125+
is removed -- a half-written upload must not linger in the
126+
agent's cwd where it could be mistaken for real input."""
127+
from app.controllers import files as files_controller
128+
129+
monkeypatch.setattr(files_controller, "MAX_UPLOAD_BYTES", 8)
130+
headers, conversation_id = _setup(client)
131+
res = client.post(
132+
f"/conversations/{conversation_id}/files",
133+
headers=headers,
134+
files={"file": ("big.xlsx", b"x" * 64, "application/octet-stream")},
135+
)
136+
assert res.status_code == 413, res.text
137+
workspace = Path(get_settings().workspace_root) / conversation_id
138+
assert list(workspace.iterdir()) == []
139+
detail = client.get(f"/conversations/{conversation_id}", headers=headers).json()
140+
assert detail["files"] == []
141+
142+
def test_artifact_empty_name_is_not_a_listing(self, client: TestClient) -> None:
143+
"""A trailing slash must not be read as "download the workspace"."""
144+
headers, conversation_id = _setup(client)
145+
res = client.get(f"/conversations/{conversation_id}/artifacts/", headers=headers)
146+
assert res.status_code in (307, 400, 404), res.text
147+
121148
def test_run_prompt_includes_uploaded_files(self, client: TestClient) -> None:
122149
from app.controllers import manager as manager_mod
123150
from app.controllers.runner import ExecResult, Runner
124151

125152
class CapturingRunner(Runner):
126-
captured: list[str] = []
153+
captured: list[tuple[str, str]] = []
127154

128155
def create(self, user_id: str, conversation_id: str) -> str:
129156
return "sbx_files"
@@ -132,7 +159,7 @@ def destroy(self, sandbox_id: str) -> None:
132159
pass
133160

134161
def exec_run(self, sandbox_id, prompt, run_id, on_line=None, timeout=None):
135-
CapturingRunner.captured.append(prompt)
162+
CapturingRunner.captured.append((prompt, run_id))
136163
return ExecResult(
137164
exit_code=0,
138165
stdout='{"type": "result", "answer": "ok", "errors": []}\n',
@@ -165,7 +192,19 @@ def reap_idle(self, ttl_seconds: float) -> list[str]:
165192
continue
166193
break
167194
assert CapturingRunner.captured, "run never executed"
168-
assert "sales.xlsx" in CapturingRunner.captured[0]
195+
harness_prompt, run_id = CapturingRunner.captured[0]
196+
assert "sales.xlsx" in harness_prompt
197+
assert "Save any result files" in harness_prompt
198+
# the Run row keeps the user's verbatim prompt, not the
199+
# augmented harness prompt (the UI echoes it)
200+
from app.models import Run
201+
from app.models.db import get_session_factory
202+
203+
db = get_session_factory()()
204+
try:
205+
assert db.get(Run, run_id).prompt == "summarize"
206+
finally:
207+
db.close()
169208
finally:
170209
monkeypatched.undo()
171210

0 commit comments

Comments
 (0)