from datetime import UTC, datetime from fastapi.testclient import TestClient from app.domains.catalog.repository import InMemoryCatalogRepository from app.domains.identity.repository import InMemoryIdentityRepository from app.main import create_app def build_client() -> TestClient: return TestClient( create_app( identity_repository=InMemoryIdentityRepository(), catalog_repository=InMemoryCatalogRepository(), ) ) def test_success_envelope_contains_request_id_and_utc_server_time() -> None: with build_client() as client: response = client.get( "/api/v1/system/health/live", headers={"X-Request-ID": "req_contract_success"}, ) assert response.status_code == 200 assert response.headers["X-Request-ID"] == "req_contract_success" assert response.json()["meta"]["request_id"] == "req_contract_success" server_time = datetime.fromisoformat( response.json()["meta"]["server_time"].replace("Z", "+00:00") ) assert server_time.tzinfo == UTC def test_request_validation_uses_stable_error_envelope() -> None: with build_client() as client: response = client.post( "/api/v1/h5/auth/login", json={"mobile": "123", "code": "1"}, headers={"X-Request-ID": "req_contract_validation"}, ) assert response.status_code == 400 assert response.headers["X-Request-ID"] == "req_contract_validation" assert response.json() == { "success": False, "error": { "code": "VALIDATION_ERROR", "message": "请求参数无效", "details": { "fields": [ { "field": "body.mobile", "message": "String should have at least 11 characters", }, {"field": "body.code", "message": "String should have at least 6 characters"}, ] }, "retryable": False, }, "meta": {"request_id": "req_contract_validation"}, }