From e9fe405e061cd9671638953734bfd026cabcce15 Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 13:07:43 +0100 Subject: [PATCH 1/6] feat: add org user by id requires su Part of the "sensical user adding" changes. --- src/organisation/router.py | 3 ++- test/test_auth_root.py | 20 -------------------- test/test_auth_su.py | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/organisation/router.py b/src/organisation/router.py index 3f4fcbc..cd1cdb8 100644 --- a/src/organisation/router.py +++ b/src/organisation/router.py @@ -292,8 +292,9 @@ async def get_users(org_model: org_model_root_claim_query_dependency): ) async def add_user_to_org( db: db_dependency, - org_model: org_model_root_claim_body_dependency, + org_model: org_model_body_dependency, user_model: user_model_body_dependency, + su: super_admin_dependency, request_model: OrgPostUserRequest, ): """ diff --git a/test/test_auth_root.py b/test/test_auth_root.py index e67bc6a..e068a55 100644 --- a/test/test_auth_root.py +++ b/test/test_auth_root.py @@ -71,26 +71,6 @@ async def test_get_org_users_auth_root(no_su_client: AsyncClient): assert "Must be the org's root user" in resp.json()["detail"] -@pytest.mark.anyio -async def test_post_org_user_auth_root(no_su_client: AsyncClient, db_session): - db_session.add( - User( - email="user@test.org", - first_name="User", - last_name="Test", - oidc_id="abcd-efgh-ijkl-1234", - ) - ) - db_session.flush() - - resp = await no_su_client.post( - "/org/user", json={"organisation_id": 2, "user_id": 2} - ) - assert resp.status_code != 422 - assert resp.status_code == 401 - assert "Must be the org's root user" in resp.json()["detail"] - - @pytest.mark.anyio async def test_get_org_groups_auth_root(no_su_client: AsyncClient): resp = await no_su_client.get("/org/groups?org_id=2") diff --git a/test/test_auth_su.py b/test/test_auth_su.py index 18319a4..1243796 100644 --- a/test/test_auth_su.py +++ b/test/test_auth_su.py @@ -67,7 +67,7 @@ async def test_post_service_auth_su(no_su_client: AsyncClient): @pytest.mark.anyio -async def test_post_perm_success(no_su_client: AsyncClient, db_session): +async def test_post_perm_auth_su(no_su_client: AsyncClient, db_session): resp = await no_su_client.post( "/iam/permission", json={"service_id": 1, "resource": "test_resource", "action": "create"}, @@ -75,3 +75,23 @@ async def test_post_perm_success(no_su_client: AsyncClient, db_session): assert resp.status_code != 422 assert resp.status_code == 401 assert resp.json()["detail"] == "Must be super admin" + + +@pytest.mark.anyio +async def test_post_org_user_auth_su(no_su_client: AsyncClient, db_session): + db_session.add( + User( + email="user@test.org", + first_name="User", + last_name="Test", + oidc_id="abcd-efgh-ijkl-1234", + ) + ) + db_session.flush() + + resp = await no_su_client.post( + "/org/user", json={"organisation_id": 1, "user_id": 2} + ) + assert resp.status_code != 422 + assert resp.status_code == 401 + assert "Must be super admin" in resp.json()["detail"] From 4ff9edf6d141eb8142b2dd58fb06ae99eff5589d Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 13:17:31 +0100 Subject: [PATCH 2/6] feat: schema mixins moved to project level Resolves circular dependency issues. --- src/iam/schemas.py | 21 ++++++++------------- src/organisation/schemas.py | 10 ++-------- src/schemas.py | 23 ++++++++++++++++++++++- src/service/schemas.py | 9 ++------- src/user/dependencies.py | 2 +- src/user/schemas.py | 16 +++------------- 6 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/iam/schemas.py b/src/iam/schemas.py index fca76de..baf7ae3 100644 --- a/src/iam/schemas.py +++ b/src/iam/schemas.py @@ -3,7 +3,6 @@ Pydantic models for the IAM module Models follow the nomenclature of: - Sub-models: "Schema" -- Mixins: "Mixin" - Models: "" ie "IAMGetGroupPermissionsResponse" """ @@ -11,10 +10,14 @@ from typing import Optional, Annotated from pydantic import EmailStr, ConfigDict, Field -from src.service.schemas import ServiceIDMixin -from src.organisation.schemas import OrgIDMixin -from src.schemas import CustomBaseModel -from src.user.schemas import UserIDMixin +from src.schemas import ( + CustomBaseModel, + ServiceIDMixin, + OrgIDMixin, + UserIDMixin, + PermIDMixin, + GroupIDMixin, +) class UserSchema(CustomBaseModel): @@ -39,14 +42,6 @@ class GroupSchema(CustomBaseModel): name: str -class GroupIDMixin(CustomBaseModel): - group_id: int = Field(gt=0) - - -class PermIDMixin(CustomBaseModel): - permission_id: int = Field(gt=0) - - class IAMGetGroupPermissionsResponse(CustomBaseModel): permissions: list[PermissionSchema] diff --git a/src/organisation/schemas.py b/src/organisation/schemas.py index 9f120f3..c474544 100644 --- a/src/organisation/schemas.py +++ b/src/organisation/schemas.py @@ -3,25 +3,19 @@ Pydantic models for organisation module Models follow the nomenclature of: - Sub-models: "Schema" -- Mixins: "Mixin" - Models: "" ie "OrgPostOrgRequest" """ from typing import Optional -from pydantic import EmailStr, ConfigDict, Field +from pydantic import EmailStr, ConfigDict -from src.schemas import CustomBaseModel +from src.schemas import CustomBaseModel, OrgIDMixin, UserIDMixin from src.contact.schemas import ContactModel -from src.user.schemas import UserIDMixin from src.organisation.constants import Status, ContactType -class OrgIDMixin(CustomBaseModel): - organisation_id: int = Field(gt=0) - - class Questionnaire(CustomBaseModel): question_one: Optional[str] = None question_two: Optional[str] = None diff --git a/src/schemas.py b/src/schemas.py index 484031b..e281fd5 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -6,7 +6,7 @@ Exports: - ResourceName """ -from pydantic import BaseModel +from pydantic import BaseModel, Field from typing import Optional @@ -19,3 +19,24 @@ class ResourceName(CustomBaseModel): organisation: str resource: str instance: Optional[str] = None + + +### Mixins ### +class OrgIDMixin(CustomBaseModel): + organisation_id: int = Field(gt=0) + + +class GroupIDMixin(CustomBaseModel): + group_id: int = Field(gt=0) + + +class PermIDMixin(CustomBaseModel): + permission_id: int = Field(gt=0) + + +class ServiceIDMixin(CustomBaseModel): + service_id: int = Field(gt=0) + + +class UserIDMixin(CustomBaseModel): + user_id: int = Field(gt=0) diff --git a/src/service/schemas.py b/src/service/schemas.py index 47d47f5..531951f 100644 --- a/src/service/schemas.py +++ b/src/service/schemas.py @@ -3,17 +3,12 @@ Pydantic models for service module Models follow the nomenclature of: - Sub-models: "Schema" -- Mixins: "Mixin" - Models: "" ie "ServiceGetServiceResponse" """ -from pydantic import ConfigDict, Field +from pydantic import ConfigDict -from src.schemas import CustomBaseModel - - -class ServiceIDMixin(CustomBaseModel): - service_id: int = Field(gt=0) +from src.schemas import CustomBaseModel, ServiceIDMixin class ServiceSchema(CustomBaseModel): diff --git a/src/user/dependencies.py b/src/user/dependencies.py index 9d2fe02..b2f2152 100644 --- a/src/user/dependencies.py +++ b/src/user/dependencies.py @@ -15,7 +15,7 @@ from src.user.models import User from src.auth.service import claims_dependency from src.database import db_dependency -from src.user.schemas import UserIDMixin +from src.schemas import UserIDMixin async def get_user_model_claims(claims: claims_dependency, db: db_dependency): diff --git a/src/user/schemas.py b/src/user/schemas.py index 74b58dd..114239f 100644 --- a/src/user/schemas.py +++ b/src/user/schemas.py @@ -3,13 +3,9 @@ Pydantic models for the user module """ from typing import Optional -from pydantic import Field, EmailStr +from pydantic import EmailStr -from src.schemas import CustomBaseModel - - -class UserIDMixin(CustomBaseModel): - user_id: int = Field(gt=0) +from src.schemas import CustomBaseModel, OrgIDMixin class OIDCClaims(CustomBaseModel): @@ -52,13 +48,7 @@ class UserResponse(CustomBaseModel): groups: Optional[dict[str, list[dict[str, str | int]]]] = None -class OrgResponse(CustomBaseModel): - org_id: int - name: str - - -class UserPostInvitationRequest(CustomBaseModel): - organisation_id: int +class UserPostInvitationRequest(OrgIDMixin): user_email: EmailStr From bace6388aa6a3ecee3d027107880186019ba46da Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 13:58:08 +0100 Subject: [PATCH 3/6] tests: pytest module markers --- test/pytest.toml | 12 ++++++++++++ test/test_auth_approval.py | 6 ++++++ test/test_auth_general.py | 5 +++++ test/test_auth_root.py | 6 ++++++ test/test_auth_su.py | 6 ++++++ test/test_auth_user.py | 6 ++++++ test/test_iam.py | 5 +++++ test/test_organisation.py | 5 +++++ test/test_service.py | 5 +++++ test/test_user.py | 5 +++++ 10 files changed, 61 insertions(+) create mode 100644 test/pytest.toml diff --git a/test/pytest.toml b/test/pytest.toml new file mode 100644 index 0000000..4b2b03b --- /dev/null +++ b/test/pytest.toml @@ -0,0 +1,12 @@ +[tool.pytest] +markers = [ + "iam_module", + "org_module", + "service_module", + "user_module", + "auth", + "root_user", + "super_admin", + "user", + "preapproval" +] \ No newline at end of file diff --git a/test/test_auth_approval.py b/test/test_auth_approval.py index 69c8a25..8bc73d9 100644 --- a/test/test_auth_approval.py +++ b/test/test_auth_approval.py @@ -12,6 +12,12 @@ from src.user.models import User from src.iam.models import Group +pytestmark = [ + pytest.mark.auth, + pytest.mark.preapproval, +] + + @pytest.fixture(autouse=True) def set_org_partial(db_session): org_model = db_session.get(Org, 1) diff --git a/test/test_auth_general.py b/test/test_auth_general.py index 0547824..7ee2070 100644 --- a/test/test_auth_general.py +++ b/test/test_auth_general.py @@ -7,6 +7,11 @@ from src.organisation.models import Organisation as Org from src.user.models import User +pytestmark = [ + pytest.mark.auth, +] + + @pytest.mark.anyio async def test_get_org_auth_root_su(default_client: AsyncClient, db_session): # If a super admin can access a resource when not the root user diff --git a/test/test_auth_root.py b/test/test_auth_root.py index e068a55..c53b42c 100644 --- a/test/test_auth_root.py +++ b/test/test_auth_root.py @@ -11,6 +11,12 @@ from src.user.models import User from src.iam.models import Group +pytestmark = [ + pytest.mark.auth, + pytest.mark.root_user, +] + + @pytest.fixture(autouse=True) def add_second_org(db_session): db_session.add( diff --git a/test/test_auth_su.py b/test/test_auth_su.py index 1243796..2e438fb 100644 --- a/test/test_auth_su.py +++ b/test/test_auth_su.py @@ -10,6 +10,12 @@ from src.organisation.models import OrgUsers from src.user.models import User +pytestmark = [ + pytest.mark.auth, + pytest.mark.super_admin, +] + + @pytest.mark.anyio async def test_get_user_auth_su(no_su_client: AsyncClient): resp = await no_su_client.get("/user/?user_id=1") diff --git a/test/test_auth_user.py b/test/test_auth_user.py index 3cd66d0..99f5579 100644 --- a/test/test_auth_user.py +++ b/test/test_auth_user.py @@ -6,6 +6,12 @@ import pytest from httpx import AsyncClient +pytestmark = [ + pytest.mark.auth, + pytest.mark.user, +] + + @pytest.mark.anyio async def test_get_self_db_auth_user(no_user_client: AsyncClient): resp = await no_user_client.get("/user/self/db") diff --git a/test/test_iam.py b/test/test_iam.py index 1599d7e..af252b4 100644 --- a/test/test_iam.py +++ b/test/test_iam.py @@ -10,6 +10,11 @@ from src.iam.models import Group from .conftest import generate_query_and_status +pytestmark = [ + pytest.mark.iam_module, +] + + @pytest.mark.anyio async def test_post_act_on_resource_endpoint_success(default_client: AsyncClient): body = { diff --git a/test/test_organisation.py b/test/test_organisation.py index a8708ea..03271dc 100644 --- a/test/test_organisation.py +++ b/test/test_organisation.py @@ -10,6 +10,11 @@ from src.user.models import User from .conftest import generate_query_and_status +pytestmark = [ + pytest.mark.org_module, +] + + @pytest.mark.anyio async def test_get_org_success(default_client: AsyncClient): resp = await default_client.get("/org?org_id=1") diff --git a/test/test_service.py b/test/test_service.py index bd8fe88..a65a939 100644 --- a/test/test_service.py +++ b/test/test_service.py @@ -8,6 +8,11 @@ from httpx import AsyncClient from .conftest import generate_query_and_status +pytestmark = [ + pytest.mark.service_module, +] + + @pytest.mark.anyio async def test_get_services_success(default_client: AsyncClient): resp = await default_client.get("/service/?org_id=1") diff --git a/test/test_user.py b/test/test_user.py index 0266c7a..9a093ba 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -9,6 +9,11 @@ from httpx import AsyncClient from .conftest import generate_query_and_status +pytestmark = [ + pytest.mark.user_module, +] + + @pytest.mark.anyio async def test_get_self_db_success(default_client: AsyncClient): resp = await default_client.get("/user/self/db") From a215d11df9ca793fcf20ca7f76368702ca46f5c7 Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 14:04:21 +0100 Subject: [PATCH 4/6] feat: id returned with permission details --- src/iam/router.py | 1 + src/iam/schemas.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/iam/router.py b/src/iam/router.py index d428e80..32ad7ee 100644 --- a/src/iam/router.py +++ b/src/iam/router.py @@ -272,6 +272,7 @@ async def create_new_permission( ): raise ConflictException(message="Permission already exists") response = { + "id": perm_model.id, "service_name": perm_model.service_name, "resource": perm_model.resource, "action": perm_model.action, diff --git a/src/iam/schemas.py b/src/iam/schemas.py index baf7ae3..e46587b 100644 --- a/src/iam/schemas.py +++ b/src/iam/schemas.py @@ -32,6 +32,7 @@ class UserSchema(CustomBaseModel): class PermissionSchema(CustomBaseModel): model_config = ConfigDict(from_attributes=True, extra="ignore") + id: int service_name: str resource: str action: str From 607f7364538f826eb6238b4242b29b465975b742 Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 14:21:32 +0100 Subject: [PATCH 5/6] feat: user ids return on get org users --- src/organisation/router.py | 2 +- src/organisation/schemas.py | 2 +- test/test_organisation.py | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/organisation/router.py b/src/organisation/router.py index cd1cdb8..8b09544 100644 --- a/src/organisation/router.py +++ b/src/organisation/router.py @@ -265,7 +265,7 @@ async def get_users(org_model: org_model_root_claim_query_dependency): Returns a list of the email addresses of all users of the organisation. """ return { - "users": [user.email for user in org_model.user_rel], + "users": [{"email": user.email, "id": user.id} for user in org_model.user_rel], "organisation": org_model, } diff --git a/src/organisation/schemas.py b/src/organisation/schemas.py index c474544..2d8c1b9 100644 --- a/src/organisation/schemas.py +++ b/src/organisation/schemas.py @@ -92,7 +92,7 @@ class OrgPatchRootResponse(CustomBaseModel): class OrgGetUserResponse(CustomBaseModel): - users: list[str] + users: list[dict[str, str | int]] organisation: OrgSchema diff --git a/test/test_organisation.py b/test/test_organisation.py index 03271dc..8155f5c 100644 --- a/test/test_organisation.py +++ b/test/test_organisation.py @@ -208,10 +208,15 @@ async def test_get_org_users_success(default_client: AsyncClient): data = resp.json() assert resp.status_code == 200 + assert "users" in data assert isinstance(data["users"], list) assert len(data["users"]) == 1 - assert data["users"][0] == "admin@test.com" + + user = data["users"][0] + assert isinstance(user, dict) + assert user["email"] == "admin@test.com" + assert user["id"] == 1 assert "organisation" in data assert data["organisation"]["name"] == "Test Org" From 76e889d836b6f391470aed2cdaed796e615c6b11 Mon Sep 17 00:00:00 2001 From: luxferre Date: Tue, 9 Jun 2026 14:43:52 +0100 Subject: [PATCH 6/6] tests: expanded assertions New assertions added for new data being delivered (eg IDs on endpoints not previously serving IDs) --- test/test_iam.py | 77 ++++++++++++++++++++++++++------------- test/test_organisation.py | 61 ++++++++++++++++++++++++++----- test/test_service.py | 3 ++ test/test_user.py | 4 ++ 4 files changed, 110 insertions(+), 35 deletions(-) diff --git a/test/test_iam.py b/test/test_iam.py index af252b4..591e789 100644 --- a/test/test_iam.py +++ b/test/test_iam.py @@ -137,14 +137,18 @@ async def test_act_on_resource_logic( @pytest.mark.anyio async def test_get_group_permissions_success(default_client: AsyncClient): resp = await default_client.get("/iam/group/permissions?org_id=1&group_id=1") + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "permissions" in data assert isinstance(data["permissions"], list) - assert data["permissions"][0]["service_name"] == "Test Service" - assert data["permissions"][0]["resource"] == "test_resource" - assert data["permissions"][0]["action"] == "read" + + permission = data["permissions"][0] + assert permission["id"] == 1 + assert permission["service_name"] == "Test Service" + assert permission["resource"] == "test_resource" + assert permission["action"] == "read" @pytest.mark.parametrize( @@ -191,15 +195,18 @@ async def test_get_group_permissions_mismatch( @pytest.mark.anyio async def test_get_group_users_success(default_client: AsyncClient): resp = await default_client.get("/iam/group/users?org_id=1&group_id=1") + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "users" in data assert isinstance(data["users"], list) - assert data["users"][0]["id"] == 1 - assert data["users"][0]["first_name"] == "Admin" - assert data["users"][0]["last_name"] == "Test" - assert data["users"][0]["email"] == "admin@test.com" + + user = data["users"][0] + assert user["id"] == 1 + assert user["first_name"] == "Admin" + assert user["last_name"] == "Test" + assert user["email"] == "admin@test.com" @pytest.mark.parametrize( @@ -248,9 +255,10 @@ async def test_post_group_success(default_client: AsyncClient): resp = await default_client.post( "/iam/group", json={"name": "New Group", "organisation_id": 1} ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "group" in data assert isinstance(data["group"], dict) assert data["group"]["name"] == "New Group" @@ -303,9 +311,10 @@ async def test_put_group_perm_success(default_client: AsyncClient, db_session): "/iam/group/permission", json={"permission_id": 1, "group_id": 2, "organisation_id": 1}, ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "group" in data assert isinstance(data["group"], dict) assert data["group"]["name"] == "Test Group Two" @@ -313,9 +322,12 @@ async def test_put_group_perm_success(default_client: AsyncClient, db_session): assert "permissions" in data assert isinstance(data["permissions"], list) - assert data["permissions"][0]["service_name"] == "Test Service" - assert data["permissions"][0]["resource"] == "test_resource" - assert data["permissions"][0]["action"] == "read" + + permission = data["permissions"][0] + assert permission["id"] == 1 + assert permission["service_name"] == "Test Service" + assert permission["resource"] == "test_resource" + assert permission["action"] == "read" @pytest.mark.parametrize( @@ -435,9 +447,10 @@ async def test_put_group_user_success(default_client: AsyncClient, db_session): resp = await default_client.put( "/iam/group/user", json={"user_id": 2, "group_id": 1, "organisation_id": 1} ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "group" in data assert isinstance(data["group"], dict) assert data["group"]["name"] == "Test Group" @@ -445,10 +458,12 @@ async def test_put_group_user_success(default_client: AsyncClient, db_session): assert "users" in data assert isinstance(data["users"], list) - assert data["users"][1]["id"] == 2 - assert data["users"][1]["first_name"] == "User" - assert data["users"][1]["last_name"] == "Test" - assert data["users"][1]["email"] == "user@test.org" + + user = data["users"][1] + assert user["id"] == 2 + assert user["first_name"] == "User" + assert user["last_name"] == "Test" + assert user["email"] == "user@test.org" @pytest.mark.parametrize( @@ -519,9 +534,12 @@ async def test_get_permissions_success(default_client: AsyncClient): assert resp.status_code == 200 assert "permissions" in data assert isinstance(data["permissions"], list) - assert data["permissions"][0]["service_name"] == "Test Service" - assert data["permissions"][0]["resource"] == "test_resource" - assert data["permissions"][0]["action"] == "read" + + permission = data["permissions"][0] + assert permission["id"] == 1 + assert permission["service_name"] == "Test Service" + assert permission["resource"] == "test_resource" + assert permission["action"] == "read" @pytest.mark.parametrize( @@ -542,10 +560,14 @@ async def test_post_perm_success(default_client: AsyncClient, db_session): "/iam/permission", json={"service_id": 1, "resource": "test_resource", "action": "create"}, ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "permission" in data + assert isinstance(data["permission"], dict) + + assert data["permission"]["id"] == 2 assert data["permission"]["service_name"] == "Test Service" assert data["permission"]["resource"] == "test_resource" assert data["permission"]["action"] == "create" @@ -629,9 +651,12 @@ async def test_post_perm_search_success(default_client: AsyncClient, db_session, assert resp.status_code == 200 assert "permissions" in data assert isinstance(data["permissions"], list) - assert data["permissions"][0]["service_name"] == "Test Service" - assert data["permissions"][0]["resource"] == "test_resource" - assert data["permissions"][0]["action"] == "read" + + permission = data["permissions"][0] + assert permission["id"] == 1 + assert permission["service_name"] == "Test Service" + assert permission["resource"] == "test_resource" + assert permission["action"] == "read" @pytest.mark.parametrize( diff --git a/test/test_organisation.py b/test/test_organisation.py index 8155f5c..f852100 100644 --- a/test/test_organisation.py +++ b/test/test_organisation.py @@ -21,12 +21,15 @@ async def test_get_org_success(default_client: AsyncClient): data = resp.json() assert resp.status_code == 200 + assert data["id"] == 1 assert data["name"] == "Test Org" + assert data["status"] == "approved" assert data["root_user"] == "admin@test.com" assert data["billing_contact"] == "billing@test.org" assert data["owner_contact"] == "owner@test.org" assert data["security_contact"] == "security@test.org" - assert data["status"] == "approved" + assert "intake_questionnaire" in data + assert isinstance(data["intake_questionnaire"], dict) @pytest.mark.parametrize( @@ -91,10 +94,11 @@ async def test_patch_org_questionnaire_partial_success( data = resp.json() assert resp.status_code == 200 - assert "intake_questionnaire" in data assert data["name"] == "Test Org" - assert data["intake_questionnaire"]["question_one"] == "new answer one" assert data["status"] == "partial" + assert "intake_questionnaire" in data + assert isinstance(data["intake_questionnaire"], dict) + assert data["intake_questionnaire"]["question_one"] == "new answer one" assert data["intake_questionnaire"]["question_two"] == "answer two" assert data["intake_questionnaire"]["question_three"] is None @@ -159,10 +163,11 @@ async def test_patch_org_questionnaire_submit_success( data = resp.json() assert resp.status_code == 200 - assert "intake_questionnaire" in data assert data["name"] == "Test Org" - assert data["intake_questionnaire"]["question_one"] == "new answer one" assert data["status"] == "submitted" + assert "intake_questionnaire" in data + assert isinstance(data["intake_questionnaire"], dict) + assert data["intake_questionnaire"]["question_one"] == "new answer one" assert data["intake_questionnaire"]["question_two"] == "answer two" assert data["intake_questionnaire"]["question_three"] is None @@ -250,9 +255,11 @@ async def test_post_org_user_success(default_client: AsyncClient, db_session): resp = await default_client.post( "/org/user", json={"organisation_id": 1, "user_id": 2} ) - data = resp.json() assert resp.status_code == 200 + + data = resp.json() + assert "users" in data assert isinstance(data["users"], list) assert "user@test.org" in data["users"] @@ -305,9 +312,10 @@ async def test_patch_org_root_user_success(default_client: AsyncClient, db_sessi resp = await default_client.patch( "/org/root_user", json={"organisation_id": 1, "user_id": 2} ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert data["name"] == "Test Org" assert data["root_user_email"] == "user@test.org" @@ -369,9 +377,10 @@ async def test_patch_org_root_user_non_member(default_client: AsyncClient, db_se @pytest.mark.anyio async def test_get_org_groups_success(default_client: AsyncClient): resp = await default_client.get("/org/groups?org_id=1") + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 assert "groups" in data assert isinstance(data["groups"], list) assert "Test Group" in data["groups"] @@ -399,6 +408,10 @@ async def test_get_org_contact_success(default_client: AsyncClient, contact_type assert resp.status_code == 200 + assert "organisation" in data + assert data["organisation"]["id"] == 1 + assert data["organisation"]["name"] == "Test Org" + attributes = [ "email", "first_name", @@ -469,9 +482,39 @@ async def test_patch_org_contact_success( "/org/contact", json={"organisation_id": 1, "contact_type": "billing", key: value}, ) + assert resp.status_code == 200 + data = resp.json() - assert resp.status_code == 200 + assert "organisation" in data + assert data["organisation"]["id"] == 1 + assert data["organisation"]["name"] == "Test Org" + + 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"]: diff --git a/test/test_service.py b/test/test_service.py index a65a939..1e19a40 100644 --- a/test/test_service.py +++ b/test/test_service.py @@ -20,6 +20,7 @@ async def test_get_services_success(default_client: AsyncClient): assert resp.status_code == 200 assert "services" in data + assert isinstance(data["services"], list) assert data["services"][0]["id"] == 1 assert data["services"][0]["name"] == "Test Service" @@ -43,6 +44,7 @@ async def test_post_service_success(default_client: AsyncClient): assert resp.status_code == 200 assert "service" in data + assert isinstance(data["service"], dict) assert data["service"]["name"] == "New Test Service" assert data["service"]["id"] == 2 assert isinstance(data["service"]["api_key"], str) @@ -72,6 +74,7 @@ async def test_patch_service_success(default_client: AsyncClient): assert resp.status_code == 200 assert "service" in data + assert isinstance(data["service"], dict) assert data["service"]["name"] == "Test Service" assert data["service"]["id"] == 1 assert isinstance(data["service"]["api_key"], str) diff --git a/test/test_user.py b/test/test_user.py index 9a093ba..31fd2bb 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -24,7 +24,9 @@ async def test_get_self_db_success(default_client: AsyncClient): assert data["last_name"] == "Test" assert data["email"] == "admin@test.com" assert "organisations" in data + assert isinstance(data["organisations"], list) assert "groups" in data + assert isinstance(data["groups"], dict) @pytest.mark.anyio @@ -37,7 +39,9 @@ async def test_get_user_success(default_client: AsyncClient): assert data["last_name"] == "Test" assert data["email"] == "admin@test.com" assert "organisations" in data + assert isinstance(data["organisations"], list) assert "groups" in data + assert isinstance(data["groups"], dict) @pytest.mark.anyio