Files

176 lines
6.1 KiB
Python
Raw Permalink Normal View History

from io import BytesIO
import pytest
from PIL import Image
from pigway_frame_flow.providers.photo_sources import PhotoSourceInput
def setup_photos(service, settings):
root = settings.data_dir.parent / "photos"
root.mkdir()
settings.photo_root = root
Image.new("RGB", (300, 200)).save(root / "a.jpg")
service.photo_sources.save(
"family", PhotoSourceInput(name="Family", kind="local", location=".")
)
def make_job(client, name):
r = client.post(
"/api/v1/jobs",
json={
"name": name,
"enabled": False,
"schedule": {"type": "daily", "time": "07:00"},
"source": {"type": "photo_source", "source_id": "family"},
},
)
assert r.status_code == 201
return r.json()["id"]
def run(client, service, job, confirm=True):
r = client.post(f"/api/v1/jobs/{job}/run")
assert r.status_code == 202, r.text
id = r.json()["operation_id"]
service.process_one()
if confirm:
service.sync()
op = client.get("/api/v1/operations/" + id).json()
return op["result"]["image_id"], op["result"]["rendered_asset_id"]
def test_task_origin_filter_and_star_bulk(client, service, settings):
setup_photos(service, settings)
job = make_job(client, "Family random")
image, asset = run(client, service, job)
rows = client.get("/api/v1/assets", params={"origin": "task", "job_id": job}).json()
assert len(rows) == 1 and rows[0]["job_name"] == "Family random"
r = client.post(
"/api/v1/assets/batch", json={"action": "star", "asset_ids": [asset, asset]}
)
assert len(r.json()["results"]) == 1
assert client.get("/api/v1/assets").json()[0]["starred"]
r = client.post(
"/api/v1/assets/batch",
json={"action": "delete", "asset_ids": [asset, "missing"]},
)
assert [x["status"] for x in r.json()["results"]] == ["completed", "failed"]
def test_each_task_keeps_one_after_confirmation(client, service, settings):
setup_photos(service, settings)
job = make_job(client, "A")
first, _ = run(client, service, job)
second, _ = run(client, service, job)
service.cloud_library.sweep()
assert service.process_one()
assert first not in {
x.image_id for x in service.registry.get("living-room").images()
}
assert second in {x.image_id for x in service.registry.get("living-room").images()}
other = make_job(client, "B")
third, _ = run(client, service, other)
service.cloud_library.checked = 0
service.cloud_library.sweep()
assert second in {x.image_id for x in service.registry.get("living-room").images()}
assert third in {x.image_id for x in service.registry.get("living-room").images()}
def test_unconfirmed_replacement_never_evicts_previous(client, service, settings):
setup_photos(service, settings)
job = make_job(client, "A")
first, _ = run(client, service, job)
second, _ = run(client, service, job, confirm=False)
service.cloud_library.sweep()
assert not service.process_one()
assert first in {x.image_id for x in service.registry.get("living-room").images()}
assert not service.db.one(
"SELECT cleanup_operation FROM managed_cloud_uploads WHERE image_id=?", (first,)
)["cleanup_operation"]
def test_starred_old_upload_survives_then_unstar_cleans(client, service, settings):
setup_photos(service, settings)
job = make_job(client, "A")
first, asset = run(client, service, job)
assert (
client.put(f"/api/v1/assets/{asset}/star", json={"starred": True}).status_code
== 200
)
run(client, service, job)
service.cloud_library.sweep()
assert not service.process_one()
assert (
client.put(f"/api/v1/assets/{asset}/star", json={"starred": False}).status_code
== 200
)
service.cloud_library.checked = 0
service.cloud_library.sweep()
assert service.process_one()
assert first not in {
x.image_id for x in service.registry.get("living-room").images()
}
assert service.assets.path(asset).exists()
def test_manual_upload_origin(client, service):
buf = BytesIO()
Image.new("RGB", (30, 20)).save(buf, "JPEG")
r = client.post(
"/api/v1/preview", files={"file": ("manual.jpg", buf.getvalue(), "image/jpeg")}
)
id = r.json()["asset_id"]
r = client.post(
"/api/v1/devices/living-room/upload", json={"type": "image", "asset_id": id}
)
service.process_one()
rows = client.get("/api/v1/assets", params={"origin": "manual"}).json()
assert len(rows) == 1 and rows[0]["asset_id"] == id
def test_clear_cloud_requires_confirmation_and_clears_current(client, service):
before = len(service.registry.get("living-room").images())
assert (
client.post(
"/api/v1/devices/living-room/images/clear", json={"confirm_current": False}
).status_code
== 400
)
r = client.post(
"/api/v1/devices/living-room/images/clear", json={"confirm_current": True}
)
assert r.status_code == 200 and len(r.json()["operations"]) == before
for _ in range(before):
assert service.process_one()
assert not service.registry.get("living-room").images()
def test_manual_display_does_not_replace_task_head(client, service, settings):
setup_photos(service, settings)
job = make_job(client, "A")
first, asset = run(client, service, job)
second, _ = run(client, service, job)
client.put(f"/api/v1/assets/{asset}/star", json={"starred": True})
response = client.post(
"/api/v1/display", json={"content": {"type": "image", "asset_id": asset}}
)
service.process_one()
service.sync()
op = client.get("/api/v1/operations/" + response.json()["operation_id"]).json()
row = service.db.one(
"SELECT job_id FROM managed_cloud_uploads WHERE image_id=?",
(op["result"]["image_id"],),
)
assert row["job_id"] is None
assert service.cloud_library.retained(
service.db.one(
"SELECT * FROM managed_cloud_uploads WHERE image_id=?", (second,)
)
)
# Legacy algorithms remain covered; production filesystem access is tested separately.
pytestmark = pytest.mark.usefixtures("legacy_photo_engine")