# Fonrey 客户端发布模块测试用例文档(可自动化) > 文档版本:v1.0 > 适用范围:`PRD/发布管理/客户端发布管理模块PRD.md` v1.2 > 用例编号范围:`TC-FON-000049` ~ `TC-FON-000072`(全局唯一) > 编号规范:`TEST_CASES/TEST_CASE_ID_SPEC.md` --- ## 变更历史 | 日期 | 变更人 | 变更内容 | |---|---|---| | 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) | ## 1. 目标与原则 1. 覆盖客户端发布模块 P0:下载安装、自动升级、版本发布、版本分布统计。 2. 每个用例必须可追溯到 `test_case_id + step_id`。 3. 优先 API 集成自动化,客户端壳层 UI 能力以 E2E/手工补充。 4. 失败报告必须定位到具体步骤,并保留请求响应或截图证据。 --- ## 2. 自动化执行与报告要求(强制) - 执行层: - API 集成:`pytest + pytest-django`(public schema) - 客户端 E2E:后续 `playwright + Electron`(当前先预留) - 每步输出:`run_id / test_case_id / step_id / status / expected_result / actual_result / error_message` - 失败附件: - API:请求体、响应体、关键日志路径 - E2E:截图与视频路径 --- ## 3. 客户端发布模块 API 端点口径(以 PRD/TECH_STACK 为准) - `GET /api/release/updates/latest/` - `GET /api/release/updates/` - `POST /api/release/updates/` - `PATCH /api/release/updates/{id}/` - `POST /api/release/updates/{id}/rollback/` - `POST /api/release/heartbeats/` - `GET /api/release/metrics/version-distribution/` - `GET /api/release/metrics/tenant-installs/` - `GET /api/release/metrics/tenant-leaderboard/` --- ## 4. 全量测试用例清单(24条) ## A. 下载与完整性(Story 1) ### TC-FON-000049 官网下载页可访问且展示最新版本 - 级别:E2E - 步骤: - `TC-FON-000049-S01` 访问官网客户端下载页 - `TC-FON-000049-S02` 校验展示版本号/发布日期/下载按钮 - `TC-FON-000049-S03` 校验下载按钮链接可用 - 预期:页面可访问,元信息完整 ### TC-FON-000050 latest 接口返回下载地址与校验值 - 级别:API - 步骤: - `TC-FON-000050-S01` 调用 `GET /api/release/updates/latest/?platform=win32&arch=x64¤t_version=1.2.0` - `TC-FON-000050-S02` 校验返回 `download_url`、`checksum_sha256`、`release_notes` - `TC-FON-000050-S03` 校验 `checksum_sha256` 长度为 64 - 预期:响应字段完整且格式正确 ### TC-FON-000051 安装包 SHA256 校验通过 - 级别:API+脚本 - 步骤: - `TC-FON-000051-S01` 获取 `download_url` 和 `checksum_sha256` - `TC-FON-000051-S02` 下载文件并计算本地 SHA256 - `TC-FON-000051-S03` 比对本地值与接口返回值 - 预期:一致,允许进入安装流程 ### TC-FON-000052 安装包 SHA256 不一致时拒绝安装 - 级别:客户端集成 - 步骤: - `TC-FON-000052-S01` 构造篡改包或错误 checksum - `TC-FON-000052-S02` 触发更新下载完成后的校验 - `TC-FON-000052-S03` 校验客户端拒绝安装并保留当前版本 - 预期:提示完整性校验失败,不覆盖现版本 --- ## B. 自动升级(Story 3) ### TC-FON-000053 无新版本时返回 has_update=false - 级别:API - 步骤:`S01` 用当前最新版本调用 latest;`S02` 校验 `has_update=false`;`S03` 校验 `latest_version` 存在 - 预期:不触发更新 ### TC-FON-000054 有新版本时返回升级信息 - 级别:API - 步骤:`S01` 用旧版本调用 latest;`S02` 校验 `has_update=true`;`S03` 校验 `latest_version` 高于 `current_version` - 预期:触发可升级状态 ### TC-FON-000055 普通更新允许“稍后提醒” - 级别:客户端 E2E - 步骤:`S01` 服务端发布 `release_type=normal`;`S02` 客户端检测更新;`S03` 校验出现“立即更新/稍后提醒” - 预期:普通更新可延期 ### TC-FON-000056 强制更新不允许“稍后提醒” - 级别:客户端 E2E - 步骤:`S01` 服务端发布 `release_type=force`;`S02` 客户端检测更新;`S03` 校验仅可“立即更新” - 预期:必须升级后继续使用 ### TC-FON-000057 更新下载失败时保持当前版本可用 - 级别:客户端 E2E - 步骤:`S01` 模拟下载中断/磁盘不足;`S02` 校验错误提示;`S03` 校验当前版本仍可正常操作 - 预期:失败可恢复,不影响业务使用 ### TC-FON-000058 更新成功后重启生效并保留登录态 - 级别:客户端 E2E - 步骤:`S01` 执行更新并下载完成;`S02` 重启客户端;`S03` 校验标题版本号更新且会话恢复 - 预期:升级成功且无需重新登录 --- ## C. 平台发布管理(Story 4) ### TC-FON-000059 平台管理员可创建草稿版本 - 级别:API - 步骤:`S01` 调用 `POST /api/release/updates/` 创建草稿;`S02` 校验 `status=draft`;`S03` 校验版本记录可在列表查询到 - 预期:草稿创建成功 ### TC-FON-000060 版本号必须符合 SemVer - 级别:API - 步骤:`S01` 提交非法版本号(如 `1.2`);`S02` 校验 400;`S03` 校验错误码 `RELEASE_VERSION_INVALID` - 预期:非法版本号被拒绝 ### TC-FON-000061 发布后 latest 接口即时可见 - 级别:API - 步骤:`S01` 将草稿改为 `published`(PATCH);`S02` 调用 latest;`S03` 校验返回该版本 - 预期:发布即时生效 ### TC-FON-000062 同平台架构仅允许一个 published - 级别:API - 步骤:`S01` 已有一个 published;`S02` 尝试并发发布第二个;`S03` 校验冲突(409) - 预期:唯一生效版本约束成立 ### TC-FON-000063 版本下线后 latest 不再返回该版本 - 级别:API - 步骤:`S01` 将已发布版本改 `archived`;`S02` 调用 latest;`S03` 校验不返回已下线版本 - 预期:下线立即生效 ### TC-FON-000064 回滚接口将历史版本恢复为 published - 级别:API - 步骤:`S01` 调用 `POST /api/release/updates/{id}/rollback/`;`S02` 校验目标版本为 `published`;`S03` 校验原版本自动下线 - 预期:回滚原子完成 --- ## D. Heartbeat 与版本分布(Story 5) ### TC-FON-000065 启动心跳首次上报创建记录 - 级别:API - 步骤:`S01` 调用 `POST /api/release/heartbeats/`;`S02` 校验写入 `(tenant_id, device_id)`;`S03` 校验 `launch_count=1` - 预期:首次上报成功 ### TC-FON-000066 启动心跳重复上报走 Upsert - 级别:API - 步骤:`S01` 对同 `(tenant_id,device_id)` 再次上报;`S02` 校验未新增新行;`S03` 校验 `launch_count+1` 且 `last_seen_at` 刷新 - 预期:符合 Upsert 语义 ### TC-FON-000067 版本分布统计按 24h 活跃口径 - 级别:API - 步骤:`S01` 构造多版本心跳数据(含超 24h);`S02` 调用 `GET /api/release/metrics/version-distribution/`;`S03` 校验仅统计最近 24h 活跃 - 预期:统计口径正确 ### TC-FON-000068 指定租户安装统计返回活跃+历史总数 - 级别:API - 步骤:`S01` 调用 `GET /api/release/metrics/tenant-installs/?tenant_id=...`;`S02` 校验返回 `active_install_count_24h`;`S03` 校验返回 `historical_install_count` - 预期:两个指标均返回且数值正确 ### TC-FON-000069 租户活跃榜按活跃安装数降序 - 级别:API - 步骤:`S01` 调用 `GET /api/release/metrics/tenant-leaderboard/`;`S02` 校验字段包含 `tenant_code/tenant_name/active/historical`;`S03` 校验按活跃安装数降序 - 预期:排序与字段正确 ### TC-FON-000070 心跳接口拒绝未鉴权请求 - 级别:API - 步骤:`S01` 未带会话访问 heartbeats;`S02` 校验 401/403;`S03` 校验无数据写入 - 预期:防伪造上报有效 ### TC-FON-000071 发布管理接口拒绝非平台管理员 - 级别:API - 步骤:`S01` 租户管理员调用 `POST /api/release/updates/`;`S02` 校验 403;`S03` 校验无新版本记录 - 预期:权限边界正确 ### TC-FON-000072 下载检测接口限流生效 - 级别:API - 步骤:`S01` 同 IP 高频访问 latest;`S02` 校验前 N 次成功;`S03` 校验超阈值 429 - 预期:触发限流,保护服务 --- ## 5. 工程实现指引(给测试开发工程师) 1. **目录建议** - `tests/integration/release/test_us_release.py` - `tests/e2e/release/test_tc_fon_000049_000072.spec.ts`(预留) 2. **命名规范** - 函数名必须带用例ID,例如:`def test_tc_fon_000062_single_published_constraint():` 3. **步骤日志** - 每步打印 step_id,断言失败消息包含 step_id 4. **报告产物** - `reports/release_run_.json` 5. **CI 门禁(阶段性)** - P0 API 用例(000050, 000053~000054, 000059~000069, 000070~000072)必须全过 --- ## 6. 变更规则 - 本模块新增用例从 `TC-FON-000073` 继续递增 - 全项目继续使用单一序列,不得重号 - 历史 ID 仅可 `deprecated`,不得复用