You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

6.7 KiB

测试指南:剧本上传自动创建子项目

功能: 剧本上传时自动创建独立的子项目工作空间
实施日期: 2026-02-06
关联 RFC: RFC 141


测试前准备

1. 环境要求

# 确保服务运行
docker-compose ps

# 预期输出:
# server    Running
# postgres  Running
# redis     Running
# celery    Running

2. 获取测试数据

# 获取 Token
TOKEN="your-jwt-token"

# 获取父项目 ID(必须有 editor 权限)
PARENT_PROJECT_ID="019c3456-7890-7abc-def0-000000000000"

测试场景

场景 1:自动创建子项目(默认行为)

测试步骤

# 上传 PDF 文件(异步解析)
curl -X POST http://localhost:6170/api/v1/screenplays/file \
  -H "Authorization: Bearer $TOKEN" \
  -F "project_id=$PARENT_PROJECT_ID" \
  -F "name=测试剧本-自动子项目" \
  -F "file=@test-screenplay.pdf"

预期响应

{
  "code": 201,
  "message": "文件上传成功,正在解析...",
  "data": {
    "screenplayId": "019c3456-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "测试剧本-自动子项目",
    "type": "file",
    "projectId": "019c3456-yyyy-yyyy-yyyy-yyyyyyyyyyyy",  //  子项目 ID
    "fileUrl": "screenplays/source/2026/02/06/xxx.pdf",
    "parsingStatus": "parsing",
    "taskId": "celery-task-xxx",
    "subproject": {  //  子项目信息
      "projectId": "019c3456-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
      "name": "测试剧本-自动子项目",
      "parentProjectId": "019c3456-7890-7abc-def0-000000000000",
      "screenplayId": "019c3456-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "type": 1,
      "description": "基于剧本《测试剧本-自动子项目》的制作项目",
      "folderId": "...",
      "createdAt": "2026-02-06T..."
    }
  }
}

验证数据库

-- 1. 验证子项目创建
SELECT 
    id, 
    name, 
    parent_project_id, 
    screenplay_id,
    description
FROM projects
WHERE name = '测试剧本-自动子项目';

-- 预期结果:
-- parent_project_id = <父项目ID>
-- screenplay_id = <剧本ID>

-- 2. 验证剧本关联
SELECT 
    screenplay_id, 
    name, 
    project_id
FROM screenplays
WHERE name = '测试剧本-自动子项目';

-- 预期结果:
-- project_id = <子项目ID>(而非父项目ID)

场景 2:禁用自动创建子项目

测试步骤

# 上传 TXT 文件(同步解析),禁用自动创建
curl -X POST http://localhost:6170/api/v1/screenplays/file \
  -H "Authorization: Bearer $TOKEN" \
  -F "project_id=$PARENT_PROJECT_ID" \
  -F "name=测试剧本-无子项目" \
  -F "file=@test-screenplay.txt" \
  -F "auto_create_subproject=false"

预期响应

{
  "code": 201,
  "message": "文件上传成功",
  "data": {
    "screenplayId": "019c3456-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
    "name": "测试剧本-无子项目",
    "type": "file",
    "projectId": "019c3456-7890-7abc-def0-000000000000",  //  父项目 ID
    "parsingStatus": "completed",
    "content": "...",
    "subproject": null  //  无子项目
  }
}

验证数据库

-- 验证剧本直接归属父项目
SELECT 
    screenplay_id, 
    name, 
    project_id
FROM screenplays
WHERE name = '测试剧本-无子项目';

-- 预期结果:
-- project_id = <父项目ID>(而非子项目ID)

-- 验证没有创建子项目
SELECT COUNT(*) FROM projects
WHERE name = '测试剧本-无子项目';

-- 预期结果:0

场景 3:协作项目权限继承

测试步骤

# 1. 创建协作项目(type=2)
COLLAB_PROJECT_ID="..."

# 2. 添加成员到协作项目
# (通过项目管理 API)

# 3. 上传剧本,自动创建子项目
curl -X POST http://localhost:6170/api/v1/screenplays/file \
  -H "Authorization: Bearer $TOKEN" \
  -F "project_id=$COLLAB_PROJECT_ID" \
  -F "name=协作剧本" \
  -F "file=@test.pdf"

验证权限继承

-- 1. 获取父项目成员
SELECT user_id, role FROM project_members
WHERE project_id = '<协作项目ID>';

-- 2. 验证子项目成员
SELECT user_id, role FROM project_members
WHERE project_id = '<子项目ID>';

-- 预期:子项目成员列表与父项目一致

场景 4:事务回滚测试

测试步骤

# 故意传入无效的父项目 ID
curl -X POST http://localhost:6170/api/v1/screenplays/file \
  -H "Authorization: Bearer $TOKEN" \
  -F "project_id=invalid-uuid" \
  -F "name=测试事务" \
  -F "file=@test.pdf"

预期行为

  • 返回错误响应(400 或 404)
  • 数据库中没有创建任何记录(剧本、子项目、附件)
  • MinIO 中没有上传文件

性能测试

响应时间测试

# 测试 10 次上传,计算平均响应时间
for i in {1..10}; do
  time curl -X POST http://localhost:6170/api/v1/screenplays/file \
    -H "Authorization: Bearer $TOKEN" \
    -F "project_id=$PARENT_PROJECT_ID" \
    -F "name=性能测试-$i" \
    -F "file=@test.pdf" \
    > /dev/null 2>&1
done

预期性能

  • 同步解析(TXT): < 300ms
  • 异步解析(PDF): < 500ms
  • 增量开销: +50-100ms(相比不创建子项目)

常见问题排查

问题 1:响应中 subproject 为 null

可能原因

  1. 设置了 auto_create_subproject=false
  2. Service 层抛出异常但被捕获

排查步骤

# 检查服务器日志
docker-compose logs server | grep "剧本创建"

# 预期日志:
# "子项目创建成功 | 子项目ID: ..."
# "剧本创建成功 | 剧本ID: ... | 子项目ID: ..."

问题 2:数据库中子项目的 screenplay_id 为 NULL

可能原因

  • 更新子项目的步骤失败

排查步骤

-- 检查子项目状态
SELECT id, name, screenplay_id, parent_project_id
FROM projects
WHERE parent_project_id IS NOT NULL
ORDER BY created_at DESC
LIMIT 10;

问题 3:权限错误

错误信息: "没有权限在此项目中创建子项目"

解决方案

  • 确保用户在父项目中拥有 editor 权限
  • 检查 project_members

回滚方案

如需临时禁用自动创建子项目:

方法 1:修改 API 默认值

# server/app/api/v1/screenplays.py
auto_create_subproject: bool = Form(False)  # ← 改为 False

方法 2:前端传参

// 在所有上传请求中添加
formData.append('auto_create_subproject', 'false');

相关文档