diff --git a/tests/e2e/management/management_client.py b/tests/e2e/management/management_client.py index b2c9eb6a29b..a9dedac8e61 100644 --- a/tests/e2e/management/management_client.py +++ b/tests/e2e/management/management_client.py @@ -45,6 +45,7 @@ from models import ( TeamNewResponse, TeamUpdateBody, UserDeleteBody, + UserDeleteResponse, UserInfoParams, UserInfoResponse, UserListParams, @@ -287,6 +288,18 @@ class ManagementClient: response_type=NoBody, ) + def delete_user_strict(self, user_id: str) -> None: + """Strict delete for the act phase of a test: a failed delete is a hard + failure, unlike the warn-only delete_user used at teardown.""" + _ = unwrap( + self.proxy.transport.post( + "/user/delete", + headers=self.proxy.transport.master, + json=UserDeleteBody(user_ids=[user_id]), + response_type=UserDeleteResponse, + ) + ) + def user_info(self, user_id: str) -> UserInfoResponse: return unwrap( self.proxy.transport.get( diff --git a/tests/e2e/management/test_management_e2e.py b/tests/e2e/management/test_management_e2e.py index dfb4a506bd6..dae68ba786d 100644 --- a/tests/e2e/management/test_management_e2e.py +++ b/tests/e2e/management/test_management_e2e.py @@ -335,6 +335,28 @@ class TestUserRoutes: assert info.user_role == "internal_user_viewer", ( f"/user/info reports user_role {info.user_role!r} after /user/update to 'internal_user_viewer'" ) + @pytest.mark.covers("mgmt.user.delete.persists") + def test_delete_removes_the_user_from_inventory( + self, client: ManagementClient, resources: ResourceManager + ) -> None: + """The teardown's deferred delete fires again on the already-deleted user by + design: the deferred cleanup must survive this test failing before the + in-body delete, and a repeat /user/delete is a cheap no-op the warn-only + teardown absorbs.""" + user_id = _create_user( + client, + resources, + UserNewBody(user_email=f"e2e-mgmt-{unique_marker()}@example.com", user_role="internal_user"), + ) + assert client.user_count(user_id) == 1, f"user {user_id} was not created before deletion" + + client.delete_user_strict(user_id) + + def removed() -> bool | None: + return True if client.user_count(user_id) == 0 else None + + _ = _poll(client, removed, f"user {user_id} still present in /user/list after /user/delete at the deadline") + @pytest.mark.covers("mgmt.user.list.happy_path") def test_created_users_appear_in_user_list( self, client: ManagementClient, resources: ResourceManager diff --git a/tests/e2e/models.py b/tests/e2e/models.py index 9e773120846..e07814f2568 100644 --- a/tests/e2e/models.py +++ b/tests/e2e/models.py @@ -705,6 +705,10 @@ class UserDeleteBody(BaseModel): user_ids: list[str] +class UserDeleteResponse(RootModel[int]): + pass + + class UserListParams(BaseModel): user_ids: str