chore: complete v1.0 milestone
Archive v1.0 MVP: 7 phases, 13 plans, 27/27 requirements. - Archive roadmap to milestones/v1.0-ROADMAP.md - Archive requirements to milestones/v1.0-REQUIREMENTS.md - Move milestone audit into milestones/ - Create MILESTONES.md with v1.0 entry - Evolve PROJECT.md: move shipped requirements to Validated, update Context with stack/LOC, log Key Decisions with outcomes - Collapse ROADMAP.md to one-line milestone summary - Update STATE.md to shipped status - Back-fill stale requirements-completed frontmatter on 02-01, 04-01, 05-01, 06-01 SUMMARY.md files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-2
@@ -110,7 +110,7 @@ def test_driver_store_save(db_env, tmp_path):
|
||||
result = store.save(data)
|
||||
|
||||
assert result == expected_sha256
|
||||
assert (drivers_dir / expected_sha256).exists()
|
||||
assert (drivers_dir / f"{expected_sha256}.zip").exists()
|
||||
|
||||
|
||||
def test_driver_store_dedup(db_env):
|
||||
@@ -138,4 +138,4 @@ def test_driver_store_get_path(db_env):
|
||||
sha256 = "abcdef1234567890" * 4 # 64 hex chars
|
||||
path = store.get_path(sha256)
|
||||
|
||||
assert path == Path(str(drivers_dir)) / sha256
|
||||
assert path == Path(str(drivers_dir)) / f"{sha256}.zip"
|
||||
|
||||
@@ -121,7 +121,7 @@ def test_driver_persisted(client: TestClient, tmp_data_dir) -> None:
|
||||
count = Driver.select().where(Driver.sha256 == expected_sha).count()
|
||||
assert count == 1
|
||||
|
||||
driver_file = tmp_data_dir / "drivers" / expected_sha
|
||||
driver_file = tmp_data_dir / "drivers" / f"{expected_sha}.zip"
|
||||
assert driver_file.exists()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""End-to-end guard: upload a driver through the HTTP endpoint, then export
|
||||
a NinjaRMM package from the resulting Driver record. This prevents regressions
|
||||
where DriverStore save path and packages.py driver lookup path diverge."""
|
||||
import io
|
||||
import json
|
||||
import zipfile
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def driver_zip_bytes():
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
||||
zf.writestr("printer.inf", "[Version]\nSignature=$WINDOWS NT$\n")
|
||||
zf.writestr("printer.cat", "FAKE_CAT")
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def test_upload_then_ninja_export_finds_driver_on_disk(
|
||||
client, tmp_data_dir, driver_zip_bytes
|
||||
):
|
||||
from imptune.db.models import Client, Driver, Printer
|
||||
|
||||
upload_resp = client.post(
|
||||
"/drivers/upload",
|
||||
files={"file": ("printer_driver.zip", driver_zip_bytes, "application/zip")},
|
||||
)
|
||||
assert upload_resp.status_code == 200
|
||||
|
||||
driver = Driver.select().order_by(Driver.id.desc()).first()
|
||||
assert driver is not None
|
||||
driver.driver_desc = json.dumps(["HP LaserJet Pro"])
|
||||
driver.save()
|
||||
|
||||
tenant = Client.create(name="Acme Corp")
|
||||
printer = Printer.create(
|
||||
name="Round Trip Printer",
|
||||
ip_address="192.168.1.50",
|
||||
port_name="IP_192.168.1.50",
|
||||
client=tenant,
|
||||
driver=driver,
|
||||
)
|
||||
|
||||
resp = client.get(f"/printers/{printer.id}/packages/ninja")
|
||||
assert resp.status_code == 200, resp.text
|
||||
assert resp.headers["content-type"] == "application/zip"
|
||||
|
||||
out = zipfile.ZipFile(io.BytesIO(resp.content))
|
||||
names = out.namelist()
|
||||
assert any(n.endswith("install.ps1") for n in names)
|
||||
assert any("drivers/printer.inf" in n for n in names)
|
||||
Reference in New Issue
Block a user