Files
mimic/backend/tests/test_simulation_templates_crud.py

240 lines
7.8 KiB
Python
Raw Normal View History

"""SimulationTemplate CRUD: list, create, get, patch, delete + RBAC + dedup."""
from __future__ import annotations
from flask.testing import FlaskClient
from backend.app.extensions import db
from backend.app.models import User
from backend.app.models.simulation_template import SimulationTemplate
from backend.tests.conftest import auth_headers as _h # noqa: E402
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_template(client: FlaskClient, token: str, **kw) -> dict:
payload = {"name": "Template Alpha", **kw}
resp = client.post("/api/templates", headers=_h(token), json=payload)
assert resp.status_code == 201, resp.get_json()
return resp.get_json()
# ---------------------------------------------------------------------------
# List
# ---------------------------------------------------------------------------
def test_list_templates_empty(client: FlaskClient, admin_token: str) -> None:
resp = client.get("/api/templates", headers=_h(admin_token))
assert resp.status_code == 200
assert resp.get_json() == []
def test_list_templates_soc_forbidden(client: FlaskClient, soc_token: str) -> None:
resp = client.get("/api/templates", headers=_h(soc_token))
assert resp.status_code == 403
def test_list_templates_unauthenticated(client: FlaskClient) -> None:
resp = client.get("/api/templates")
assert resp.status_code == 401
# ---------------------------------------------------------------------------
# Create
# ---------------------------------------------------------------------------
def test_create_template_as_admin(
client: FlaskClient, admin_user: User, admin_token: str
) -> None:
body = _make_template(
client,
admin_token,
description="desc",
commands="cmd",
prerequisites="prereq",
)
assert body["name"] == "Template Alpha"
assert body["description"] == "desc"
assert body["commands"] == "cmd"
assert body["prerequisites"] == "prereq"
assert body["techniques"] == []
assert body["tactics"] == []
assert body["created_by"] == {"id": admin_user.id, "username": "admin1"}
assert body["id"] is not None
def test_create_template_as_redteam(
client: FlaskClient, redteam_user: User, redteam_token: str
) -> None:
body = _make_template(client, redteam_token)
assert body["created_by"]["username"] == "redteam1"
def test_create_template_soc_forbidden(client: FlaskClient, soc_token: str) -> None:
resp = client.post(
"/api/templates", headers=_h(soc_token), json={"name": "T"}
)
assert resp.status_code == 403
def test_create_template_missing_name(client: FlaskClient, admin_token: str) -> None:
resp = client.post("/api/templates", headers=_h(admin_token), json={})
assert resp.status_code == 400
assert "name" in resp.get_json()["error"]
def test_create_template_duplicate_name_409(
client: FlaskClient, admin_token: str
) -> None:
_make_template(client, admin_token)
resp = client.post(
"/api/templates", headers=_h(admin_token), json={"name": "Template Alpha"}
)
assert resp.status_code == 409
assert "already exists" in resp.get_json()["error"]
# ---------------------------------------------------------------------------
# Get single
# ---------------------------------------------------------------------------
def test_get_template(client: FlaskClient, admin_token: str) -> None:
created = _make_template(client, admin_token)
resp = client.get(f"/api/templates/{created['id']}", headers=_h(admin_token))
assert resp.status_code == 200
assert resp.get_json()["id"] == created["id"]
def test_get_template_not_found(client: FlaskClient, admin_token: str) -> None:
resp = client.get("/api/templates/9999", headers=_h(admin_token))
assert resp.status_code == 404
def test_get_template_soc_forbidden(
client: FlaskClient, admin_token: str, soc_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.get(f"/api/templates/{created['id']}", headers=_h(soc_token))
assert resp.status_code == 403
# ---------------------------------------------------------------------------
# Patch
# ---------------------------------------------------------------------------
def test_patch_template_name(client: FlaskClient, admin_token: str) -> None:
created = _make_template(client, admin_token)
resp = client.patch(
f"/api/templates/{created['id']}",
headers=_h(admin_token),
json={"name": "Renamed"},
)
assert resp.status_code == 200
assert resp.get_json()["name"] == "Renamed"
assert resp.get_json()["updated_at"] is not None
def test_patch_template_empty_name_rejected(
client: FlaskClient, admin_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.patch(
f"/api/templates/{created['id']}",
headers=_h(admin_token),
json={"name": ""},
)
assert resp.status_code == 400
def test_patch_template_unknown_field_rejected(
client: FlaskClient, admin_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.patch(
f"/api/templates/{created['id']}",
headers=_h(admin_token),
json={"bogus_field": "x"},
)
assert resp.status_code == 400
assert "unknown fields" in resp.get_json()["error"]
def test_patch_template_duplicate_name_409(
client: FlaskClient, admin_token: str
) -> None:
_make_template(client, admin_token, name="T1")
t2 = _make_template(client, admin_token, name="T2")
resp = client.patch(
f"/api/templates/{t2['id']}",
headers=_h(admin_token),
json={"name": "T1"},
)
assert resp.status_code == 409
def test_patch_template_soc_forbidden(
client: FlaskClient, admin_token: str, soc_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.patch(
f"/api/templates/{created['id']}",
headers=_h(soc_token),
json={"name": "X"},
)
assert resp.status_code == 403
def test_patch_template_not_found(client: FlaskClient, admin_token: str) -> None:
resp = client.patch(
"/api/templates/9999", headers=_h(admin_token), json={"name": "X"}
)
assert resp.status_code == 404
# ---------------------------------------------------------------------------
# Delete
# ---------------------------------------------------------------------------
def test_delete_template(
client: FlaskClient, app, admin_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.delete(f"/api/templates/{created['id']}", headers=_h(admin_token))
assert resp.status_code == 204
with app.app_context():
assert db.session.get(SimulationTemplate, created["id"]) is None
def test_delete_template_not_found(client: FlaskClient, admin_token: str) -> None:
resp = client.delete("/api/templates/9999", headers=_h(admin_token))
assert resp.status_code == 404
def test_delete_template_soc_forbidden(
client: FlaskClient, admin_token: str, soc_token: str
) -> None:
created = _make_template(client, admin_token)
resp = client.delete(f"/api/templates/{created['id']}", headers=_h(soc_token))
assert resp.status_code == 403
# ---------------------------------------------------------------------------
# List returns ordered by name
# ---------------------------------------------------------------------------
def test_list_templates_ordered_by_name(
client: FlaskClient, admin_token: str
) -> None:
for name in ("Zebra", "Alpha", "Midpoint"):
_make_template(client, admin_token, name=name)
body = client.get("/api/templates", headers=_h(admin_token)).get_json()
names = [t["name"] for t in body]
assert names == sorted(names)