""" [DELETE] /org/ is not tested because the testing client cannot attach a body to a delete request. """ from typing import Any import pytest from httpx import AsyncClient from .conftest import generate_query_and_status, standard_test pytestmark = [ pytest.mark.org_module, ] @pytest.mark.parametrize("query, expected_status", generate_query_and_status(["org_id"])) @pytest.mark.anyio async def test_get_org_status_checks( default_client: AsyncClient, query: str, expected_status: int ): resp = await default_client.get(f"/org?{query}") assert resp.status_code == expected_status @pytest.mark.parametrize( "body, expected_status", [ ({"name": 42}, 422), ({}, 422), ({"name": "New Test Org", "intake_questionnaire": {"question_one": 42}}, 422), ], ) @pytest.mark.anyio async def test_post_org_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.post("/org", json=body) assert resp.status_code == expected_status @pytest.mark.parametrize( "body, expected_status", [ ({"organisation_id": 42}, 404), ({"organisation_id": "Org One"}, 422), ({"organisation_id": ""}, 422), ({}, 422), ( { "organisation_id": "1", "intake_questionnaire": {"question_one": 42}, "partial": True, }, 422, ), ( {"organisation_id": "1", "intake_questionnaire": {"question_one": "valid"}}, 422, ), ( { "organisation_id": "1", "intake_questionnaire": {"question_one": "valid"}, "partial": 42, }, 422, ), ], ) @pytest.mark.anyio async def test_patch_questionnaire_partial_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.patch("/org/questionnaire", json=body) assert resp.status_code == expected_status @pytest.mark.anyio async def test_patch_org_questionnaire_submit_success(default_client: AsyncClient): resp = await default_client.patch( "/org/questionnaire", json={ "organisation_id": 3, "intake_questionnaire": { "question_one": "new answer one", "question_two": None, "question_three": None, }, "partial": False, }, ) data = resp.json() assert resp.status_code == 200 assert data["name"] == "Org Three" assert data["status"] == "submitted" assert "intake_questionnaire" in data assert isinstance(data["intake_questionnaire"], dict) metadata = data["intake_questionnaire"]["metadata"] assert metadata["version"] == 0 assert metadata["submission_date"] is not None questions = data["intake_questionnaire"]["questions"] assert questions["question_one"] == "new answer one" assert questions["question_two"] == "answer two" assert questions["question_three"] is None @pytest.mark.parametrize( "status", ["partial", "submitted", "remediation", "approved", "rejected", "removed"] ) @pytest.mark.anyio async def test_patch_org_status_success(default_client: AsyncClient, status: str): resp = await default_client.patch( "/org/status", json={"organisation_id": 1, "status": status} ) data = resp.json() assert resp.status_code == 200 assert data["name"] == "Org One" assert data["status"] == status @pytest.mark.parametrize( "body, expected_status", [ ({"organisation_id": 42}, 404), ({"organisation_id": "Org One"}, 422), ({"organisation_id": ""}, 422), ({}, 422), ({"organisation_id": "1", "status": True}, 422), ({"organisation_id": "1", "status": 42}, 422), ], ) @pytest.mark.anyio async def test_patch_org_status_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.patch("/org/status", json=body) assert resp.status_code == expected_status @pytest.mark.parametrize("query, expected_status", generate_query_and_status(["org_id"])) @pytest.mark.anyio async def test_get_org_users_status_checks( default_client: AsyncClient, query: str, expected_status: int ): resp = await default_client.get(f"/org/users?{query}") assert resp.status_code == expected_status @pytest.mark.parametrize( "body, expected_status", [ ({"organisation_id": 42}, 404), ({}, 422), ({"organisation_id": 1, "user_id": "id"}, 422), ({"user_id": 2}, 422), ({"organisation_id": 1, "user_id": 42}, 404), ({"organisation_id": 1, "user_id": 1}, 409), ], ) @pytest.mark.anyio async def test_post_org_user_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.post("/org/user", json=body) assert resp.status_code == expected_status @pytest.mark.parametrize( "body, expected_status", [ ({"organisation_id": 42, "user_id": 2}, 404), ({"organisation_id": "Org One", "user_id": 2}, 422), ({"organisation_id": "", "user_id": 2}, 422), ({}, 422), ({"user_id": 2}, 422), ({"user_id": 42}, 404), ({"organisation_id": 1, "user_id": "Test User"}, 422), ], ) @pytest.mark.anyio async def test_patch_root_user_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.patch("/org/root_user", json=body) assert resp.status_code == expected_status @pytest.mark.anyio async def test_patch_org_root_user_non_member(default_client: AsyncClient): resp = await default_client.patch( "/org/root_user", json={"organisation_id": 1, "user_id": 3} ) data = resp.json() assert resp.status_code == 422 assert data["detail"] == "This user does not belong to your organisation." @pytest.mark.parametrize("query, expected_status", generate_query_and_status(["org_id"])) @pytest.mark.anyio async def test_get_org_groups_status_checks( default_client: AsyncClient, query: str, expected_status: int ): resp = await default_client.get(f"/org/groups?{query}") assert resp.status_code == expected_status @pytest.mark.parametrize("contact_type", ["billing", "security", "owner"]) @pytest.mark.anyio async def test_get_org_contact_success(default_client: AsyncClient, contact_type: str): resp = await default_client.get(f"/org/contact?org_id=1&contact_type={contact_type}") data = resp.json() assert resp.status_code == 200 assert "organisation" in data assert data["organisation"]["id"] == 1 assert data["organisation"]["name"] == "Org One" attributes = [ "email", "first_name", "last_name", "phonenumber", "vat_number", "address", ] for attribute in attributes: assert attribute in data["contact"] address_attributes = [ "post_office_box_number", "street_address", "street_address_line_2", "locality", "address_region", "country_code", "postal_code", ] for attribute in address_attributes: assert attribute in data["contact"]["address"] @pytest.mark.parametrize( "query, expected_status", [ ("org_id=42&contact_type=billing", 404), ("org_id=banana&contact_type=billing", 422), ("", 422), ("org_id=1&contact_type=contact", 422), ("contact_type=billing", 422), ], ) @pytest.mark.anyio async def test_get_org_contact_status_checks( default_client: AsyncClient, query: str, expected_status: int ): resp = await default_client.get(f"/org/contact?{query}") assert resp.status_code == expected_status @pytest.mark.parametrize( "key, value", [ ("email", "user@example.com"), ("first_name", "John"), ("last_name", "Doe"), ("phonenumber", "+441234567890"), ("vat_number", "GB123456789"), ("post_office_box_number", "PO Box 123"), ("street_address", "123 Example Street"), ("street_address_line_2", "Suite 4B"), ("locality", "Glasgow"), ("address_region", "Glasgow City"), ("country_code", "GB"), ("postal_code", "G1 1AA"), ], ) @pytest.mark.anyio async def test_patch_org_contact_success(default_client: AsyncClient, key: str, value: str): resp = await default_client.patch( "/org/contact", json={"organisation_id": 1, "contact_type": "billing", key: value}, ) assert resp.status_code == 200 data = resp.json() assert "organisation" in data assert data["organisation"]["id"] == 1 assert data["organisation"]["name"] == "Org One" attributes = [ "email", "first_name", "last_name", "phonenumber", "vat_number", "address", ] for attribute in attributes: assert attribute in data["contact"] address_attributes = [ "post_office_box_number", "street_address", "street_address_line_2", "locality", "address_region", "country_code", "postal_code", ] for attribute in address_attributes: assert attribute in data["contact"]["address"] if key in data["contact"]: assert data["contact"][key] == value elif key in data["contact"]["address"]: assert data["contact"]["address"][key] == value else: pytest.fail(f"Invalid contact key: {key}") @pytest.mark.parametrize( "body, expected_status", [ ({"organisation_id": 42, "contact_type": "billing"}, 404), ({"organisation_id": 1, "contact_type": "security"}, 200), ({"organisation_id": 1, "contact_type": "owner"}, 200), ({"organisation_id": "Org One", "contact_type": "billing"}, 422), ({"organisation_id": "", "contact_type": "billing"}, 422), ({}, 422), ({"organisation_id": 1, "contact_type": "not_real"}, 422), ({"organisation_id": 1, "contact_type": 42}, 422), ({"organisation_id": 1, "contact_type": ""}, 422), ], ) @pytest.mark.anyio async def test_patch_org_contact_status_checks( default_client: AsyncClient, body: dict[str, str], expected_status: int ): resp = await default_client.patch("/org/contact", json=body) assert resp.status_code == expected_status @pytest.mark.anyio async def test_get_org_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "GET" path = "/org" auth_level = "Root User" query = "?org_id=1" body = {} expected_data = { "organisations": [ { "organisation_id": 1, "name": "Org One", "status": "approved", "root_user_email": "admin@test.com", "intake_questionnaire": { "metadata": {"version": 0, "submission_date": None}, "questions": { "question_one": None, "question_two": "answer two", "question_three": None, }, }, "billing_contact": {"id": 1, "email": "billing@orgone.com"}, "owner_contact": {"id": 2, "email": "owner@orgone.com"}, "security_contact": {"id": 3, "email": "security@orgone.com"}, } ] } await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_post_org_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "POST" path = "/org" auth_level = "User" query = "" body = {"name": "New Test Org"} expected_data = {"id": 4, "name": "New Test Org", "status": "partial"} await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_patch_org_questionnaire_partial_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "PATCH" path = "/org/questionnaire" auth_level = "Root User" query = "" body = { "organisation_id": 3, "intake_questionnaire": { "question_one": "new answer one", "question_two": None, "question_three": None, }, "partial": True, } expected_data = { "id": 3, "name": "Org Three", "status": "partial", "intake_questionnaire": { "metadata": {"version": 0, "submission_date": None}, "questions": { "question_one": "new answer one", "question_two": "answer two", "question_three": None, }, }, } await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_get_org_users_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "GET" path = "/org/users" auth_level = "Root User" query = "?org_id=1" body = {} expected_data = { "users": [ {"email": "admin@test.com", "id": 1}, {"email": "user@orgone.com", "id": 2}, ], "organisation": {"id": 1, "name": "Org One"}, } await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_post_org_user_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "POST" path = "/org/user" auth_level = "Super Admin" query = "" body = {"organisation_id": 1, "user_id": 3} expected_data = { "users": [ {"email": "admin@test.com", "id": 1}, {"email": "user@orgone.com", "id": 2}, {"email": "root@orgtwo.com", "id": 3}, ], "organisation": {"id": 1, "name": "Org One"}, } await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_patch_org_root_user_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "PATCH" path = "/org/root_user" auth_level = "Super Admin" query = "" body = {"organisation_id": 1, "user_id": 2} expected_data = {"name": "Org One", "root_user_email": "user@orgone.com"} await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_get_org_groups_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "GET" path = "/org/groups" auth_level = "Root User" query = "?org_id=1" body = {} expected_data = { "groups": [ {"name": "Org One Group", "id": 1}, {"name": "Org One Group Two", "id": 3}, ], "organisation": {"id": 1, "name": "Org One"}, } await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_delete_org_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "DELETE" path = "/org" auth_level = "Super Admin" query = "?org_id=1" body = {} expected_data = {} await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_delete_org_users_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "DELETE" path = "/org/user" auth_level = "Root User" query = "?org_id=1&user_id=2" body = {} expected_data = {} await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data ) @pytest.mark.anyio async def test_delete_preapproval_org_standard( default_client: AsyncClient, route_data: dict[str, dict[str, Any]] ): method = "DELETE" path = "/org/self" auth_level = "Root User" query = "?org_id=3" body = {} expected_data = {} await standard_test( default_client, method, path, auth_level, query, body, expected_data, route_data )