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.
 
 
 

7.2 KiB

W3-T8 独立复审报告

复审结论

  • Verdict:PASS
  • 复审范围:
    • mydreamjob-server/src/main/java/com/mydreamjob/skill/SkillCloudController.java
    • mydreamjob-server/src/test/java/com/mydreamjob/skill/SkillCloudControllerTest.java
    • mydreamjob-server/src/test/java/com/mydreamjob/skill/SkillCloudAuthorizationIntegrationTest.java
    • 对照前次报告 changes/n03-skill-cloud/.superpowers/sdd/reviews/W3-T8.md
  • 复审方式:静态核对实现、测试断言、DTO、JWT/角色链路与测试清理;独立运行指定 8 个测试类。未修改任何实现或测试文件。

原 Important finding 关闭状态

T8-I1:CLOSED

前次问题为三个 OpenAPI 200 示例的 total、计数与数组长度矛盾,且测试未读取示例内容。当前修复已关闭该问题:

  • SkillCloudController.java:56:词云示例改为 total=1 且 items 为 1 项。
  • SkillCloudController.java:103:匹配示例改为 matchScore=50、matchedCount=1、totalCount=2,命中 1 项、缺失 1 项。
  • SkillCloudController.java:150:学习路径示例改为 total=1 且 items 为 1 项。
  • SkillCloudControllerTest.java:267-307:测试读取 /v3/api-docs 中的 responses.200.content.application/json.examples.success.value,使用 Jackson 解析字符串示例或对象示例。
  • SkillCloudControllerTest.java:278-280:词云 data 字段集合精确匹配,total == items.size(),技能项字段集合与 SkillCloudItem 一致。
  • SkillCloudControllerTest.java:282-292:匹配字段集合精确匹配,matchedSkills.size == matchedCount、missingSkills.size == totalCount - matchedCount,并按计数校验 matchScore。
  • SkillCloudControllerTest.java:294-299:学习路径字段集合精确匹配,total == items.size(),路径项字段集合与 SkillLearningPathItem 一致。
  • 对照 DTO:
    • SkillCloudResponse.java:industry、occupation、category、total、items。
    • SkillCloudItem.java:rank、skillId、skillCode、nameZh、nameEn、sourceType、sourceCode、categoryId、categoryName、heat、heatSourceCode、heatElementId、heatProxy。
    • SkillMatchResponse.java:matchScore、matchedCount、totalCount、matchedSkills、missingSkills。
    • SkillLearningPathResponse.java:total、items。
    • SkillLearningPathItem.java:priority、skillId、skillName、categoryId、categoryName、suggestion。

可证伪性:单独篡改 matchScore 会在 SkillCloudControllerTest.java:289-290 失败;篡改 total 会在 :279、:288 或 :297 失败;缩短或扩长数组会因元素数量不一致失败;直接删除示例或改坏 JSON 会在 :302-306 失败。

T8-I2:CLOSED

前次问题为角色测试通过 Mock ProfileService 按 userId 决定结果,未证明真实数据库角色集合。当前修复已关闭该问题:

  • SkillCloudAuthorizationIntegrationTest.java:42-46:使用 @SpringBootTest、MockMvc、真实 integration-test profile 和独立 H2 数据库。
  • :55-74:测试注入真实 UserRepository、真实 JwtTokenProvider;只 Mock 三个技能服务及 Redis,不 Mock ProfileService。
  • :95-108:真实保存 STUDENT、COMPANY、ADMIN、STUDENT+COMPANY、COMPANY+ADMIN 五种角色集合,并在三个端点上分别断言 200、403、403、200、403。
  • SkillCloudController.java:185-198:身份只取认证主体 userId,随后调用真实 profileService.assertStudentRole(userId)。
  • ProfileService.java:50-57:真实读取 UserRepository 并按 User.roles 中是否包含 STUDENT 判断。
  • JwtAuthenticationFilter.java:34-40:JWT 仅用于解析 subject 并建立认证主体;测试 token 即使统一携带 roles=STUDENT claim,生产链路仍按数据库角色拒绝 COMPANY/ADMIN,因此断言真实可证。

