Skip to content

Commit 3ded244

Browse files
Add tests of Unzip tool
Note use of `noqa: S105` in test_unzip_file.py. This is to silence warnings over a test password value used only in testing. Assisted-by: Codex
1 parent c688142 commit 3ded244

2 files changed

Lines changed: 304 additions & 0 deletions

File tree

tests/live/test_live_unzip.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from __future__ import annotations
2+
3+
import zipfile
4+
from pathlib import Path
5+
6+
import pytest
7+
8+
from pdfrest import AsyncPdfRestClient, PdfRestApiError, PdfRestClient
9+
from pdfrest.models import PdfRestFile
10+
11+
from ..resources import get_test_resource_path
12+
13+
14+
def _build_zip_payload(tmp_path: Path) -> Path:
15+
zip_path = tmp_path / "sample.zip"
16+
with zipfile.ZipFile(zip_path, "w") as bundle:
17+
report_path = get_test_resource_path("report.pdf")
18+
bundle.write(report_path, arcname="report.pdf")
19+
return zip_path
20+
21+
22+
@pytest.fixture(scope="module")
23+
def uploaded_zip_file(
24+
pdfrest_api_key: str,
25+
pdfrest_live_base_url: str,
26+
tmp_path_factory: pytest.TempPathFactory,
27+
) -> PdfRestFile:
28+
zip_path = _build_zip_payload(tmp_path_factory.mktemp("zip-input"))
29+
with PdfRestClient(
30+
api_key=pdfrest_api_key,
31+
base_url=pdfrest_live_base_url,
32+
) as client:
33+
return client.files.create_from_paths([zip_path])[0]
34+
35+
36+
def test_live_unzip_file(
37+
pdfrest_api_key: str,
38+
pdfrest_live_base_url: str,
39+
uploaded_zip_file: PdfRestFile,
40+
) -> None:
41+
with PdfRestClient(
42+
api_key=pdfrest_api_key,
43+
base_url=pdfrest_live_base_url,
44+
) as client:
45+
response = client.unzip_file(uploaded_zip_file)
46+
47+
assert response.output_files
48+
assert all(file.size > 0 for file in response.output_files)
49+
assert all(file.name for file in response.output_files)
50+
assert str(response.input_id) == str(uploaded_zip_file.id)
51+
52+
53+
def test_live_unzip_invalid_override(
54+
pdfrest_api_key: str,
55+
pdfrest_live_base_url: str,
56+
uploaded_zip_file: PdfRestFile,
57+
) -> None:
58+
with (
59+
PdfRestClient(
60+
api_key=pdfrest_api_key,
61+
base_url=pdfrest_live_base_url,
62+
) as client,
63+
pytest.raises(PdfRestApiError, match="id"),
64+
):
65+
client.unzip_file(
66+
uploaded_zip_file,
67+
extra_body={"id": "not-a-uuid"},
68+
)
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_live_unzip_file_async(
73+
pdfrest_api_key: str,
74+
pdfrest_live_base_url: str,
75+
uploaded_zip_file: PdfRestFile,
76+
) -> None:
77+
async with AsyncPdfRestClient(
78+
api_key=pdfrest_api_key,
79+
base_url=pdfrest_live_base_url,
80+
) as client:
81+
response = await client.unzip_file(
82+
uploaded_zip_file,
83+
extra_query={"trace": "async"},
84+
)
85+
86+
assert response.output_files
87+
assert all(file.size > 0 for file in response.output_files)
88+
assert all(file.name for file in response.output_files)
89+
assert str(response.input_id) == str(uploaded_zip_file.id)

