Some checks failed
Lint & Test / test (push) Failing after 9s
Auto-fixed 138 unused imports and f-string issues. Manually fixed: ambiguous variable names (l→layer), availability-check imports using importlib.util.find_spec, unused Color import, ImagePool forward ref via TYPE_CHECKING, multi-statement semicolons, and E402 suppression.
124 lines
4.4 KiB
Python
124 lines
4.4 KiB
Python
"""E2E: Output target lifecycle.
|
|
|
|
Tests target CRUD with a dependency on a device:
|
|
create device -> create target -> list -> update -> delete target -> cleanup device.
|
|
"""
|
|
|
|
|
|
|
|
class TestOutputTargetLifecycle:
|
|
"""A user wires up an output target to a device."""
|
|
|
|
def _create_device(self, client) -> str:
|
|
"""Helper: create a mock device and return its ID."""
|
|
resp = client.post("/api/v1/devices", json={
|
|
"name": "Target Test Device",
|
|
"url": "mock://target-test",
|
|
"device_type": "mock",
|
|
"led_count": 60,
|
|
})
|
|
assert resp.status_code == 201
|
|
return resp.json()["id"]
|
|
|
|
def test_full_target_crud_lifecycle(self, client):
|
|
device_id = self._create_device(client)
|
|
|
|
# 1. List targets -- should be empty
|
|
resp = client.get("/api/v1/output-targets")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["count"] == 0
|
|
|
|
# 2. Create an output target referencing the device
|
|
create_payload = {
|
|
"name": "E2E Test Target",
|
|
"target_type": "led",
|
|
"device_id": device_id,
|
|
"fps": 30,
|
|
"protocol": "ddp",
|
|
"tags": ["e2e"],
|
|
}
|
|
resp = client.post("/api/v1/output-targets", json=create_payload)
|
|
assert resp.status_code == 201, f"Create failed: {resp.text}"
|
|
target = resp.json()
|
|
target_id = target["id"]
|
|
assert target["name"] == "E2E Test Target"
|
|
assert target["device_id"] == device_id
|
|
assert target["target_type"] == "led"
|
|
assert target["fps"] == 30
|
|
assert target["protocol"] == "ddp"
|
|
|
|
# 3. List targets -- should contain the new target
|
|
resp = client.get("/api/v1/output-targets")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["count"] == 1
|
|
assert data["targets"][0]["id"] == target_id
|
|
|
|
# 4. Get target by ID
|
|
resp = client.get(f"/api/v1/output-targets/{target_id}")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["name"] == "E2E Test Target"
|
|
|
|
# 5. Update the target -- change name and fps
|
|
resp = client.put(
|
|
f"/api/v1/output-targets/{target_id}",
|
|
json={"name": "Updated Target", "fps": 60},
|
|
)
|
|
assert resp.status_code == 200
|
|
updated = resp.json()
|
|
assert updated["name"] == "Updated Target"
|
|
assert updated["fps"] == 60
|
|
|
|
# 6. Verify update via GET
|
|
resp = client.get(f"/api/v1/output-targets/{target_id}")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["name"] == "Updated Target"
|
|
|
|
# 7. Delete the target
|
|
resp = client.delete(f"/api/v1/output-targets/{target_id}")
|
|
assert resp.status_code == 204
|
|
|
|
# 8. Verify target is gone
|
|
resp = client.get(f"/api/v1/output-targets/{target_id}")
|
|
assert resp.status_code == 404
|
|
|
|
# 9. Clean up the device
|
|
resp = client.delete(f"/api/v1/devices/{device_id}")
|
|
assert resp.status_code == 204
|
|
|
|
def test_cannot_delete_device_referenced_by_target(self, client):
|
|
"""Deleting a device that has a target should return 409."""
|
|
device_id = self._create_device(client)
|
|
|
|
resp = client.post("/api/v1/output-targets", json={
|
|
"name": "Blocking Target",
|
|
"target_type": "led",
|
|
"device_id": device_id,
|
|
})
|
|
assert resp.status_code == 201
|
|
target_id = resp.json()["id"]
|
|
|
|
# Attempt to delete device -- should fail
|
|
resp = client.delete(f"/api/v1/devices/{device_id}")
|
|
assert resp.status_code == 409
|
|
assert "referenced" in resp.json()["detail"].lower()
|
|
|
|
# Clean up: delete target first, then device
|
|
resp = client.delete(f"/api/v1/output-targets/{target_id}")
|
|
assert resp.status_code == 204
|
|
resp = client.delete(f"/api/v1/devices/{device_id}")
|
|
assert resp.status_code == 204
|
|
|
|
def test_create_target_with_invalid_device_returns_422(self, client):
|
|
"""Creating a target with a non-existent device_id returns 422."""
|
|
resp = client.post("/api/v1/output-targets", json={
|
|
"name": "Orphan Target",
|
|
"target_type": "led",
|
|
"device_id": "nonexistent_device",
|
|
})
|
|
assert resp.status_code == 422
|
|
|
|
def test_get_nonexistent_target_returns_404(self, client):
|
|
resp = client.get("/api/v1/output-targets/nonexistent_id")
|
|
assert resp.status_code == 404
|