"""Tests for PUT /api/users/{id}/password (admin only) - issue #25(c). Kept in its own file rather than test_users.py: that file covers the rest of the users router, worked on in a different lot in the same session. """ from httpx import AsyncClient from src.backend.models.orm.user import User from src.backend.tests.conftest import auth_headers class TestChangeUserPassword: async def test_admin_changes_password_invalidates_api_key( self, client: AsyncClient, admin_user: User, maker_user: User ): """Changing a user's password invalidates their existing api_key, the same as setup.py's change-user-password (setup.py:634). """ old_key = maker_user.plain_key old_username = maker_user.username assert old_key is not None resp = await client.put( f"/api/users/{maker_user.id}/password", headers=auth_headers(admin_user), json={"password": "NewSecurePass1"}, ) assert resp.status_code == 200 assert "changed" in resp.json()["message"].lower() # The old key no longer authenticates. Read it before the request # above: the client and app share one session (see conftest), so # `maker_user.plain_key` in this process reflects the mutation too. resp2 = await client.get("/api/auth/me", headers={"X-API-Key": old_key}) assert resp2.status_code == 401 # The new password works and issues a fresh key. resp3 = await client.post( "/api/auth/login", json={"username": old_username, "password": "NewSecurePass1"}, ) assert resp3.status_code == 200 assert resp3.json()["api_key"] != old_key async def test_non_admin_forbidden( self, client: AsyncClient, maker_user: User ): resp = await client.put( f"/api/users/{maker_user.id}/password", headers=auth_headers(maker_user), json={"password": "WhateverPass1"}, ) assert resp.status_code == 403 async def test_user_not_found( self, client: AsyncClient, admin_user: User ): resp = await client.put( "/api/users/999999/password", headers=auth_headers(admin_user), json={"password": "WhateverPass1"}, ) assert resp.status_code == 404 async def test_password_too_short_rejected( self, client: AsyncClient, admin_user: User, maker_user: User ): resp = await client.put( f"/api/users/{maker_user.id}/password", headers=auth_headers(admin_user), json={"password": "short"}, ) assert resp.status_code == 422