baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
"""共享 fixtures:tenant/org/user/async_api_client + postgres 用例自动跳过。"""
import pytest
import pytest_asyncio
from model_bakery import baker
from django.test import AsyncClient
from apps.core.models import Tenant, Org, TenantMembership
@pytest.fixture
def tenant(db):
return baker.make(Tenant, code="test", name="测试租户", is_active=True)
@pytest.fixture
def other_tenant(db):
return baker.make(Tenant, code="other", name="其他租户", is_active=True)
@pytest.fixture
def org(db, tenant):
return baker.make(
Org, tenant=tenant, code="hq", name="总部", org_path="001", is_active=True
)
@pytest.fixture
def user(db, tenant, django_user_model):
account = django_user_model.objects.create_user(
username="alice", password="alice12345"
)
TenantMembership.objects.create(user=account, tenant=tenant, role="member")
return account
@pytest.fixture
def auth_token(user):
from rest_framework_simplejwt.tokens import RefreshToken
refresh = RefreshToken.for_user(user)
return str(refresh.access_token)
@pytest_asyncio.fixture
async def api_client(user, tenant):
"""async 客户端 + JWT + 租户头。"""
from rest_framework_simplejwt.tokens import RefreshToken
refresh = RefreshToken.for_user(user)
client = AsyncClient()
# 用 META 风格注入 headers
return client
@pytest.fixture
def api_headers(user, tenant):
"""返回 dict 形式的 headers,调用方传给 AsyncClient 请求。"""
from rest_framework_simplejwt.tokens import RefreshToken
refresh = RefreshToken.for_user(user)
return {
"HTTP_AUTHORIZATION": f"Bearer {refresh.access_token}",
"HTTP_X_TENANT_ID": tenant.code,
}
@pytest_asyncio.fixture
async def anon_client():
return AsyncClient()
# ============================================================
# PostgreSQL 专用用例:SQLite 下自动跳过
# ============================================================
def pytest_collection_modifyitems(config, items):
"""标记 `@pytest.mark.postgres` 的用例只在 PG 后端执行。
SQLite 是数据库级写锁,多线程并发会报 `database table is locked`,
这类用例在 SQLite 上跑没有意义(会假失败)。
"""
from django.conf import settings
engine = settings.DATABASES["default"]["ENGINE"]
if "postgresql" in engine:
return # PG 后端:全部执行
skip_pg = pytest.mark.skip(
reason=f"需要 PostgreSQL(当前 {engine.split('.')[-1]});"
"用 DJANGO_SETTINGS_MODULE=config.settings.pgtest 运行"
)
for item in items:
if "postgres" in item.keywords:
item.add_marker(skip_pg)