diff --git a/tests/test_driver_upload.py b/tests/test_driver_upload.py new file mode 100644 index 0000000..84849c9 --- /dev/null +++ b/tests/test_driver_upload.py @@ -0,0 +1,162 @@ +"""Integration tests for driver upload endpoint and drivers page.""" +import hashlib +import io +import json +import zipfile + +import pytest +from fastapi.testclient import TestClient + + +# --------------------------------------------------------------------------- +# Helper +# --------------------------------------------------------------------------- + +SAMPLE_INF = """\ +[Version] +Signature="$Windows NT$" +Class=Printer +Provider=%MFG% + +[Manufacturer] +%MFG%=Models,NTamd64 + +[Models.NTamd64] +%DRIVER_NAME%=Install,{12345678-1234-1234-1234-123456789012} + +[Strings] +MFG="Test Manufacturer" +DRIVER_NAME="Test LaserJet Pro" +""" + + +def _make_driver_zip( + inf_content: str = SAMPLE_INF, + inf_name: str = "sample.inf", + extra_files: dict[str, bytes] | None = None, +) -> bytes: + """Build an in-memory ZIP with one .inf file and optional extra files.""" + buf = io.BytesIO() + with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf: + zf.writestr(inf_name, inf_content.encode("utf-8")) + if extra_files: + for name, data in extra_files.items(): + zf.writestr(name, data) + return buf.getvalue() + + +# --------------------------------------------------------------------------- +# Tests +# --------------------------------------------------------------------------- + + +def test_drivers_page(client: TestClient) -> None: + """GET /drivers returns 200 with an upload form targeting /drivers/upload.""" + resp = client.get("/drivers") + assert resp.status_code == 200 + html = resp.text + assert 'type="file"' in html + assert "/drivers/upload" in html + assert "hx-post" in html + + +def test_upload_valid_zip(client: TestClient) -> None: + """POST /drivers/upload with a valid ZIP containing .inf returns 200 with driver name.""" + zip_bytes = _make_driver_zip() + resp = client.post( + "/drivers/upload", + files={"file": ("driver.zip", zip_bytes, "application/zip")}, + ) + assert resp.status_code == 200 + assert "Test LaserJet Pro" in resp.text + + +def test_upload_non_zip(client: TestClient) -> None: + """POST /drivers/upload with a .txt file (not a ZIP) returns 400.""" + resp = client.post( + "/drivers/upload", + files={"file": ("driver.zip", b"this is not a zip", "application/zip")}, + ) + assert resp.status_code == 400 + + +def test_upload_no_inf(client: TestClient) -> None: + """POST /drivers/upload with a ZIP containing no .inf returns 400.""" + buf = io.BytesIO() + with zipfile.ZipFile(buf, "w") as zf: + zf.writestr("readme.txt", b"no driver here") + zip_bytes = buf.getvalue() + resp = client.post( + "/drivers/upload", + files={"file": ("driver.zip", zip_bytes, "application/zip")}, + ) + assert resp.status_code == 400 + + +def test_upload_returns_select(client: TestClient) -> None: + """POST /drivers/upload with valid ZIP returns HTML containing a