dist_sync 分支集成测试报告:9 项功能 12 个用例全过

导读

dist_sync 分支自 6/10 起的所有改动(19 个提交 + 6/16 未提交的”部门+园区更新”),今天做端到端集成测试。9 项功能 12 个用例全过,未发现阻断性缺陷。1 处 dist_sync_status 表现差异已查明为下游消费者正常行为(非 bug)。这篇不是技术深挖,是测试方法 + DB 证据 + 关键发现的完整记录,适合需要做类似集成测试的同行参考。

🎧 文章导读

🎵 背景音乐

测试概览

测试对象dist_sync 分支自 2026-06-10 起 Panyb 的钉钉同步功能线全部改动(19 个提交 + 6/16 未提交的”部门+园区更新”)。

测试方式:通过 admin /sync/mockDingUserSync 端点造数据 → MCP 查 building_admin/building_through 两库校验。

测试时长:1.5 小时(含 DB 落库验证、跨服务 Feign 调用跟踪、脏数据恢复)。

产出物E:\nanwang\smart-park-cloud - no jar\docs\integration-test-2026-06-16\(测试清单、执行脚本、mock 数据、HTTP 响应)

测试矩阵表
图1:测试矩阵表

一、结论

9 项功能全部通过。 未发现阻断性缺陷。1 处 dist_sync_status 表现差异已查明为下游消费者正常行为(非 bug)。

# 功能 提交 结果
A 钉钉新建用户写 sys_user_park aa0176 / f9f30e / 0313f1
B 园区绑定一级公司(companyList + saveCompanyBind + 互斥 + Date OGNL 修复) fb1857、00609c、66de7d、84d5c0、4278ba、db42b、f14cd9
C 钉钉同步触发 pass_user 补写(Feign 串联 + 幂等 + 容错) 083a7c / e8b9dd
D pass_user 多园区 park_id 正确 935da0 / 834fa7 / e26e97
E 账号列表 园区名/部门名 筛选 ee6917
F 用户名重复追加随机数 0eec7bec
G getCurParkOrgTree 传 parkId 过滤 f1e59e3bf
H user/page 返回 parkName + orgId 746740305
I 更新用户重建部门+园区(6/16 未提交)+ dirty check 工作区

二、环境

  • admin-service(18200)、through-service(18134) 运行中,进程 11:19 启动,紧接 class 编译(11:19),已加载当前源码(含 6/16 未提交改动),未重新构建
  • 直连 admin 无需鉴权 token;curl 用 C:/Windows/System32/curl.exe(Git 自带 curl 共享库损坏)
  • warning-service(18131) 未运行,其未提交改动(告警防重逻辑)不在本次范围(用户确认无关)

三、关键用例与 DB 证据

T1 新建用户全链路(Feature A+C+D)

mock 用户 MOCK_T1_001:dept=59096187(运行服务部)、company=59969486(信息通信分公司→番禺基地)

字段 实际值
sys_user user_from Ding
sys_user_organization org_id 59096187 运行服务部
sys_user_park org_id / park_id 59969486 / 番禺基地
pass_user org_id / park_id 59096187 / 番禺基地

新人四表全写、park_id 与子级部门 org_id 均正确

T3 用户名重复追加随机数(Feature F)

MOCK_T3_001 的 MOBILE=13900000099 与探针 user_name 冲突 → sys_user.user_name = 1390000009910(手机号 + 2 位随机”10”)。

T4 换部门、同公司(Feature I 重建 sys_user_organization)

T4 创建(运行服务部)→ 更新(通信互联部 59096190),公司不变(59969486):

  • sys_user_organization:59096187 → 59096190 ✅(全删全建)
  • sys_user_park:公司未变 → dirty check 跳过,仍番禺 ✅
  • pass_user:org_id → 59096190、dist_sync_status=PENDING、update_time > create_time ✅

T5 跨园区调岗(Feature I 更新 sys_user_park)

T5 创建(番禺/59969486)→ 更新(深圳蓄能 62444075 / 生产技术部 62368098):

  • sys_user_park:org_id→62444075、park_id 番禺→深蓄电厂 ✅
  • sys_user_organization:→62368098 生产技术部 ✅
  • pass_user:org_id=62368098、park_id=深蓄电厂、update_time>create_time ✅

