from dataclasses import replace from datetime import UTC, datetime from fastapi.testclient import TestClient from sqlalchemy import create_engine, func, select from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.pool import StaticPool from zbt.core.config import Settings from zbt.core.passwords import PasswordService from zbt.domains.catalog.models import Plan, Product, ProductVersion from zbt.domains.catalog.repository import InMemoryCatalogRepository from zbt.domains.identity.models import AdminUser, H5User from zbt.infrastructure.mysql.core_models import CoreBase, PlanRecord from zbt.infrastructure.mysql.repositories import ( SqlAlchemyCatalogRepository, SqlAlchemyIdentityRepository, ) from zbt.main import create_app def test_sqlalchemy_repositories_round_trip_identity_and_catalog() -> None: engine = create_engine("sqlite+pysqlite:///:memory:") CoreBase.metadata.create_all(engine) session_factory = sessionmaker(engine, class_=Session, expire_on_commit=False) identities = SqlAlchemyIdentityRepository(session_factory) catalog = SqlAlchemyCatalogRepository(session_factory) identities.save_h5_user( H5User( id="01USER00000000000000000001", mobile="18800000001", mobile_masked="188****0001", display_name="测试用户甲", status="ACTIVE", created_at=datetime(2026, 7, 25, tzinfo=UTC), ) ) catalog.save_product( Product( id="01PRODUCT00000000000000001", product_code="MED-BASIC", name="蓉惠基础医疗险", category="MEDICAL", summary="基础医疗保障", status="ACTIVE", ) ) version = ProductVersion( id="01VERSION00000000000000002", product_id="01PRODUCT00000000000000001", version_no="2.0.0", status="PUBLISHED", effective_from=datetime(2026, 1, 1, tzinfo=UTC), effective_to=None, plans=(Plan(id="01PLAN0000000000000000002", code="BASIC", name="基础计划"),), ) catalog.save_version(version) catalog.save_version(version) assert identities.get_h5_user_by_mobile("18800000001").display_name == "测试用户甲" assert catalog.list_products()[0].product_code == "MED-BASIC" loaded_version = catalog.list_versions("01PRODUCT00000000000000001")[0] assert loaded_version.version_no == "2.0.0" assert loaded_version.is_available_at(datetime(2026, 7, 25, tzinfo=UTC)) with session_factory() as session: assert session.scalar(select(func.count()).select_from(PlanRecord)) == 1 def test_admin_session_loaded_from_sql_repository_remains_active() -> None: engine = create_engine( "sqlite+pysqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) CoreBase.metadata.create_all(engine) session_factory = sessionmaker(engine, class_=Session, expire_on_commit=False) identities = SqlAlchemyIdentityRepository(session_factory) admin_user = AdminUser( id="01ADMIN0000000000000000001", username="admin", password_hash=PasswordService().hash("旧密码仅用于覆盖测试"), display_name="系统管理员", status="ACTIVE", roles=("SUPER_ADMIN",), permissions=("*",), data_scope="ALL", ) identities.save_admin_user(admin_user) identities.save_admin_user( replace( admin_user, password_hash=PasswordService().hash("zaq1XSW@"), ) ) settings = Settings( app_env="test", jwt_access_secret="a" * 32, jwt_refresh_secret="b" * 32, field_encryption_key="c" * 32, ) application = create_app( settings=settings, identity_repository=identities, catalog_repository=InMemoryCatalogRepository(), ) with TestClient(application) as client: login = client.post( "/api/v1/admin/auth/login", json={"username": "admin", "password": "zaq1XSW@"}, ) token = login.json()["data"]["tokens"]["access_token"] profile = client.get( "/api/v1/admin/me", headers={"Authorization": f"Bearer {token}"}, ) assert profile.status_code == 200 assert profile.json()["data"]["display_name"] == "系统管理员"