"""Integration tests for channels login_router endpoints.""" from __future__ import annotations import httpx import pytest from .conftest import ( BASE_URL, DEFAULT_CHANNEL_TYPE, NON_EXISTENT_ACCOUNT_ID, NON_EXISTENT_SESSION_ID, ) pytestmark = [pytest.mark.asyncio, pytest.mark.integration] LOGIN_BASE = f"{BASE_URL}/{DEFAULT_CHANNEL_TYPE}/accounts/{NON_EXISTENT_ACCOUNT_ID}/login" # ============================================================================= # === Auth three-tier for login status === # ============================================================================= async def test_get_login_status_requires_auth(test_client: httpx.AsyncClient): # Act response = await test_client.get(f"{LOGIN_BASE}/status") # Assert assert response.status_code == 401, response.text async def test_get_login_status_forbids_standard_user(test_client: httpx.AsyncClient, standard_user): # Act response = await test_client.get( f"{LOGIN_BASE}/status", headers=standard_user["headers"], ) # Assert assert response.status_code == 403, response.text async def test_get_login_status_non_existent_returns_404(test_client: httpx.AsyncClient, admin_headers): # Act response = await test_client.get(f"{LOGIN_BASE}/status", headers=admin_headers) # Assert assert response.status_code == 404, response.text # ============================================================================= # === qr/start === # ============================================================================= async def test_qr_start_requires_auth(test_client: httpx.AsyncClient): # Act response = await test_client.post(f"{LOGIN_BASE}/qr/start") # Assert assert response.status_code == 401, response.text async def test_qr_start_forbids_standard_user(test_client: httpx.AsyncClient, standard_user): # Act response = await test_client.post( f"{LOGIN_BASE}/qr/start", headers=standard_user["headers"], ) # Assert assert response.status_code == 403, response.text async def test_qr_start_non_existent_account_returns_404(test_client: httpx.AsyncClient, admin_headers): # Act response = await test_client.post(f"{LOGIN_BASE}/qr/start", headers=admin_headers) # Assert assert response.status_code == 404, response.text # ============================================================================= # === qr/wait === # ============================================================================= async def test_qr_wait_requires_session_id(test_client: httpx.AsyncClient, admin_headers): # Act — 缺少必填 query 参数 session_id response = await test_client.get(f"{LOGIN_BASE}/qr/wait", headers=admin_headers) # Assert assert response.status_code == 422, response.text async def test_qr_wait_non_existent_account_returns_404_or_422(test_client: httpx.AsyncClient, admin_headers): # Arrange params = {"session_id": NON_EXISTENT_SESSION_ID} # Act response = await test_client.get( f"{LOGIN_BASE}/qr/wait", params=params, headers=admin_headers, ) # Assert — 账户不存在返回 404,或登录会话无效返回 422 assert response.status_code in (404, 422), response.text async def test_qr_wait_rejects_timeout_out_of_range(test_client: httpx.AsyncClient, admin_headers): # Arrange — timeout_ms=500 低于下限 1000 params = {"session_id": NON_EXISTENT_SESSION_ID, "timeout_ms": 500} # Act response = await test_client.get( f"{LOGIN_BASE}/qr/wait", params=params, headers=admin_headers, ) # Assert assert response.status_code == 422, response.text async def test_qr_wait_rejects_timeout_over_max(test_client: httpx.AsyncClient, admin_headers): # Arrange — timeout_ms=70000 超过上限 60000 params = {"session_id": NON_EXISTENT_SESSION_ID, "timeout_ms": 70000} # Act response = await test_client.get( f"{LOGIN_BASE}/qr/wait", params=params, headers=admin_headers, ) # Assert assert response.status_code == 422, response.text # ============================================================================= # === qr/cancel === # ============================================================================= async def test_qr_cancel_requires_session_id(test_client: httpx.AsyncClient, admin_headers): # Act — 缺少必填 query 参数 session_id response = await test_client.post(f"{LOGIN_BASE}/qr/cancel", headers=admin_headers) # Assert assert response.status_code == 422, response.text async def test_qr_cancel_non_existent_account_returns_404_or_422(test_client: httpx.AsyncClient, admin_headers): # Arrange params = {"session_id": NON_EXISTENT_SESSION_ID} # Act response = await test_client.post( f"{LOGIN_BASE}/qr/cancel", params=params, headers=admin_headers, ) # Assert assert response.status_code in (404, 422), response.text # ============================================================================= # === qr/refresh === # ============================================================================= async def test_qr_refresh_requires_session_id(test_client: httpx.AsyncClient, admin_headers): # Act — 缺少必填 query 参数 session_id response = await test_client.post(f"{LOGIN_BASE}/qr/refresh", headers=admin_headers) # Assert assert response.status_code == 422, response.text async def test_qr_refresh_non_existent_account_returns_404_or_422(test_client: httpx.AsyncClient, admin_headers): # Arrange params = {"session_id": NON_EXISTENT_SESSION_ID} # Act response = await test_client.post( f"{LOGIN_BASE}/qr/refresh", params=params, headers=admin_headers, ) # Assert assert response.status_code in (404, 422), response.text # ============================================================================= # === logout === # ============================================================================= async def test_logout_requires_auth(test_client: httpx.AsyncClient): # Act response = await test_client.post(f"{LOGIN_BASE}/logout") # Assert assert response.status_code == 401, response.text async def test_logout_forbids_standard_user(test_client: httpx.AsyncClient, standard_user): # Act response = await test_client.post( f"{LOGIN_BASE}/logout", headers=standard_user["headers"], ) # Assert assert response.status_code == 403, response.text async def test_logout_non_existent_account_returns_404(test_client: httpx.AsyncClient, admin_headers): # Act response = await test_client.post(f"{LOGIN_BASE}/logout", headers=admin_headers) # Assert assert response.status_code == 404, response.text # ============================================================================= # === force-logout === # ============================================================================= async def test_force_logout_requires_auth(test_client: httpx.AsyncClient): # Arrange body = {"reason": "pytest"} # Act response = await test_client.post(f"{LOGIN_BASE}/force-logout", json=body) # Assert assert response.status_code == 401, response.text async def test_force_logout_forbids_standard_user(test_client: httpx.AsyncClient, standard_user): # Arrange body = {"reason": "pytest"} # Act response = await test_client.post( f"{LOGIN_BASE}/force-logout", json=body, headers=standard_user["headers"], ) # Assert assert response.status_code == 403, response.text async def test_force_logout_requires_reason(test_client: httpx.AsyncClient, admin_headers): # Act — 缺少必填字段 reason response = await test_client.post( f"{LOGIN_BASE}/force-logout", json={}, headers=admin_headers, ) # Assert assert response.status_code == 422, response.text async def test_force_logout_non_existent_account_returns_404(test_client: httpx.AsyncClient, admin_headers): # Arrange body = {"reason": "pytest"} # Act response = await test_client.post( f"{LOGIN_BASE}/force-logout", json=body, headers=admin_headers, ) # Assert assert response.status_code == 404, response.text