- Added monitoring metrics for project creation success and error handling in `ProjectRepository`. - Implemented similar monitoring for scenario creation in `ScenarioRepository`. - Refactored `run_monte_carlo` function in `simulation.py` to include timing and success/error metrics. - Introduced new CSS styles for headers, alerts, and navigation buttons in `main.css` and `projects.css`. - Created a new JavaScript file for navigation logic to handle chevron buttons. - Updated HTML templates to include new navigation buttons and improved styling for buttons. - Added tests for reporting service and routes to ensure proper functionality and access control. - Removed unused imports and optimized existing test files for better clarity and performance.
144 lines
4.4 KiB
Python
144 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import csv
|
|
from io import BytesIO, StringIO
|
|
from zipfile import ZipFile
|
|
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.orm import Session
|
|
|
|
from models import Project, Scenario, ScenarioStatus
|
|
|
|
|
|
def _seed_projects(session: Session) -> None:
|
|
project = Project(name="Alpha", operation_type="open_pit")
|
|
project.updated_at = project.created_at
|
|
session.add(project)
|
|
session.commit()
|
|
|
|
|
|
def _seed_scenarios(session: Session, project: Project) -> Scenario:
|
|
scenario = Scenario(
|
|
name="Scenario A",
|
|
project_id=project.id,
|
|
status=ScenarioStatus.ACTIVE,
|
|
)
|
|
session.add(scenario)
|
|
session.commit()
|
|
session.refresh(scenario)
|
|
return scenario
|
|
|
|
|
|
def test_projects_export_modal(client: TestClient) -> None:
|
|
response = client.get("/exports/modal/projects")
|
|
assert response.status_code == 200
|
|
assert "Export Projects" in response.text
|
|
|
|
|
|
def test_scenarios_export_modal(client: TestClient) -> None:
|
|
response = client.get("/exports/modal/scenarios")
|
|
assert response.status_code == 200
|
|
assert "Export Scenarios" in response.text
|
|
|
|
|
|
def test_project_export_csv(client: TestClient, unit_of_work_factory) -> None:
|
|
with unit_of_work_factory() as uow:
|
|
project = Project(name="CSV Project", operation_type="open_pit")
|
|
uow.projects.create(project)
|
|
|
|
response = client.post(
|
|
"/exports/projects",
|
|
json={"format": "csv"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.headers["Content-Type"].startswith("text/csv")
|
|
assert "attachment; filename=" in response.headers["Content-Disposition"]
|
|
|
|
content = response.content.decode("utf-8")
|
|
reader = csv.reader(StringIO(content))
|
|
rows = list(reader)
|
|
assert rows[0][:3] == ["name", "location", "operation_type"]
|
|
assert any(row[0] == "CSV Project" for row in rows[1:])
|
|
|
|
|
|
def test_project_export_excel(client: TestClient, unit_of_work_factory) -> None:
|
|
with unit_of_work_factory() as uow:
|
|
project = Project(name="XLSX Project", operation_type="open_pit")
|
|
uow.projects.create(project)
|
|
|
|
response = client.post(
|
|
"/exports/projects",
|
|
json={"format": "xlsx"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.headers["Content-Type"].startswith(
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
|
|
with ZipFile(BytesIO(response.content)) as archive:
|
|
assert "xl/workbook.xml" in archive.namelist()
|
|
|
|
|
|
def test_scenario_export_csv(client: TestClient, unit_of_work_factory) -> None:
|
|
with unit_of_work_factory() as uow:
|
|
project = Project(name="Scenario Project", operation_type="open_pit")
|
|
uow.projects.create(project)
|
|
scenario = Scenario(
|
|
name="Scenario CSV",
|
|
project_id=project.id,
|
|
status=ScenarioStatus.ACTIVE,
|
|
)
|
|
uow.scenarios.create(scenario)
|
|
|
|
response = client.post(
|
|
"/exports/scenarios",
|
|
json={"format": "csv"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
reader = csv.reader(StringIO(response.content.decode("utf-8")))
|
|
rows = list(reader)
|
|
assert rows[0][0] == "project_name"
|
|
assert any(row[0] == "Scenario Project" for row in rows[1:])
|
|
|
|
|
|
def test_scenario_export_excel(client: TestClient, unit_of_work_factory) -> None:
|
|
with unit_of_work_factory() as uow:
|
|
project = Project(name="Scenario Excel", operation_type="open_pit")
|
|
uow.projects.create(project)
|
|
scenario = Scenario(
|
|
name="Scenario XLSX",
|
|
project_id=project.id,
|
|
status=ScenarioStatus.ACTIVE,
|
|
)
|
|
uow.scenarios.create(scenario)
|
|
|
|
response = client.post(
|
|
"/exports/scenarios",
|
|
json={"format": "xlsx"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.headers["Content-Type"].startswith(
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
|
|
with ZipFile(BytesIO(response.content)) as archive:
|
|
assert "xl/workbook.xml" in archive.namelist()
|
|
|
|
|
|
def test_scenario_export_rejects_invalid_currency_filter(client: TestClient) -> None:
|
|
response = client.post(
|
|
"/exports/scenarios",
|
|
json={
|
|
"format": "csv",
|
|
"filters": {"currencies": ["USD", "XX"]},
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 422
|
|
detail = response.json()["detail"]
|
|
assert "Invalid currency code" in detail
|