Johnntirs's picture
Room Visualizer backend (Docker)
0cdb4e8
Raw
History Blame Contribute Delete
3.95 kB
"""End-to-end smoke test for the mock pipeline (no network, no GPU).
Creates synthetic room images, drives every endpoint via FastAPI's TestClient,
and asserts the generated output file actually lands on disk.
Run: python scripts/smoke_test.py
"""
from __future__ import annotations
import io
import sys
from pathlib import Path
from PIL import Image, ImageDraw
BACKEND_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(BACKEND_DIR))
from fastapi.testclient import TestClient # noqa: E402
from app.config import settings # noqa: E402
from app.main import app # noqa: E402
def make_room(floor_rgb, wall_rgb) -> bytes:
"""A trivial 'room': wall on the upper half, floor on the lower half."""
w, h = 1024, 768
img = Image.new("RGB", (w, h), wall_rgb)
ImageDraw.Draw(img).rectangle([0, int(h * 0.5), w, h], fill=floor_rgb)
buf = io.BytesIO()
img.save(buf, format="JPEG")
return buf.getvalue()
def main() -> int:
with TestClient(app) as client: # `with` runs the lifespan (init_db)
r = client.get("/")
assert r.status_code == 200, r.text
print("health:", r.json())
r = client.get("/get-catalog")
assert r.status_code == 200, r.text
catalog = r.json()
print("catalog items:", len(catalog))
assert 30 <= len(catalog) <= 40, "catalog must have 30-40 items"
r = client.get("/get-catalog", params={"styles": "modern,minimal", "category": "sofa"})
recs = r.json()
print("top sofa for modern,minimal:", recs[0]["name"], "score=", recs[0]["score"])
assert recs[0]["score"] >= recs[-1]["score"], "recommendations must be ranked"
files = [
("files", ("room1.jpg", make_room((150, 140, 130), (210, 205, 200)), "image/jpeg")),
("files", ("room2.jpg", make_room((120, 130, 140), (200, 205, 210)), "image/jpeg")),
("files", ("room3.jpg", make_room((140, 120, 110), (205, 200, 195)), "image/jpeg")),
]
r = client.post("/upload-room", files=files)
assert r.status_code == 200, r.text
up = r.json()
sid, img_id = up["session_id"], up["images"][0]["id"]
print("uploaded:", len(up["images"]), "images; session", sid[:8])
assert len(up["images"]) == 3
# too-few-images guard
r = client.post("/upload-room", files=files[:1])
assert r.status_code == 400, "should reject < 3 images"
r = client.post("/analyze-room", json={"session_id": sid, "image_id": img_id})
assert r.status_code == 200, r.text
an = r.json()
print(
"analyze: objects=", len(an["detected_objects"]),
"floor_pts=", len(an["floor_polygon"]),
"free=", an["free_space_ratio"],
"ml_used=", an["ml_used"],
)
assert len(an["floor_polygon"]) >= 3, "need a usable-floor polygon"
item_ids = [catalog[0]["id"], catalog[7]["id"]]
r = client.post(
"/generate-room",
json={"session_id": sid, "image_id": img_id, "item_ids": item_ids},
)
assert r.status_code == 200, r.text
gen = r.json()
print("generated:", gen["image_url"], "via", gen["provider"])
assert gen["provider"] == "mock"
rel = gen["image_url"].split("/static/")[-1]
out = settings.STATIC_DIR / rel
assert out.exists(), f"missing output file {out}"
print("output exists:", out.name, out.stat().st_size, "bytes")
for p in gen["placements"]:
print(" placement", p["item_id"], "->", p["scale_note"])
# confirm /remove-object does NOT exist
r = client.post("/remove-object", json={})
assert r.status_code == 404, "/remove-object must not exist"
print("confirmed: /remove-object returns 404 (removal is OUT)")
print("\nSMOKE TEST PASSED")
return 0
if __name__ == "__main__":
raise SystemExit(main())