feat: Add CRUD tests for project and scenario models
This commit is contained in:
152
tests/test_project_scenario_routes.py
Normal file
152
tests/test_project_scenario_routes.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from models import MiningOperationType, ResourceType, ScenarioStatus
|
||||
|
||||
|
||||
def _create_project(client: TestClient, name: str = "Alpha Project") -> dict:
|
||||
payload = {
|
||||
"name": name,
|
||||
"location": "Chile",
|
||||
"operation_type": MiningOperationType.OPEN_PIT.value,
|
||||
"description": "Initial feasibility study",
|
||||
}
|
||||
response = client.post("/projects", json=payload)
|
||||
assert response.status_code == 201, response.text
|
||||
return response.json()
|
||||
|
||||
|
||||
def test_project_crud_cycle(client: TestClient) -> None:
|
||||
project = _create_project(client)
|
||||
project_id = project["id"]
|
||||
|
||||
fetch_response = client.get(f"/projects/{project_id}")
|
||||
assert fetch_response.status_code == 200
|
||||
assert fetch_response.json()["name"] == "Alpha Project"
|
||||
|
||||
list_response = client.get("/projects")
|
||||
project_ids = {item["id"] for item in list_response.json()}
|
||||
assert project_id in project_ids
|
||||
|
||||
update_payload = {"description": "Updated project description", "location": "Peru"}
|
||||
update_response = client.put(f"/projects/{project_id}", json=update_payload)
|
||||
assert update_response.status_code == 200
|
||||
assert update_response.json()["description"] == "Updated project description"
|
||||
assert update_response.json()["location"] == "Peru"
|
||||
|
||||
delete_response = client.delete(f"/projects/{project_id}")
|
||||
assert delete_response.status_code == 204
|
||||
|
||||
missing_response = client.get(f"/projects/{project_id}")
|
||||
assert missing_response.status_code == 404
|
||||
|
||||
|
||||
def test_project_creation_conflict_returns_409(client: TestClient) -> None:
|
||||
_create_project(client, name="Conflict Project")
|
||||
conflict_payload = {
|
||||
"name": "Conflict Project",
|
||||
"location": "Canada",
|
||||
"operation_type": MiningOperationType.OTHER.value,
|
||||
"description": "Duplicate entry",
|
||||
}
|
||||
response = client.post("/projects", json=conflict_payload)
|
||||
assert response.status_code == 409
|
||||
assert "violates" in response.json()["detail"].lower()
|
||||
|
||||
|
||||
def test_create_project_requires_valid_operation_type(client: TestClient) -> None:
|
||||
invalid_payload = {
|
||||
"name": "Invalid Operation",
|
||||
"location": "Australia",
|
||||
"operation_type": "INVALID",
|
||||
"description": "Bad op type",
|
||||
}
|
||||
response = client.post("/projects", json=invalid_payload)
|
||||
assert response.status_code == 422
|
||||
body = response.json()
|
||||
assert body["detail"][0]["loc"][-1] == "operation_type"
|
||||
|
||||
|
||||
def test_scenario_crud_cycle(client: TestClient) -> None:
|
||||
project = _create_project(client)
|
||||
project_id = project["id"]
|
||||
|
||||
creation_payload = {
|
||||
"name": "Scenario A",
|
||||
"description": "Base case assumptions",
|
||||
"status": ScenarioStatus.DRAFT.value,
|
||||
"start_date": "2025-01-01",
|
||||
"end_date": "2026-01-01",
|
||||
"discount_rate": 8.5,
|
||||
"currency": "usd",
|
||||
"primary_resource": ResourceType.DIESEL.value,
|
||||
}
|
||||
create_response = client.post(
|
||||
f"/projects/{project_id}/scenarios",
|
||||
json=creation_payload,
|
||||
)
|
||||
assert create_response.status_code == 201, create_response.text
|
||||
scenario = create_response.json()
|
||||
scenario_id = scenario["id"]
|
||||
assert scenario["currency"] == "USD"
|
||||
assert scenario["project_id"] == project_id
|
||||
|
||||
list_response = client.get(f"/projects/{project_id}/scenarios")
|
||||
assert list_response.status_code == 200
|
||||
listed_ids = {item["id"] for item in list_response.json()}
|
||||
assert scenario_id in listed_ids
|
||||
|
||||
update_payload = {"description": "Revised assumptions", "status": ScenarioStatus.ACTIVE.value}
|
||||
update_response = client.put(f"/scenarios/{scenario_id}", json=update_payload)
|
||||
assert update_response.status_code == 200
|
||||
updated = update_response.json()
|
||||
assert updated["description"] == "Revised assumptions"
|
||||
assert updated["status"] == ScenarioStatus.ACTIVE.value
|
||||
|
||||
delete_response = client.delete(f"/scenarios/{scenario_id}")
|
||||
assert delete_response.status_code == 204
|
||||
|
||||
missing_response = client.get(f"/scenarios/{scenario_id}")
|
||||
assert missing_response.status_code == 404
|
||||
|
||||
|
||||
def test_create_scenario_requires_existing_project(client: TestClient) -> None:
|
||||
payload = {
|
||||
"name": "Orphan Scenario",
|
||||
"status": ScenarioStatus.DRAFT.value,
|
||||
}
|
||||
response = client.post("/projects/999/scenarios", json=payload)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_scenario_conflict_returns_409(client: TestClient) -> None:
|
||||
project = _create_project(client, name="Scenario Container")
|
||||
project_id = project["id"]
|
||||
|
||||
payload = {"name": "Duplicate Scenario"}
|
||||
first_response = client.post(f"/projects/{project_id}/scenarios", json=payload)
|
||||
assert first_response.status_code == 201
|
||||
|
||||
conflict_response = client.post(f"/projects/{project_id}/scenarios", json=payload)
|
||||
assert conflict_response.status_code == 409
|
||||
assert "constraints" in conflict_response.json()["detail"].lower()
|
||||
|
||||
|
||||
def test_create_scenario_invalid_currency_returns_422(client: TestClient) -> None:
|
||||
project = _create_project(client, name="Currency Project")
|
||||
project_id = project["id"]
|
||||
payload = {
|
||||
"name": "Bad Currency",
|
||||
"currency": "zz",
|
||||
}
|
||||
response = client.post(f"/projects/{project_id}/scenarios", json=payload)
|
||||
assert response.status_code == 422
|
||||
detail = response.json()["detail"][0]
|
||||
assert detail["loc"][-1] == "currency"
|
||||
assert "invalid currency code" in detail["msg"].lower()
|
||||
|
||||
|
||||
def test_list_scenarios_missing_project_returns_404(client: TestClient) -> None:
|
||||
response = client.get("/projects/424242/scenarios")
|
||||
assert response.status_code == 404
|
||||
Reference in New Issue
Block a user