tests/test_unzip_file.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
from __future__ import annotations
2+
3+
import json
4+
5+
import httpx
6+
import pytest
7+
from pydantic import ValidationError
8+
9+
from pdfrest import AsyncPdfRestClient, PdfRestClient
10+
from pdfrest.models import PdfRestFile, PdfRestFileBasedResponse, PdfRestFileID
11+
from pdfrest.models._internal import UnzipPayload
12+
13+
from .graphics_test_helpers import (
14+
ASYNC_API_KEY,
15+
VALID_API_KEY,
16+
build_file_info_payload,
17+
)
18+
19+
20+
def make_zip_file(file_id: str, name: str = "archive.zip") -> PdfRestFile:
21+
return PdfRestFile.model_validate(
22+
build_file_info_payload(file_id, name, "application/zip")
23+
)
24+
25+
26+
def test_unzip_file_success(monkeypatch: pytest.MonkeyPatch) -> None:
27+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
28+
zip_file = make_zip_file(str(PdfRestFileID.generate()))
29+
output_id = str(PdfRestFileID.generate())
30+
31+
payload_dump = UnzipPayload.model_validate({"files": zip_file}).model_dump(
32+
mode="json", by_alias=True, exclude_none=True, exclude_unset=True
33+
)
34+
35+
seen: dict[str, int] = {"post": 0, "get": 0}
36+
37+
def handler(request: httpx.Request) -> httpx.Response:
38+
if request.method == "POST" and request.url.path == "/unzip":
39+
seen["post"] += 1
40+
payload = json.loads(request.content.decode("utf-8"))
41+
assert payload == payload_dump
42+
return httpx.Response(
43+
200,
44+
json={
45+
"inputId": [zip_file.id],
46+
"files": [
47+
{
48+
"name": "inner.txt",
49+
"id": output_id,
50+
"outputUrl": f"https://api.pdfrest.com/resource/{output_id}",
51+
}
52+
],
53+
},
54+
)
55+
if request.method == "GET" and request.url.path == f"/resource/{output_id}":
56+
seen["get"] += 1
57+
assert request.url.params["format"] == "info"
58+
return httpx.Response(
59+
200,
60+
json=build_file_info_payload(
61+
output_id,
62+
"inner.txt",
63+
"text/plain",
64+
),
65+
)
66+
msg = f"Unexpected request {request.method} {request.url}"
67+
raise AssertionError(msg)
68+
69+
transport = httpx.MockTransport(handler)
70+
with PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client:
71+
response = client.unzip_file(zip_file)
72+
73+
assert seen == {"post": 1, "get": 1}
74+
assert isinstance(response, PdfRestFileBasedResponse)
75+
assert response.output_file.name == "inner.txt"
76+
assert response.output_file.type == "text/plain"
77+
assert str(response.input_id) == str(zip_file.id)
78+
79+
80+
def test_unzip_file_with_password_and_customization(
81+
monkeypatch: pytest.MonkeyPatch,
82+
) -> None:
83+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
84+
zip_file = make_zip_file(str(PdfRestFileID.generate()))
85+
output_id = str(PdfRestFileID.generate())
86+
captured_timeout: dict[str, float | dict[str, float] | None] = {}
87+
88+
password = "Secret123" # noqa: S105 - test-only password fixture
89+
90+
def handler(request: httpx.Request) -> httpx.Response:
91+
if request.method == "POST" and request.url.path == "/unzip":
92+
assert request.url.params["trace"] == "sync"
93+
assert request.headers["X-Debug"] == "sync"
94+
captured_timeout["value"] = request.extensions.get("timeout")
95+
payload = json.loads(request.content.decode("utf-8"))
96+
assert payload["id"] == str(zip_file.id)
97+
assert payload["password"] == password
98+
assert payload["diagnostics"] == "on"
99+
return httpx.Response(
100+
200,
101+
json={
102+
"inputId": [zip_file.id],
103+
"outputId": [output_id],
104+
},
105+
)
106+
if request.method == "GET" and request.url.path == f"/resource/{output_id}":
107+
assert request.url.params["trace"] == "sync"
108+
assert request.headers["X-Debug"] == "sync"
109+
return httpx.Response(
110+
200,
111+
json=build_file_info_payload(
112+
output_id,
113+
"custom-unzip.txt",
114+
"text/plain",
115+
),
116+
)
117+
msg = f"Unexpected request {request.method} {request.url}"
118+
raise AssertionError(msg)
119+
120+
transport = httpx.MockTransport(handler)
121+
with PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client:
122+
response = client.unzip_file(
123+
zip_file,
124+
password=password,
125+
extra_query={"trace": "sync"},
126+
extra_headers={"X-Debug": "sync"},
127+
extra_body={"diagnostics": "on"},
128+
timeout=0.25,
129+
)
130+
131+
assert isinstance(response, PdfRestFileBasedResponse)
132+
assert response.output_file.name == "custom-unzip.txt"
133+
timeout_value = captured_timeout["value"]
134+
assert timeout_value is not None
135+
if isinstance(timeout_value, dict):
136+
assert all(pytest.approx(0.25) == value for value in timeout_value.values())
137+
else:
138+
assert timeout_value == pytest.approx(0.25)
139+
140+
141+
def test_unzip_file_requires_zip(monkeypatch: pytest.MonkeyPatch) -> None:
142+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
143+
non_zip = PdfRestFile.model_validate(
144+
build_file_info_payload(
145+
str(PdfRestFileID.generate()), "document.pdf", "application/pdf"
146+
)
147+
)
148+
transport = httpx.MockTransport(lambda request: (_ for _ in ()).throw(RuntimeError))
149+
150+
with (
151+
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
152+
pytest.raises(ValidationError, match="Must be a ZIP file"),
153+
):
154+
client.unzip_file(non_zip)
155+
156+
157+
def test_unzip_file_single_input(monkeypatch: pytest.MonkeyPatch) -> None:
158+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
159+
first = make_zip_file(str(PdfRestFileID.generate()))
160+
second = make_zip_file(str(PdfRestFileID.generate()))
161+
transport = httpx.MockTransport(lambda request: (_ for _ in ()).throw(RuntimeError))
162+
163+
with (
164+
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
165+
pytest.raises(ValidationError, match="at most 1 item"),
166+
):
167+
client.unzip_file([first, second])
168+
169+
170+
@pytest.mark.asyncio
171+
async def test_async_unzip_file(monkeypatch: pytest.MonkeyPatch) -> None:
172+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
173+
zip_file = make_zip_file(str(PdfRestFileID.generate()))
174+
output_id = str(PdfRestFileID.generate())
175+
176+
payload_dump = UnzipPayload.model_validate({"files": zip_file}).model_dump(
177+
mode="json", by_alias=True, exclude_none=True, exclude_unset=True
178+
)
179+
180+
def handler(request: httpx.Request) -> httpx.Response:
181+
if request.method == "POST" and request.url.path == "/unzip":
182+
payload = json.loads(request.content.decode("utf-8"))
183+
assert payload == payload_dump
184+
return httpx.Response(
185+
200,
186+
json={
187+
"inputId": [zip_file.id],
188+
"files": [
189+
{
190+
"name": "async.txt",
191+
"id": output_id,
192+
"outputUrl": f"https://api.pdfrest.com/resource/{output_id}",
193+
}
194+
],
195+
},
196+
)
197+
if request.method == "GET" and request.url.path == f"/resource/{output_id}":
198+
return httpx.Response(
199+
200,
200+
json=build_file_info_payload(
201+
output_id,
202+
"async.txt",
203+
"text/plain",
204+
),
205+
)
206+
msg = f"Unexpected request {request.method} {request.url}"
207+
raise AssertionError(msg)
208+
209+
transport = httpx.MockTransport(handler)
210+
async with AsyncPdfRestClient(api_key=ASYNC_API_KEY, transport=transport) as client:
211+
response = await client.unzip_file(zip_file)
212+
213+
assert isinstance(response, PdfRestFileBasedResponse)
214+
assert response.output_file.name == "async.txt"
215+
assert str(response.input_id) == str(zip_file.id)

0 commit comments

Comments
 (0)