Skip to content

Commit 8e43255

Browse files
tests: Add async live delete tests and improve sync/async error handling
- Added async live delete tests under `test_live_delete.py`, covering success, invalid ID, and missing ID scenarios for `AsyncPdfRestClient`. - Improved exception handling to use `pytest.RaisesGroup` for both sync and async delete error aggregation. - Enhanced test customization to validate extra query parameters, headers, and timeout behavior during async operations. Assisted-by: Codex
1 parent a277af0 commit 8e43255

2 files changed

Lines changed: 140 additions & 16 deletions

File tree

tests/live/test_live_delete.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
import pytest
66
from pydantic import ValidationError
77

8-
from pdfrest import PdfRestClient, PdfRestDeleteError, PdfRestErrorGroup
8+
from pdfrest import (
9+
AsyncPdfRestClient,
10+
PdfRestClient,
11+
PdfRestDeleteError,
12+
PdfRestErrorGroup,
13+
)
914
from pdfrest.models import PdfRestFileID
1015

1116
from ..resources import get_test_resource_path
@@ -26,6 +31,22 @@ def test_live_delete_files_success(
2631
assert result is None
2732

2833

34+
@pytest.mark.asyncio
35+
async def test_live_async_delete_files_success(
36+
pdfrest_api_key: str,
37+
pdfrest_live_base_url: str,
38+
) -> None:
39+
resource = get_test_resource_path("report.pdf")
40+
async with AsyncPdfRestClient(
41+
api_key=pdfrest_api_key,
42+
base_url=pdfrest_live_base_url,
43+
) as client:
44+
uploaded = (await client.files.create_from_paths([resource]))[0]
45+
result = await client.files.delete(uploaded)
46+
47+
assert result is None
48+
49+
2950
def test_live_delete_files_invalid_id(
3051
pdfrest_api_key: str,
3152
pdfrest_live_base_url: str,
@@ -40,6 +61,21 @@ def test_live_delete_files_invalid_id(
4061
client.files.delete(uploaded, extra_body={"ids": token_urlsafe(16)})
4162

4263

64+
@pytest.mark.asyncio
65+
async def test_live_async_delete_files_invalid_id(
66+
pdfrest_api_key: str,
67+
pdfrest_live_base_url: str,
68+
) -> None:
69+
resource = get_test_resource_path("report.pdf")
70+
async with AsyncPdfRestClient(
71+
api_key=pdfrest_api_key,
72+
base_url=pdfrest_live_base_url,
73+
) as client:
74+
uploaded = (await client.files.create_from_paths([resource]))[0]
75+
with pytest.raises(ValidationError):
76+
await client.files.delete(uploaded, extra_body={"ids": token_urlsafe(16)})
77+
78+
4379
def test_live_delete_files_missing_id(
4480
pdfrest_api_key: str,
4581
pdfrest_live_base_url: str,
@@ -67,3 +103,33 @@ def test_live_delete_files_missing_id(
67103
client.files.delete(
68104
uploaded, extra_body={"ids": ",".join([bad_id_1, bad_id_2])}
69105
)
106+
107+
108+
@pytest.mark.asyncio
109+
async def test_live_async_delete_files_missing_id(
110+
pdfrest_api_key: str,
111+
pdfrest_live_base_url: str,
112+
) -> None:
113+
resource = get_test_resource_path("report.pdf")
114+
async with AsyncPdfRestClient(
115+
api_key=pdfrest_api_key,
116+
base_url=pdfrest_live_base_url,
117+
) as client:
118+
bad_id_1 = PdfRestFileID.generate()
119+
bad_id_2 = PdfRestFileID.generate()
120+
uploaded = (await client.files.create_from_paths([resource]))[0]
121+
with pytest.RaisesGroup(
122+
pytest.RaisesExc(
123+
PdfRestDeleteError,
124+
match=f"Failed to delete file {bad_id_1}.*does not exist",
125+
),
126+
pytest.RaisesExc(
127+
PdfRestDeleteError,
128+
match=f"Failed to delete file {bad_id_2}.*does not exist",
129+
),
130+
match="Failed to delete one or more files.",
131+
check=lambda eg: isinstance(eg, PdfRestErrorGroup),
132+
):
133+
await client.files.delete(
134+
uploaded, extra_body={"ids": ",".join([bad_id_1, bad_id_2])}
135+
)

tests/test_delete_files.py

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ def test_delete_payload_serialization() -> None:
2727

2828

2929
def test_delete_payload_rejects_empty() -> None:
30-
with pytest.raises(ValidationError):
30+
with pytest.raises(
31+
ValidationError,
32+
match="List should have at least 1 item after validation",
33+
):
3134
DeletePayload.model_validate({"files": []})
3235

3336

@@ -133,16 +136,19 @@ def handler(request: httpx.Request) -> httpx.Response:
133136
transport = httpx.MockTransport(handler)
134137
with (
135138
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
136-
pytest.raises(PdfRestErrorGroup) as exc_info,
139+
pytest.RaisesGroup(
140+
pytest.RaisesExc(
141+
PdfRestDeleteError,
142+
match=(
143+
f"Failed to delete file {file_repr.id}.*File could not be deleted"
144+
),
145+
),
146+
match="Failed to delete one or more files.",
147+
check=lambda eg: isinstance(eg, PdfRestErrorGroup),
148+
),
137149
):
138150
client.files.delete(file_repr)
139151

140-
assert len(exc_info.value.exceptions) == 1
141-
inner = exc_info.value.exceptions[0]
142-
assert isinstance(inner, PdfRestDeleteError)
143-
assert inner.file_id == str(file_repr.id)
144-
assert "File could not be deleted" in str(inner)
145-
146152

147153
def test_delete_files_aggregates_multiple_failures(
148154
monkeypatch: pytest.MonkeyPatch,
@@ -168,16 +174,17 @@ def handler(request: httpx.Request) -> httpx.Response:
168174
transport = httpx.MockTransport(handler)
169175
with (
170176
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
171-
pytest.raises(PdfRestErrorGroup) as exc_info,
177+
pytest.RaisesGroup(
178+
pytest.RaisesExc(
179+
PdfRestDeleteError,
180+
match=f"Failed to delete file {second.id}.*Permission denied",
181+
),
182+
match="Failed to delete one or more files.",
183+
check=lambda eg: isinstance(eg, PdfRestErrorGroup),
184+
),
172185
):
173186
client.files.delete([first, second])
174187

175-
assert len(exc_info.value.exceptions) == 1
176-
inner = exc_info.value.exceptions[0]
177-
assert isinstance(inner, PdfRestDeleteError)
178-
assert inner.file_id == str(second.id)
179-
assert "Permission denied" in str(inner)
180-
181188

182189
@pytest.mark.asyncio
183190
async def test_async_delete_files_success(
@@ -218,6 +225,57 @@ def handler(request: httpx.Request) -> httpx.Response:
218225
assert result is None
219226

220227

228+
@pytest.mark.asyncio
229+
async def test_async_delete_files_request_customization(
230+
monkeypatch: pytest.MonkeyPatch,
231+
) -> None:
232+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
233+
file_repr = make_pdf_file(PdfRestFileID.generate(2))
234+
captured_timeout: dict[str, float | dict[str, float] | None] = {}
235+
236+
def handler(request: httpx.Request) -> httpx.Response:
237+
if request.method == "POST" and request.url.path == "/delete":
238+
assert request.url.params["trace"] == "async"
239+
assert request.headers["X-Debug"] == "async"
240+
captured_timeout["value"] = request.extensions.get("timeout")
241+
payload = json.loads(request.content.decode("utf-8"))
242+
assert payload["ids"] == str(file_repr.id)
243+
assert payload["diagnostics"] == "enabled"
244+
return httpx.Response(
245+
200,
246+
json={
247+
"deletionResponses": {
248+
str(file_repr.id): "Successfully Deleted",
249+
}
250+
},
251+
)
252+
msg = f"Unexpected request {request.method} {request.url}"
253+
raise AssertionError(msg)
254+
255+
transport = httpx.MockTransport(handler)
256+
async with AsyncPdfRestClient(
257+
api_key=ASYNC_API_KEY,
258+
transport=transport,
259+
) as client:
260+
result = await client.files.delete(
261+
file_repr,
262+
extra_query={"trace": "async"},
263+
extra_headers={"X-Debug": "async"},
264+
extra_body={"diagnostics": "enabled"},
265+
timeout=0.55,
266+
)
267+
268+
assert result is None
269+
timeout_value = captured_timeout["value"]
270+
assert timeout_value is not None
271+
if isinstance(timeout_value, dict):
272+
assert all(
273+
component == pytest.approx(0.55) for component in timeout_value.values()
274+
)
275+
else:
276+
assert timeout_value == pytest.approx(0.55)
277+
278+
221279
@pytest.mark.asyncio
222280
async def test_async_delete_files_raises_error_group(
223281
monkeypatch: pytest.MonkeyPatch,

0 commit comments

Comments
 (0)