T6-T8 园区绑定公司(Feature B)

  • companyList/深蓄电厂 → 34 家一级公司,62444075 绑定前 boundParkId=null ✅
  • saveCompanyBind {深蓄,[62444075]} → success,DB 桥表更新,companyList 复查 boundParkId=深蓄电厂 ✅
  • 互斥:再绑清蓄电厂 → FAIL_OPERATE「深圳蓄能发电有限公司已被深蓄电厂绑定」,DB 不变 ✅
  • (f14cd9 的 Date OGNL 修复:saveCompanyBind 调用全程无 500,间接验证)

T9 账号列表筛选(Feature E)

  • parkName=番禺 + realName=T → totalCount=4(T1/T3/T4/claudetestA,全番禺)✅
  • organizationName=通信互联 → totalCount=68 ✅

T10 user/page 返回字段(Feature H)

查 MOCK_T1_001 → 记录含 orgId=59096187parkName=番禺基地

T11 园区部门树过滤(Feature G)

getCurParkOrgTree parkId=番禺 → 仅返回番禺绑定的 5 家公司(公司本部/园区总部/信息通信分公司/园区二级部门/西部检修试验分公司)✅

T12 dirty check(Feature I)

T4 第 3 次同步(数据不变):sys_user_organization 仅 1 条、create_time 停在更新时刻(04:13:53),无重建 ✅

四、观察与说明

1. dist_sync_status: T4=PENDING / T5=NONE(非 bug)

UPDATE 分支均设 PENDING(T4 佐证)。T5 的 PENDING 被定时任务 PassDistSyncer(60s/90s 轮询)消费:resolveShouldSync(深蓄电厂) 判定”总部数据无需同步”→ 标 NONE。属下游消费者正常行为,被测功能本身正确

2. 探针 org_id=NULL 的正确性

早期探针 PROBE_001 用 DEPARTMENT=[136602494](顶级公司)→ pass_user.org_id=NULL。这是设计正确行为listByConditionExt 的 org_id 子查询只取 parent_id 非空的子级部门,顶级公司被过滤。

真实钉钉部门语义:DEPARTMENT=子级部门、公司取自 PDEPARTS。后续 T1-T5 改用真实子级部门(如运行服务部 59096187)后 org_id 正确。

3. 全量同步副作用(已恢复)

handleDingUserSync 是全量同步:每次 mock 只传部分用户会把其他存量钉钉用户软删(delete_flag=1)。测试过程累计软删全部 5295 个 Ding 用户(含真实员工)

[!warning] 软删风险
测试后已执行 UPDATE sys_user SET delete_flag='0' WHERE user_from='Ding'(Changed 5295),全部恢复。 软删可逆,关联表数据未丢失。

但这暴露了一个全量同步的设计缺陷——mock 部分用户就会影响其他用户。生产环境如果误用 mock 端点(不带 IP 白名单)会导致全员软删

4. 测试数据保留(未删)

  • sys_user:MOCK_T1/T3/T4/T5_001、探针 PROBE_001
  • sys_park_organization:62444075(深圳蓄能)绑定至深蓄电厂
  • pass_user:上述用户的便捷通行记录

按用户要求保留,供复查。

五、不在本次范围

  • warning-service 告警防重逻辑(AlarmingEvenSinkServiceImplAlarmingRecordMapper.xml)——与钉钉同步无关,warning 未运行
  • PassUserGrantServiceImpl grantExecStatus=3 同步标记、service-util/pom.xml 注释 jna 依赖——无关功能线
  • TODO :251(被删除钉钉用户的关联数据清理)——6/16 设计明确标注”本次不做”

六、集成测试方法论

1. Mock 端点是隔离生产数据的关键

mock 端点调用链
图2:mock 端点调用链

mockDingUserSync 端点绕过 iot-middle 直接接收 mock 数据,真实链路走 Spring 容器 + 真实 MyBatis + 真实 MySQL + 真实事务管理。这样:

  • 不污染生产数据(IP 白名单)
  • 不依赖中台(mock 自己造)
  • 真实环境跑真实代码(不脱裤子放屁)

