Fix API compatibility and add user/role/permission and asset import/export

This commit is contained in:
2026-01-25 23:36:23 +08:00
commit 501d11e14e
371 changed files with 68853 additions and 0 deletions

View File

@@ -0,0 +1,286 @@
"""
测试配置和Fixtures
"""
import pytest
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.pool import StaticPool
from datetime import datetime
from typing import AsyncGenerator
from app.main import app
from app.db.base import Base
from app.models.user import User, Role, UserRole, Permission
from app.models.device_type import DeviceType, DeviceTypeField
from app.core.security import get_password_hash, security_manager
# 创建测试数据库引擎
test_engine = create_async_engine(
"sqlite+aiosqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
# 创建测试会话工厂
TestSessionLocal = async_sessionmaker(
test_engine,
class_=AsyncSession,
expire_on_commit=False,
autocommit=False,
autoflush=False,
)
@pytest.fixture(scope="function")
async def db_session():
"""创建测试数据库会话"""
async with test_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with TestSessionLocal() as session:
yield session
await session.rollback()
async with test_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@pytest.fixture(scope="function")
async def client(db_session):
"""创建测试客户端"""
from app.core.deps import get_db
async def override_get_db():
yield db_session
app.dependency_overrides[get_db] = override_get_db
async with AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test"
) as ac:
yield ac
app.dependency_overrides.clear()
# ===== 用户相关Fixtures =====
@pytest.fixture
async def test_password() -> str:
"""测试密码"""
return "Test123456"
@pytest.fixture
async def test_user(db_session: AsyncSession, test_password: str) -> User:
"""创建测试用户"""
user = User(
username="testuser",
password_hash=get_password_hash(test_password),
real_name="测试用户",
email="test@example.com",
phone="13800138000",
status="active",
is_admin=False
)
db_session.add(user)
await db_session.flush()
await db_session.refresh(user)
return user
@pytest.fixture
async def test_admin(db_session: AsyncSession, test_password: str) -> User:
"""创建测试管理员"""
admin = User(
username="admin",
password_hash=get_password_hash(test_password),
real_name="系统管理员",
email="admin@example.com",
status="active",
is_admin=True
)
db_session.add(admin)
await db_session.flush()
await db_session.refresh(admin)
return admin
@pytest.fixture
async def test_role(db_session: AsyncSession) -> Role:
"""创建测试角色"""
role = Role(
role_name="测试角色",
role_code="TEST_ROLE",
description="用于测试的角色",
status="active",
sort_order=1
)
db_session.add(role)
await db_session.flush()
await db_session.refresh(role)
return role
@pytest.fixture
async def auth_headers(client: AsyncClient, test_user: User, test_password: str) -> dict:
"""获取认证头"""
# 登录获取token
response = await client.post(
"/api/v1/auth/login",
json={
"username": test_user.username,
"password": test_password,
"captcha": "1234",
"captcha_key": "test-uuid"
}
)
if response.status_code == 200:
token = response.json()["data"]["access_token"]
return {"Authorization": f"Bearer {token}"}
return {}
@pytest.fixture
async def admin_headers(client: AsyncClient, test_admin: User, test_password: str) -> dict:
"""获取管理员认证头"""
response = await client.post(
"/api/v1/auth/login",
json={
"username": test_admin.username,
"password": test_password,
"captcha": "1234",
"captcha_key": "test-uuid"
}
)
if response.status_code == 200:
token = response.json()["data"]["access_token"]
return {"Authorization": f"Bearer {token}"}
return {}
# ===== 设备类型相关Fixtures =====
@pytest.fixture
async def test_device_type(db_session: AsyncSession, test_admin: User) -> DeviceType:
"""创建测试设备类型"""
device_type = DeviceType(
type_code="COMPUTER",
type_name="计算机",
category="IT设备",
description="台式机、笔记本等",
icon="computer",
status="active",
sort_order=1,
created_by=test_admin.id
)
db_session.add(device_type)
await db_session.flush()
await db_session.refresh(device_type)
return device_type
@pytest.fixture
async def test_device_type_with_fields(
db_session: AsyncSession,
test_device_type: DeviceType,
test_admin: User
) -> DeviceType:
"""创建带字段的测试设备类型"""
fields = [
DeviceTypeField(
device_type_id=test_device_type.id,
field_code="cpu",
field_name="CPU型号",
field_type="text",
is_required=True,
placeholder="例如: Intel i5-10400",
validation_rules={"max_length": 100},
sort_order=1,
created_by=test_admin.id
),
DeviceTypeField(
device_type_id=test_device_type.id,
field_code="memory",
field_name="内存容量",
field_type="select",
is_required=True,
options=[
{"label": "8GB", "value": "8"},
{"label": "16GB", "value": "16"},
{"label": "32GB", "value": "32"}
],
sort_order=2,
created_by=test_admin.id
),
DeviceTypeField(
device_type_id=test_device_type.id,
field_code="disk",
field_name="硬盘容量",
field_type="text",
is_required=False,
placeholder="例如: 512GB SSD",
sort_order=3,
created_by=test_admin.id
)
]
for field in fields:
db_session.add(field)
await db_session.flush()
return test_device_type
# ===== 辅助函数Fixtures =====
@pytest.fixture
def sample_asset_data(test_device_type: DeviceType) -> dict:
"""示例资产数据"""
return {
"asset_name": "测试资产",
"device_type_id": test_device_type.id,
"organization_id": 1,
"model": "测试型号",
"serial_number": f"SN{datetime.now().strftime('%Y%m%d%H%M%S')}",
"purchase_date": "2024-01-15",
"purchase_price": 5000.00,
"warranty_period": 24,
"location": "测试位置",
"dynamic_attributes": {
"cpu": "Intel i5-10400",
"memory": "16",
"disk": "512GB SSD"
}
}
@pytest.fixture
def sample_device_type_data() -> dict:
"""示例设备类型数据"""
return {
"type_code": "LAPTOP",
"type_name": "笔记本电脑",
"category": "IT设备",
"description": "笔记本电脑类",
"icon": "laptop",
"sort_order": 1
}
@pytest.fixture
def sample_field_data() -> dict:
"""示例字段数据"""
return {
"field_code": "gpu",
"field_name": "显卡型号",
"field_type": "text",
"is_required": False,
"placeholder": "例如: GTX 1660Ti",
"validation_rules": {"max_length": 100},
"sort_order": 4
}