Multi-tenant factory inspection system (SpiFox, Enkid, Alpet): - FastAPI backend with JWT auth, PostgreSQL (asyncpg) - Next.js 16 frontend with App Router, SWR data fetching - Machines CRUD with equipment parts management - Part lifecycle tracking (hours/count/date) with counters - Partial unique index for soft-delete support - 24 pytest tests passing, E2E verified Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
138 lines
4.2 KiB
Python
138 lines
4.2 KiB
Python
import pytest
|
|
from httpx import AsyncClient
|
|
from tests.conftest import get_auth_headers
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_machine(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
resp = await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "1호기", "equipment_code": "TC-001", "model": "Press A"},
|
|
headers=headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["name"] == "1호기"
|
|
assert data["equipment_code"] == "TC-001"
|
|
assert data["tenant_id"] == "test-co"
|
|
assert data["parts_count"] == 0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_machines(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "1호기", "equipment_code": "TC-001"},
|
|
headers=headers,
|
|
)
|
|
await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "2호기", "equipment_code": "TC-002"},
|
|
headers=headers,
|
|
)
|
|
|
|
resp = await client.get("/api/test-co/machines", headers=headers)
|
|
assert resp.status_code == 200
|
|
machines = resp.json()["machines"]
|
|
assert len(machines) == 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_machine_detail(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
create_resp = await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "1호기", "equipment_code": "TC-001"},
|
|
headers=headers,
|
|
)
|
|
machine_id = create_resp.json()["id"]
|
|
|
|
resp = await client.get(f"/api/test-co/machines/{machine_id}", headers=headers)
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["name"] == "1호기"
|
|
assert data["parts"] == []
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_machine(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
create_resp = await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "1호기"},
|
|
headers=headers,
|
|
)
|
|
machine_id = create_resp.json()["id"]
|
|
|
|
resp = await client.put(
|
|
f"/api/test-co/machines/{machine_id}",
|
|
json={"name": "1호기 (수정)", "equipment_code": "NEW-001"},
|
|
headers=headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["name"] == "1호기 (수정)"
|
|
assert resp.json()["equipment_code"] == "NEW-001"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_machine(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
create_resp = await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "삭제할 설비"},
|
|
headers=headers,
|
|
)
|
|
machine_id = create_resp.json()["id"]
|
|
|
|
resp = await client.delete(f"/api/test-co/machines/{machine_id}", headers=headers)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["status"] == "success"
|
|
|
|
get_resp = await client.get(f"/api/test-co/machines/{machine_id}", headers=headers)
|
|
assert get_resp.status_code == 404
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tenant_isolation(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client)
|
|
|
|
await client.post(
|
|
"/api/test-co/machines",
|
|
json={"name": "test-co 설비"},
|
|
headers=headers,
|
|
)
|
|
await client.post(
|
|
"/api/other-co/machines",
|
|
json={"name": "other-co 설비"},
|
|
headers=headers,
|
|
)
|
|
|
|
resp_test = await client.get("/api/test-co/machines", headers=headers)
|
|
resp_other = await client.get("/api/other-co/machines", headers=headers)
|
|
|
|
assert len(resp_test.json()["machines"]) == 1
|
|
assert len(resp_other.json()["machines"]) == 1
|
|
assert resp_test.json()["machines"][0]["name"] == "test-co 설비"
|
|
assert resp_other.json()["machines"][0]["name"] == "other-co 설비"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_machine_unauthenticated(client: AsyncClient, seeded_db):
|
|
resp = await client.get("/api/test-co/machines")
|
|
assert resp.status_code == 401
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tenant_access_denied(client: AsyncClient, seeded_db):
|
|
headers = await get_auth_headers(client, email="admin@test-co.com")
|
|
|
|
resp = await client.get("/api/other-co/machines", headers=headers)
|
|
assert resp.status_code == 403
|