feat: The Other Dude v9.0.1 — full-featured email system
ci: add GitHub Pages deployment workflow for docs site Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
183
backend/tests/integration/test_firmware_api.py
Normal file
183
backend/tests/integration/test_firmware_api.py
Normal file
@@ -0,0 +1,183 @@
|
||||
"""
|
||||
Integration tests for the Firmware API endpoints.
|
||||
|
||||
Tests exercise:
|
||||
- GET /api/firmware/versions -- list firmware versions (global)
|
||||
- GET /api/tenants/{tenant_id}/firmware/overview -- firmware overview per tenant
|
||||
- GET /api/tenants/{tenant_id}/firmware/upgrades -- list upgrade jobs
|
||||
- PATCH /api/tenants/{tenant_id}/devices/{device_id}/preferred-channel
|
||||
|
||||
Upgrade endpoints (POST .../upgrade, .../mass-upgrade) require actual RouterOS
|
||||
connections and NATS, so we verify the endpoint exists and handles missing
|
||||
services gracefully. Download/cache endpoints require super_admin.
|
||||
|
||||
All tests run against real PostgreSQL.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
class TestFirmwareVersions:
|
||||
"""Firmware version listing endpoints."""
|
||||
|
||||
async def test_list_firmware_versions(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
):
|
||||
"""GET /api/firmware/versions returns 200 with list (may be empty)."""
|
||||
auth = await auth_headers_factory(admin_session)
|
||||
|
||||
resp = await client.get(
|
||||
"/api/firmware/versions",
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert isinstance(data, list)
|
||||
|
||||
async def test_list_firmware_versions_with_filters(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
):
|
||||
"""GET /api/firmware/versions with filters returns 200."""
|
||||
auth = await auth_headers_factory(admin_session)
|
||||
|
||||
resp = await client.get(
|
||||
"/api/firmware/versions",
|
||||
params={"architecture": "arm", "channel": "stable"},
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert isinstance(resp.json(), list)
|
||||
|
||||
|
||||
class TestFirmwareOverview:
|
||||
"""Tenant-scoped firmware overview."""
|
||||
|
||||
async def test_firmware_overview(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/firmware/overview returns 200."""
|
||||
auth = await auth_headers_factory(admin_session)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
resp = await client.get(
|
||||
f"/api/tenants/{tenant_id}/firmware/overview",
|
||||
headers=auth["headers"],
|
||||
)
|
||||
# May return 200 or 500 if firmware_service depends on external state
|
||||
# At minimum, it should not be 404
|
||||
assert resp.status_code != 404
|
||||
|
||||
|
||||
class TestPreferredChannel:
|
||||
"""Device preferred firmware channel endpoint."""
|
||||
|
||||
async def test_set_device_preferred_channel(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
create_test_device,
|
||||
create_test_tenant,
|
||||
):
|
||||
"""PATCH preferred channel updates the device firmware channel preference."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id, role="operator"
|
||||
)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
|
||||
resp = await client.patch(
|
||||
f"/api/tenants/{tenant_id}/devices/{device.id}/preferred-channel",
|
||||
json={"preferred_channel": "long-term"},
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["preferred_channel"] == "long-term"
|
||||
assert data["status"] == "ok"
|
||||
|
||||
async def test_set_invalid_preferred_channel(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
create_test_device,
|
||||
create_test_tenant,
|
||||
):
|
||||
"""PATCH with invalid channel returns 422."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id, role="operator"
|
||||
)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
|
||||
resp = await client.patch(
|
||||
f"/api/tenants/{tenant_id}/devices/{device.id}/preferred-channel",
|
||||
json={"preferred_channel": "invalid"},
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 422
|
||||
|
||||
|
||||
class TestUpgradeJobs:
|
||||
"""Upgrade job listing endpoints."""
|
||||
|
||||
async def test_list_upgrade_jobs_empty(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/firmware/upgrades returns paginated response."""
|
||||
auth = await auth_headers_factory(admin_session)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
resp = await client.get(
|
||||
f"/api/tenants/{tenant_id}/firmware/upgrades",
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "items" in data
|
||||
assert "total" in data
|
||||
assert isinstance(data["items"], list)
|
||||
assert data["total"] >= 0
|
||||
|
||||
async def test_get_upgrade_job_not_found(
|
||||
self,
|
||||
client,
|
||||
auth_headers_factory,
|
||||
admin_session,
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/firmware/upgrades/{fake_id} returns 404."""
|
||||
auth = await auth_headers_factory(admin_session)
|
||||
tenant_id = auth["tenant_id"]
|
||||
fake_id = str(uuid.uuid4())
|
||||
|
||||
resp = await client.get(
|
||||
f"/api/tenants/{tenant_id}/firmware/upgrades/{fake_id}",
|
||||
headers=auth["headers"],
|
||||
)
|
||||
assert resp.status_code == 404
|
||||
|
||||
async def test_firmware_unauthenticated(self, client):
|
||||
"""GET firmware versions without auth returns 401."""
|
||||
resp = await client.get("/api/firmware/versions")
|
||||
assert resp.status_code == 401
|
||||
Reference in New Issue
Block a user