可证伪性:若实现改为信任 JWT 的 roles claim,COMPANY/ADMIN 场景会因测试 token 的 STUDENT claim 返回 200 而失败;若改回 Mock 按 userId 放行,数据库角色集合测试在本类中无法满足,且真实 ProfileService 未替换。

额外身份查询参数

  • SkillCloudAuthorizationIntegrationTest.java:112-130:对三个端点同时传入公司用户的 userId 和 studentId,但使用学生 JWT;全部返回 200,并验证 SkillMatchService 与 SkillLearningPathService 收到 JWT 学生 ID,SkillCloudQueryService 只收到筛选参数。
  • SkillCloudController.java:73-83、:120-130、:167-177:三个接口均未声明 userId 或 studentId 请求参数,身份只来自 resolveAuthenticatedStudent()。
  • 结论:额外查询参数不能覆盖 JWT 主体。

端点、参数与安全回归

  • SkillCloudController.java:73、:120、:167:三个 GET 路由保持为 /skills/word-cloud、/skills/match、/skills/learning-path。
  • 三个方法均要求正整数 industryId、occupationId,可选正整数 categoryId;@Validated 与 @Positive 生效。
  • SecurityConfig.java:77-78:GET /skills/** 要求 authenticated,匿名请求无法进入 Controller。
  • SkillCloudControllerTest.java:156-165:三个端点匿名请求均断言 401。
  • SkillCloudControllerTest.java:168-206:覆盖必填参数缺失、非正整数和可选参数非法返回 400。
  • SkillCloudControllerTest.java:110-154:三个 STUDENT 成功路径均返回统一 ApiResponse 和对应 Service DTO 载荷。
  • 未发现 T8 修改导致三个端点、参数校验或 SecurityConfig 行为回归。

测试清理与范围

  • SkillCloudControllerTest.java:50-51 与 SkillCloudAuthorizationIntegrationTest.java:45-46 使用不同的 H2 数据库名,避免类别间共享数据。
  • SkillCloudControllerTest.java:105-108、SkillCloudAuthorizationIntegrationTest.java:89-92 均在每个测试后执行 userRepository.deleteAll()。
  • 指定 8 个测试类完成后全部通过,未观察到外键残留或后续测试污染。
  • 当前工作区中未出现 docs/skill-cloud-api.md,未修改 docs/openapi-rc.json、docs/frontend-integration.md,未实现 T9/T10。

独立测试结果

环境:JDK 17.0.16,Maven 3.9.7。

执行命令:

$env:JAVA_HOME='D:\java\jdk'
& 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' '-Dtest=SkillTaxonomyMigrationTest,SkillCloudSeedDataIntegrationTest,SkillTaxonomyRepositoryTest,SkillCloudQueryServiceTest,SkillMatchServiceTest,SkillLearningPathServiceTest,SkillCloudControllerTest,SkillCloudAuthorizationIntegrationTest' test

结果:

Tests run: 66, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Total time: 53.008 s

分类结果:

  • SkillTaxonomyMigrationTest:2
  • SkillCloudSeedDataIntegrationTest:8
  • SkillTaxonomyRepositoryTest:6
  • SkillCloudQueryServiceTest:8
  • SkillMatchServiceTest:16
  • SkillLearningPathServiceTest:10
  • SkillCloudControllerTest:14
  • SkillCloudAuthorizationIntegrationTest:2

剩余阻断项

无 Critical、Important 阻断项。T8-I1、T8-I2 均已关闭,T8 可进入后续流程。

非阻断备注:200 响应目前通过示例和测试断言锁定字段及计数,未显式绑定具体响应 schema;本轮要求已满足,不阻断 T8。