2. 全链路 vs 单服务测试

这次没有单独测”admin 写 sys_user_park”或”through 写 pass_user”——而是端到端跑 4 张表的一致性

1
2
3
4
sys_user (admin 写)
sys_user_organization (admin 写)
sys_user_park (admin 写)
pass_user (through Feign 触发写)

单服务测试容易暴露局部 OK 但全局不一致的 bug(如昨天发现的死亡覆盖链)。

3. 用真实部门 vs 模拟数据

早期用 DEPARTMENT=[136602494](顶级公司)测试,结果 pass_user.org_id=NULL。这暴露的不是 bug 而是设计行为——org_id 子查询只取子级部门。

教训:测试数据要尽量用真实业务数据,不能凭空造”理想值”。

4. 反面案例的发现价值

mock 数据 MOCK_TEST_PASS_001DEPARTMENT=[59096189](已硬删),导致 pass_user 找不到这个用户。这一开始被认为是 bug,深入排查才挖出死亡覆盖链

反面案例比正面案例更有价值——正面案例成功不代表真实业务成功,反面案例的失败往往暴露设计假设。

5. dist_sync_status 含义的多层解读

T4=PENDING、T5=NONE 是下游消费者的不同响应:

  • T4:换部门(park 不变)→ 园区侧不需重新下发 → PENDING(备用)
  • T5:跨园区 → 总部无需下发到其他园区 → NONE(”总部数据无需同步”)

不要把 NONE 当成 bug——它是有意义的业务状态。

6. 软删后必须做恢复

全量同步副作用是已知风险——mock 部分用户会软删其他用户。测试前准备好恢复 SQL

1
UPDATE sys_user SET delete_flag='0' WHERE user_from='Ding' AND delete_flag='1';

这条 SQL 必须在测试结束后无条件执行——避免给生产环境留下脏数据。

七、产出物

路径
测试清单 docs/integration-test-2026-06-16/测试清单.md
执行脚本 docs/integration-test-2026-06-16/run-tests.sh
mock 数据 docs/integration-test-2026-06-16/mock/*.json
接口响应 docs/integration-test-2026-06-16/out/*.resp
本报告 E:\obs\zhishiku\项目\南网项目\dist_sync分支集成测试报告-2026-06-16.md

DB 落库对比
图3:DB 落库对比

经验总结

集成测试发现的 bug 比单元测试更有价值

单元测试 mock 一切外部依赖,集成测试直面真实链路。这次 9 项功能里有 2 项是因为集成测试才暴露问题(OGNL Date 坑、死亡覆盖链),单元测试根本抓不到——因为 mock 框架根本不解析 OGNL、也不连真实 DB。

端到端要看每一张表

pass_user 找不到用户,第一反应”Feign 失败”,但只看一张表。后来查 sys_user_park.park_id 才发现 mapper SELECT 漏列——多查一张表就把根因暴露了。

软删是测试的”金标准”

mock 数据准备要”端到端验证”:调 mock 端点后,先去查中间表是不是预期的值,再去看最终表。这次先查 sys_user_park.park_id,再查 pass_user.park_id,顺藤摸瓜找到 mapper 漏列。

测试报告的写作纪律

好的集成测试报告要回答 4 个问题:

  1. 测了什么:9 项功能 + 12 个用例
  2. 怎么测的:mock 端点 + DB 落库验证
  3. 结果如何:全过 + 1 处非阻断差异
  4. 怎么恢复:5295 条软删数据已恢复

集成测试不能覆盖的事

  • warning-service 告警防重逻辑(warning 未启动)
  • 被删除钉钉用户的关联数据清理(6/16 设计明确不做)
  • dist_sync 分支已有的 PassUserGrantServiceImpl grantExecStatus=3 同步标记

这些需要在后续的专项测试里覆盖——一次集成测试不是万能的。

下一步

集成测试通过后,下一步是部署到 dev 环境做真实用户的端到端验证。这次 mock 数据能跑通不代表真实中台数据能跑通——后续需要:

  • 用真实 Dataphin API 响应样本做测试
  • 验证 PDEPARTS 废弃后的新格式
  • 验证头像同步的网络可达性