test(02-02): add failing integration tests for driver upload
This commit is contained in:
@@ -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 <select> element."""
|
||||
zip_bytes = _make_driver_zip()
|
||||
resp = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("driver.zip", zip_bytes, "application/zip")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert "<select" in resp.text
|
||||
assert "Test LaserJet Pro" in resp.text
|
||||
|
||||
|
||||
def test_driver_persisted(client: TestClient, tmp_data_dir) -> None:
|
||||
"""After upload, Driver record exists in DB and file exists in DriverStore."""
|
||||
from imptune.db.models import Driver
|
||||
|
||||
zip_bytes = _make_driver_zip()
|
||||
expected_sha = hashlib.sha256(zip_bytes).hexdigest()
|
||||
|
||||
resp = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("driver.zip", zip_bytes, "application/zip")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
count = Driver.select().where(Driver.sha256 == expected_sha).count()
|
||||
assert count == 1
|
||||
|
||||
driver_file = tmp_data_dir / "drivers" / expected_sha
|
||||
assert driver_file.exists()
|
||||
|
||||
|
||||
def test_dedup_upload(client: TestClient) -> None:
|
||||
"""Uploading the same ZIP twice creates only one Driver record."""
|
||||
from imptune.db.models import Driver
|
||||
|
||||
zip_bytes = _make_driver_zip()
|
||||
|
||||
resp1 = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("driver.zip", zip_bytes, "application/zip")},
|
||||
)
|
||||
assert resp1.status_code == 200
|
||||
|
||||
resp2 = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("driver.zip", zip_bytes, "application/zip")},
|
||||
)
|
||||
assert resp2.status_code == 200
|
||||
|
||||
sha = hashlib.sha256(zip_bytes).hexdigest()
|
||||
count = Driver.select().where(Driver.sha256 == sha).count()
|
||||
assert count == 1
|
||||
|
||||
|
||||
def test_unused_files_in_response(client: TestClient) -> None:
|
||||
"""Upload a ZIP with an extra file not in INF; response HTML mentions 'unused'."""
|
||||
zip_bytes = _make_driver_zip(
|
||||
extra_files={"readme.txt": b"This file is not referenced by the INF"}
|
||||
)
|
||||
resp = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("driver.zip", zip_bytes, "application/zip")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
# Response should indicate unused files (count or the word "unused")
|
||||
assert "unused" in resp.text.lower()
|
||||
Reference in New Issue
Block a user