"""Engagement endpoint tests.""" from __future__ import annotations from flask.testing import FlaskClient from backend.app.models import User from backend.tests.conftest import auth_headers as _h def _create( client: FlaskClient, token: str, **overrides: object ) -> dict[str, object]: payload: dict[str, object] = { "name": "Op Alpha", "description": "first engagement", "start_date": "2026-06-01", "end_date": "2026-06-10", "status": "planned", } payload.update(overrides) resp = client.post("/api/engagements", headers=_h(token), json=payload) assert resp.status_code == 201, resp.get_json() return resp.get_json() def test_create_engagement_as_redteam( client: FlaskClient, redteam_user: User, redteam_token: str ) -> None: body = _create(client, redteam_token) assert body["name"] == "Op Alpha" assert body["status"] == "planned" assert body["created_by"] == {"id": redteam_user.id, "username": "redteam1"} def test_create_engagement_as_admin( client: FlaskClient, admin_user: User, admin_token: str ) -> None: body = _create(client, admin_token, name="Op Admin") assert body["created_by"]["username"] == "admin1" def test_create_engagement_soc_forbidden( client: FlaskClient, soc_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(soc_token), json={"name": "x", "start_date": "2026-06-01"}, ) assert resp.status_code == 403 def test_create_engagement_unauth(client: FlaskClient) -> None: resp = client.post( "/api/engagements", json={"name": "x", "start_date": "2026-06-01"} ) assert resp.status_code == 401 def test_create_engagement_missing_name( client: FlaskClient, redteam_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(redteam_token), json={"start_date": "2026-06-01"}, ) assert resp.status_code == 400 def test_create_engagement_bad_date( client: FlaskClient, redteam_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(redteam_token), json={"name": "bad", "start_date": "not-a-date"}, ) assert resp.status_code == 400 def test_create_engagement_end_before_start( client: FlaskClient, redteam_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(redteam_token), json={ "name": "bad", "start_date": "2026-06-10", "end_date": "2026-06-01", }, ) assert resp.status_code == 400 def test_create_engagement_bad_status( client: FlaskClient, redteam_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(redteam_token), json={"name": "bad", "start_date": "2026-06-01", "status": "wat"}, ) assert resp.status_code == 400 def test_create_engagement_default_status_planned( client: FlaskClient, redteam_token: str ) -> None: resp = client.post( "/api/engagements", headers=_h(redteam_token), json={"name": "Op default", "start_date": "2026-06-01"}, ) assert resp.status_code == 201 assert resp.get_json()["status"] == "planned" def test_list_engagements_all_roles_can_read( client: FlaskClient, redteam_token: str, soc_token: str, admin_token: str, ) -> None: _create(client, redteam_token) for token in (redteam_token, soc_token, admin_token): resp = client.get("/api/engagements", headers=_h(token)) assert resp.status_code == 200 body = resp.get_json() assert isinstance(body, list) assert len(body) >= 1 assert body[0]["created_by"] == { "id": body[0]["created_by"]["id"], "username": body[0]["created_by"]["username"], } def test_get_engagement_404(client: FlaskClient, redteam_token: str) -> None: resp = client.get("/api/engagements/9999", headers=_h(redteam_token)) assert resp.status_code == 404 def test_get_engagement_ok(client: FlaskClient, redteam_token: str) -> None: created = _create(client, redteam_token) resp = client.get( f"/api/engagements/{created['id']}", headers=_h(redteam_token) ) assert resp.status_code == 200 assert resp.get_json()["id"] == created["id"] def test_patch_engagement_redteam( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token) resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(redteam_token), json={"status": "active", "description": "now in progress"}, ) assert resp.status_code == 200 body = resp.get_json() assert body["status"] == "active" assert body["description"] == "now in progress" def test_patch_engagement_admin( client: FlaskClient, redteam_token: str, admin_token: str ) -> None: created = _create(client, redteam_token) resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(admin_token), json={"name": "Op renamed"}, ) assert resp.status_code == 200 assert resp.get_json()["name"] == "Op renamed" def test_patch_engagement_bad_status( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token) resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(redteam_token), json={"status": "wat"}, ) assert resp.status_code == 400 def test_patch_engagement_soc_forbidden( client: FlaskClient, redteam_token: str, soc_token: str ) -> None: created = _create(client, redteam_token) resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(soc_token), json={"status": "closed"}, ) assert resp.status_code == 403 def test_patch_engagement_end_before_start( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token, start_date="2026-06-01") resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(redteam_token), json={"end_date": "2026-05-30"}, ) assert resp.status_code == 400 def test_patch_engagement_clear_end_date( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token, end_date="2026-06-30") resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(redteam_token), json={"end_date": None}, ) assert resp.status_code == 200 assert resp.get_json()["end_date"] is None def test_patch_engagement_empty_name_rejected( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token) resp = client.patch( f"/api/engagements/{created['id']}", headers=_h(redteam_token), json={"name": " "}, ) assert resp.status_code == 400 def test_patch_engagement_404(client: FlaskClient, redteam_token: str) -> None: resp = client.patch( "/api/engagements/9999", headers=_h(redteam_token), json={"name": "x"} ) assert resp.status_code == 404 def test_delete_engagement_redteam( client: FlaskClient, redteam_token: str ) -> None: created = _create(client, redteam_token) resp = client.delete( f"/api/engagements/{created['id']}", headers=_h(redteam_token) ) assert resp.status_code == 204 def test_delete_engagement_admin( client: FlaskClient, redteam_token: str, admin_token: str ) -> None: created = _create(client, redteam_token) resp = client.delete( f"/api/engagements/{created['id']}", headers=_h(admin_token) ) assert resp.status_code == 204 def test_delete_engagement_soc_forbidden( client: FlaskClient, redteam_token: str, soc_token: str ) -> None: created = _create(client, redteam_token) resp = client.delete( f"/api/engagements/{created['id']}", headers=_h(soc_token) ) assert resp.status_code == 403 def test_delete_engagement_404(client: FlaskClient, redteam_token: str) -> None: resp = client.delete("/api/engagements/9999", headers=_h(redteam_token)) assert resp.status_code == 404