Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录
切换导航
U
ubains-module-test
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
1
议题
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
郑晓兵
ubains-module-test
Commits
b227d759
提交
b227d759
authored
9月 08, 2026
作者:
陈泽健
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix(execution): 运行中 total_cases 保持计划总数(会话53副作用,单点删除覆盖行恢复计划总数口径,437 测试全绿,5.60 部署并实机验证)
Co-Authored-By:
Claude
<
noreply@anthropic.com
>
上级
f363abdd
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
241 行增加
和
8 行删除
+241
-8
_问题处理与计划执行_执行进度总数显示修复.md
Docs/PRD/需求文档/执行中心/_问题处理与计划执行_执行进度总数显示修复.md
+109
-0
HANDOFF_UI自动化.md
HANDOFF_UI自动化.md
+32
-4
execution_service.py
backend/app/services/execution_service.py
+5
-4
diag_544_sched_case_count.py
backend/scripts/diag_544_sched_case_count.py
+95
-0
没有找到文件。
Docs/PRD/需求文档/执行中心/_问题处理与计划执行_执行进度总数显示修复.md
0 → 100644
浏览文件 @
b227d759
# 问题处理与计划执行 — 执行进度总用例数显示修复
> **文档类型**:问题处理单 + 计划执行
> **所属模块**:执行中心(UI 自动化执行)
> **优先级**:P1(显示口径错误,不丢数据但误导用户)
> **创建日期**:2026-09-08
> **来源**:用户反馈「5.44 定时任务用例只有 60 多个,应该有 300 多条」
---
## 1. 问题描述
用户查看 5.44 定时任务执行时,发现「用例数」只有 60 多个,而定时任务选中模块下实际有 340+ 条 UI 用例。
### 1.1 现场核实(2026-09-08,5.44 实查)
| 核查项 | 结果 |
|--------|------|
|
`test_cases`
总数 | 409(= 342 UI + 67 安全) |
| 定时任务「UI自动化回归」选中模块 | 28 个 |
| 按调度逻辑(
`status=active`
+
`case_type=ui`
)实际收集 |
**342 条**
✅ |
| 当轮执行
`case_results`
(exec_94ccad06,09:35 触发) | 252 pending + 71 passed + 19 failed =
**342**
✅ |
| 该执行
`total_cases`
字段(运行中) |
**89**
(= 71 + 19 + 0)❌ |
| 上一轮完整执行 total_cases | 341(263 + 79,≈342,差 1 为单条结果写入失败) |
**结论**
:用例数据无任何丢失,342 条全部正常排入执行。「60 多个」是
**运行中 `total_cases` 字段被实时覆盖为「已完成数」**
导致的显示口径错误。
## 2. 根因分析
### 2.1 直接根因
`backend/app/services/execution_service.py`
`_persist_case_result()`
实时回调中(会话 53 MissingGreenlet 修复引入):
```
python
execution
.
passed
=
passed
execution
.
failed
=
failed
execution
.
skipped
=
skipped
# 显式覆盖 total_cases(passed+failed+skipped),计算通过率不再依赖
# calculate_pass_rate() 读 self.total_cases 列(commit 后 ORM 实例已过期,
# 读列会触发同步 lazy load → MissingGreenlet)。
execution
.
total_cases
=
passed
+
failed
+
skipped
# ← 问题行
execution
.
pass_rate
=
round
(
passed
/
(
passed
+
failed
+
skipped
)
*
100
,
2
)
...
```
每个用例完成后把
`total_cases`
覆盖为「当时已完成数」,导致:
| 展示位置 | 现状错误表现 | 正确表现 |
|----------|-------------|---------|
| 执行中心「总用例数」统计卡 | 运行中从 0 涨到 342(跑完才是总数) | 全程恒为 342(计划总数) |
| 执行记录列表「用例数」列 | 运行中显示已完成数(用户误以为用例丢了) | 恒为计划总数 |
| 执行进度条
`progressPercent`
|
**恒为 100%**
(分子 = 分母,进度语义完全失效) | 随执行从 0% 涨到 100% |
### 2.2 为什么当时会加这行
会话 53 修 MySQL
`MissingGreenlet`
:失败回滚后 ORM 实例过期,
`calculate_pass_rate()`
读
`self.total_cases`
列触发同步 lazy load → 500。当时的修法是显式赋值
`total_cases`
让通过率不依赖读列。
### 2.3 修复依据(为什么可以安全删除)
-
**通过率本就不依赖 `total_cases` 列**
:
`_persist_case_result`
中的
`pass_rate`
已用本地变量
`passed/(passed+failed+skipped)`
计算,覆盖
`total_cases`
对它无意义。
-
**计划总数在创建时已落库**
:
`create_execution()`
中
`total_cases=len(case_ids)`
(571 行),删除覆盖后该值全程保持。
-
**过期风险已重新评估**
:
`database.py`
配置
`expire_on_commit=False`
,commit 后属性不过期;
`MissingGreenlet`
仅发生在「回滚后读列」场景。执行收尾块(927-930 行)读
`execution.start_time/end_time`
的既有行为本次
**不动**
,风险面无扩大。
-
**收尾 `calculate_pass_rate()` 口径自然修正**
:正常完成时
`total_cases(342) = passed+failed+skipped`
,通过率不变;中途取消时通过率分母为计划总数(语义更合理——pending 的用例计入未通过基数,与执行详情页 pending 展示一致)。
## 3. 修复方案
### 3.1 代码改动(单文件单点)
**文件**
:
`backend/app/services/execution_service.py`
**改动**
:删除
`_persist_case_result`
中
`execution.total_cases = passed + failed + skipped`
覆盖行,注释改为说明「total_cases 保持创建时的计划总数,运行中不覆盖」。
### 3.2 不改的部分
| 范围 | 理由 |
|------|------|
|
`create_execution()`
|
`total_cases=len(case_ids)`
已是正确口径 |
| 执行收尾块(924-931 行) | 读列行为维持现状,避免扩大改动面 |
| 安全测试路径(1318 行
`total_cases = len(case_results)`
) | 安全执行为一次性批量写库,无运行中展示诉求 |
| 前端 | 展示字段就是后端
`total_cases`
,后端口径修正后自动恢复 |
| 看门狗 / 报告生成 | 不读取运行中
`total_cases`
做判定 |
## 4. 计划执行步骤
| # | 步骤 | 状态 |
|---|------|------|
| 1 | 输出本文档 | ✅ |
| 2 | 删除
`execution_service.py`
中
`total_cases`
覆盖行 + 更新注释 | ✅ |
| 3 | 后端全量
`pytest tests/`
回归(重点:执行相关测试) | ✅ 437 passed |
| 4 | 部署 5.60:MD5 部署前核对 → scp 单文件 →
`docker restart`
→ 健康检查 | ✅(15s healthy,
`/health`
200) |
| 5 |
**不部署**
5.44 / 5.202(用户明确本次只更新 5.60) | — |
## 5. 验收标准
1.
后端全量测试通过,无新增失败。✅ 437 passed
2.
5.60 部署后容器 healthy、
`/health`
200。✅
3.
下一次执行运行中:
`total_cases`
恒为计划总数。✅
**实机验证**
:exec_a92b33d4(19 用例)运行中查库
`total_cases=19`
、
`case_results=3 failed + 16 pending`
(修复前此处会显示 3);进度条恢复 0%→100% 语义。
4.
5.44 上现网定时任务不受影响(未部署,待后续统一部署时随会话 53 改动一起上)。
### ⚠️ 部署过程备注
重启时 5.60 有一笔 10:39 手动触发的执行(exec_ff03b772)正在运行,被重启中断;FastAPI shutdown 钩子正常收尾(日志「执行完成 通过=0 失败=2」),未留僵尸 running 记录。10:44 起新执行正常。
## 6. 遗留与关联
-
会话 53 待办「5.44 看板用例断言文案修正」不受本修复影响,仍待处理。
-
本修复与未提交的会话 53 改动同在
`execution_service.py`
,git 提交时需一并说明(用户未要求本次提交,遵循「未明确要求不自动 commit」约束)。
---
*本文档由 Claude Code 于 2026-09-08 创建(问题处理与修复执行同步完成)。*
HANDOFF_UI自动化.md
浏览文件 @
b227d759
...
...
@@ -2,12 +2,40 @@
> **生成时间**: 2026-09-08
> **当前分支**: `platform-auto-test`
> **最近提交**:
`b80abae3` feat(recorder): 真录制器与定位质量提升 Phase 1-5(引擎/路由/E2E/前端)(会话 53 改动未提交,工作区待提交
)
> **状态**: 🟢 **会话5
3 完成(2026-09-08):5.44 登录/落库双 P0 攻坚闭环(do_login→_navigate_to_home 主动落首页 + error_message 60000B 截断 + MissingGreenlet 绕过),5 条核心用例 3轮回归从全失败→4/5 通过,仅剩看板断言文案 1 条('.block' 实际文本「新建会议」≠ 预期「今日会议」);同步部署 5.60(7 后端文件 + 前端 dist 95 文件,健康检查全绿,RECORDER_ENABLED 生效
)**(历史会话见下章节)
> **最近提交**:
本会话(54)`fix(execution): 运行中 total_cases 保持计划总数`(提交推送后回填 hash
)
> **状态**: 🟢 **会话5
4 完成(2026-09-08):执行进度「总用例数」显示修复——运行中 total_cases 被覆盖为已完成数(会话53 MissingGreenlet 修复副作用)导致 5.44 定时任务执行中显示 60 多而非 342、前端进度条恒 100%;单点删除覆盖行恢复计划总数口径,437 测试全绿,已部署 5.60 并实机验证(运行中 total_cases 恒为 19
)**(历史会话见下章节)
---
## 📊 当前状态(会话 53,2026-09-08 · 5.44 登录/落库 P0 攻坚闭环 + 5.60 部署)
## 📊 当前状态(会话 54,2026-09-08 · 执行进度总数显示修复 + 5.60 部署)
**背景**
:用户反馈「5.44 定时任务用例只有 60 多个,应该有 300 多条」。5.44 实查核实:用例数据无丢失(409 = 342 UI + 67 安全;定时任务 28 模块实际收集 342 条,当轮 case_results 252 pending + 71 passed + 19 failed = 342 全部排入)。「60 多」是
**运行中 `total_cases` 字段被实时覆盖为「已完成数」**
的显示口径错误——会话 53 MissingGreenlet 修复的副作用。
### ✅ 修复内容
-
**根因**
:
`execution_service.py`
`_persist_case_result()`
中
`execution.total_cases = passed + failed + skipped`
,每个用例完成后把总用例数覆盖为已完成数 → 执行中心「总用例数」运行中从 0 涨到 342、进度条
`(passed+failed+skipped)/total_cases`
恒 100%。
-
**修复**
:单点删除该覆盖行,
`total_cases`
保持
`create_execution()`
写入的计划总数
`len(case_ids)`
。通过率分子分母均用本地变量,不受影响;
`expire_on_commit=False`
已确认,收尾
`calculate_pass_rate()`
读列安全(MissingGreenlet 仅回滚后触发,收尾路径未动)。
-
**文档**
:
`Docs/PRD/需求文档/执行中心/_问题处理与计划执行_执行进度总数显示修复.md`
(问题核实数据 / 根因链 / 方案依据 / 执行步骤 / 验收标准 / 部署备注)。
-
**测试**
:后端全量
`pytest tests/`
**437 passed**
(70s,无回归)。
### ✅ 5.60 部署与实机验证
-
部署前拉取远程文件 diff:与本地仅差本次一处(4行→5行),无其他窗口 WIP;远程备份
`execution_service.py.bak_20260908`
。
-
上传(LF 行尾)→ 容器 py_compile OK → restart 15s healthy →
`/health`
200。
-
**实机验证**
:新代码下第一笔执行
`exec_a92b33d4`
(19 用例)运行中查库
`total_cases=19`
恒定(case_results = 3 failed + 16 pending;修复前此处显示 3)——总用例数不再从 0 往上涨,进度条恢复 0%→100% 语义。
-
**验证脚本**
:
`backend/scripts/verify_560_total_cases_fix.py`
(传执行 ID 复查;被 .gitignore 忽略未入库)。诊断脚本
`diag_544_sched_case_count.py`
已入库。
### ⚠️ 部署过程备注(如实记录)
-
重启时 5.60 有一笔 10:39 手动触发的执行(exec_ff03b772)正在运行,被重启中断;FastAPI shutdown 钩子正常收尾(日志「执行完成 通过=0 失败=2」),未留僵尸 running 记录,10:44 起新执行正常。
### ⚠️ 待办
-
**5.44 / 5.202 部署本修复**
(本次按用户要求仅部署 5.60;5.44 运行中显示口径仍旧,跑完终值正确;需与下一次统一部署一起上)
-
**5.44 看板用例收尾**
(会话 53 遗留):case_6699d6dd 步骤 3 断言修正为「新建会议」→ 5/5 回归确认
-
**5.202 部署**
会话 53 改动(遗留)
-
**5.60 录制器真实环境验收**
(会话 52 P2)
-
清理诊断脚本(diag_544_
*
.py、dump_544_cases.py、dump9_cases.json、tmp_wait_deploy_544.py 等)
---
## 📊 历史状态(会话 53,2026-09-08 · 5.44 登录/落库 P0 攻坚闭环 + 5.60 部署)
**背景**
:承接会话 51 遗留 P0(5.44 全量套件 ~100% 失败,
`do_login`
后落不到首页,卡
`.nav_right_list.el-dropdown-selfdefine`
等待),本次在 5.44 容器内完成根因定位、代码修复、用例数据修复与回归,并将全部修复同步部署到 5.60。
...
...
@@ -256,4 +284,4 @@
---
*本文档由 Claude Code 于 2026-09-08 更新(会话 5
3:5.44 登录/落库双 P0 闭环(do_login 后 _navigate_to_home 主动落首页 + error_message 60000B/log-error 20000 截断 + 滚动计数绕过 MissingGreenlet),fix_544_login_cases.py 重写 5 用例+删 4 垃圾用例(409 总数),3 轮回归 4/5(看板 .block 文本实测「新建会议」);5.60 部署 7 后端文件 + dist 95 文件全绿(RECORDER_ENABLED 生效、PLATFORM_BASE_URL 保留)。历史:
会话 52 真录制器 Phase 5(`b80abae3`);会话 51 截图瘦身部署 5.44(`228c732a`+`45a247b8`);会话 50 会议巡检 navigate 直达 3/3 通过 `1924d77f`+`d2660651`;会话 49 视讯设备直达升级 11/11 `35a58b2e`;会话 48 看门狗修复 + 缺口补齐 8/8 `720bf764`)。*
*本文档由 Claude Code 于 2026-09-08 更新(会话 5
4:执行进度「总用例数」显示修复——运行中 total_cases 被覆盖为已完成数的会话 53 副作用,单点删除恢复计划总数口径(437 测试全绿),已部署 5.60 并实机验证运行中 total_cases 恒为 19;问题处理文档入库 Docs/PRD/需求文档/执行中心/。历史:会话 53 5.44 登录/落库双 P0 闭环(do_login 后 _navigate_to_home 主动落首页 + error_message 60000B/log-error 20000 截断 + 滚动计数绕过 MissingGreenlet),fix_544_login_cases.py 重写 5 用例+删 4 垃圾用例(409 总数),3 轮回归 4/5(看板 .block 文本实测「新建会议」);5.60 部署 7 后端文件 + dist 95 文件全绿(RECORDER_ENABLED 生效、PLATFORM_BASE_URL 保留);
会话 52 真录制器 Phase 5(`b80abae3`);会话 51 截图瘦身部署 5.44(`228c732a`+`45a247b8`);会话 50 会议巡检 navigate 直达 3/3 通过 `1924d77f`+`d2660651`;会话 49 视讯设备直达升级 11/11 `35a58b2e`;会话 48 看门狗修复 + 缺口补齐 8/8 `720bf764`)。*
backend/app/services/execution_service.py
浏览文件 @
b227d759
...
...
@@ -729,10 +729,11 @@ class ExecutionService:
execution
.
passed
=
passed
execution
.
failed
=
failed
execution
.
skipped
=
skipped
# 显式覆盖 total_cases(passed+failed+skipped),计算通过率不再依赖
# calculate_pass_rate() 读 self.total_cases 列(commit 后 ORM 实例已过期,
# 读列会触发同步 lazy load → MissingGreenlet)。
execution
.
total_cases
=
passed
+
failed
+
skipped
# total_cases 不在此覆盖:保持 create_execution 写入的计划总数,
# 运行中「总用例数」恒为计划值、进度条 (passed+failed+skipped)/
# total_cases 才有进度语义(曾覆盖为已完成数,导致定时任务执行中
# 显示 60 多而非 342、进度条恒 100%——见执行中心问题处理文档)。
# 通过率分子分母均用本地变量,不依赖 total_cases 列。
execution
.
pass_rate
=
round
(
passed
/
(
passed
+
failed
+
skipped
)
*
100
,
2
)
if
(
passed
+
failed
+
skipped
)
else
0.0
await
self
.
db
.
commit
()
# 立即提交,前端轮询可见
...
...
backend/scripts/diag_544_sched_case_count.py
0 → 100644
浏览文件 @
b227d759
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
诊断:5.44 定时任务用例数为何只有 60 多(预期 300+)
检查项:
1. scheduled_tasks 配置(module_ids / case_type / enabled)
2. test_cases 总数 / 按 status 分布 / 按 case_type 分布
3. 各模块下的 active ui 用例数
4. 任务选中模块集合内的 active ui 用例总数(调度实际会收到的数量)
5. 最近几次 scheduled 执行的 total_cases
"""
import
sys
sys
.
stdout
.
reconfigure
(
encoding
=
"utf-8"
)
import
json
import
paramiko
HOST
,
USER
,
PWD
=
"192.168.5.44"
,
"root"
,
"Ubains@123"
MYSQL
=
"plat-auto-test-mysql"
DB
=
"plat_auto_test"
cli
=
paramiko
.
SSHClient
()
cli
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
cli
.
connect
(
HOST
,
username
=
USER
,
password
=
PWD
,
timeout
=
20
)
def
run
(
cmd
,
timeout
=
60
):
_
,
stdout
,
stderr
=
cli
.
exec_command
(
cmd
,
timeout
=
timeout
)
return
(
stdout
.
read
()
.
decode
(
"utf-8"
,
errors
=
"replace"
)
.
strip
(),
stderr
.
read
()
.
decode
(
"utf-8"
,
errors
=
"replace"
)
.
strip
())
def
sql
(
q
,
label
):
out
,
err
=
run
(
f
"docker exec {MYSQL} mysql -uroot -p'Ubains@2025' {DB} -e
\"
{q}
\"
2>/dev/null"
)
print
(
f
"
\n
----- {label} -----"
)
print
(
out
if
out
else
f
"(空) err: {err[:300]}"
)
return
out
# 1. 定时任务配置
tasks_out
=
sql
(
"SELECT id, name, enabled, case_type, module_ids, schedule_type, last_run_at, next_run_at "
"FROM scheduled_tasks;"
,
"1. 定时任务配置"
)
# 2. 用例总数与分布
sql
(
"SELECT COUNT(*) AS total FROM test_cases;"
,
"2a. 用例总数"
)
sql
(
"SELECT status, COUNT(*) FROM test_cases GROUP BY status;"
,
"2b. 按 status 分布"
)
sql
(
"SELECT case_type, COUNT(*) FROM test_cases GROUP BY case_type;"
,
"2c. 按 case_type 分布"
)
# 3. 各模块 active ui 用例数
sql
(
"SELECT m.id, m.name, COUNT(c.id) AS active_ui "
"FROM modules m LEFT JOIN test_cases c "
"ON c.module_id=m.id AND c.status='active' AND c.case_type='ui' "
"GROUP BY m.id, m.name ORDER BY active_ui DESC;"
,
"3. 各模块 active+ui 用例数"
)
# 4. 计算每个任务选中模块内的实际用例数(与调度逻辑一致)
if
tasks_out
:
lines
=
tasks_out
.
splitlines
()
header
=
lines
[
0
]
.
split
(
"
\t
"
)
idx
=
{
h
:
i
for
i
,
h
in
enumerate
(
header
)}
for
row
in
lines
[
1
:]:
cols
=
row
.
split
(
"
\t
"
)
if
len
(
cols
)
<
len
(
header
):
continue
name
=
cols
[
idx
[
"name"
]]
raw
=
cols
[
idx
[
"module_ids"
]]
try
:
mod_ids
=
json
.
loads
(
raw
.
replace
(
"'"
,
'"'
))
if
raw
else
[]
except
Exception
:
mod_ids
=
[
m
.
strip
(
"
\"
'[] "
)
for
m
in
raw
.
split
(
","
)
if
m
.
strip
(
"
\"
'[] "
)]
id_list
=
","
.
join
(
f
"'{m}'"
for
m
in
mod_ids
if
m
)
print
(
f
"
\n
----- 任务「{name}」module_ids={mod_ids} ({len(mod_ids)} 个模块) -----"
)
if
not
id_list
:
print
(
"(未选中任何模块)"
)
continue
sql
(
f
"SELECT COUNT(*) AS will_run FROM test_cases "
f
"WHERE module_id IN ({id_list}) AND status='active' AND case_type='ui';"
,
f
"4. 任务「{name}」调度实际收到的用例数"
,
)
# 5. 最近 scheduled 执行的规模
sql
(
"SELECT id, name, trigger_type, status, total_cases, passed, failed, created_at "
"FROM executions WHERE trigger_type='scheduled' "
"ORDER BY created_at DESC LIMIT 6;"
,
"5. 最近 scheduled 执行"
)
cli
.
close
()
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论