Commit dbc345405fcc00b7ad2e1dcf36e665fd8075cd8d

Authored by zichun
1 parent f690a242

chore(infra): test.mjs 固定后端测试 JDK 为 Java 17

机器默认 JDK 为 25,Surefire fork 的测试 JVM 沿用默认 JDK 后,Mockito 自带
Byte Buddy(仅支持到 Java 22)无法对 JwtUtil 等具体类做 inline mock,导致
UsrAuthServiceImplTest 在 setUp 整片报 'cannot mock' error。test.mjs 在跑后端
Maven 前自动解析并固定 JAVA_HOME 到 Java 17(JAVA17_HOME / 现有 JAVA_HOME /
macOS java_home -v 17 / 常见 Linux 路径),仅作用于本进程树,不改全局 profile。
Showing 1 changed file with 63 additions and 1 deletions
scripts/test.mjs
... ... @@ -9,7 +9,7 @@
9 9 // 命令字符串来自 docs/04 §零(构建/lint/单测/e2e)——由 skeleton-gen 在 Plan 期填充。
10 10  
11 11 import { spawnSync } from 'node:child_process'
12   -import { existsSync } from 'node:fs'
  12 +import { existsSync, readdirSync } from 'node:fs'
13 13 import { dirname, join } from 'node:path'
14 14 import { fileURLToPath } from 'node:url'
15 15  
... ... @@ -29,6 +29,65 @@ function run(label, command, cwd = PROJECT_ROOT) {
29 29 }
30 30 }
31 31  
  32 +// ── JDK 固定(后端)─────────────────────────────────────────────────
  33 +// 本项目锁定 Java 17(docs/04 §零)。但开发机默认 JDK 可能更新(如 JDK 25),
  34 +// 而 Maven Surefire fork 出的测试 JVM 会沿用默认 JDK:Mockito 自带的 Byte Buddy
  35 +// 不支持过新的 class file 版本(JDK 25 = 69,Byte Buddy 仅到 Java 22 = 66),
  36 +// 导致 `Mockito cannot mock class ...` 在 setUp 阶段整片报 error。
  37 +// 这里在跑后端 Maven 前,把本进程(及其 spawnSync 子进程)的 JAVA_HOME 固定到
  38 +// 一个 Java 17 运行时;不改写全局/用户 profile,仅影响本次测试闸进程树。
  39 +function javaMajor(javaHome) {
  40 + if (!javaHome) return null
  41 + const bin = join(javaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java')
  42 + if (!existsSync(bin)) return null
  43 + const res = spawnSync(bin, ['-version'], { encoding: 'utf8' })
  44 + const out = `${res.stdout || ''}${res.stderr || ''}`
  45 + const m = out.match(/version "(\d+)/) // "17.0.19" → 17;"25.0.2" → 25
  46 + return m ? Number(m[1]) : null
  47 +}
  48 +
  49 +function resolveJava17Home() {
  50 + // 1) 显式覆盖:JAVA17_HOME
  51 + if (javaMajor(process.env.JAVA17_HOME) === 17) return process.env.JAVA17_HOME
  52 + // 2) 现有 JAVA_HOME 恰好已是 17
  53 + if (javaMajor(process.env.JAVA_HOME) === 17) return process.env.JAVA_HOME
  54 + // 3) macOS:/usr/libexec/java_home -v 17
  55 + if (process.platform === 'darwin') {
  56 + const r = spawnSync('/usr/libexec/java_home', ['-v', '17'], { encoding: 'utf8' })
  57 + if (r.status === 0) { const h = (r.stdout || '').trim(); if (javaMajor(h) === 17) return h }
  58 + }
  59 + // 4) 常见 Linux 安装位置(best-effort)
  60 + for (const base of ['/usr/lib/jvm', '/opt/java', '/opt']) {
  61 + if (!existsSync(base)) continue
  62 + try {
  63 + for (const name of readdirSync(base)) {
  64 + if (!/17/.test(name)) continue
  65 + const h = join(base, name)
  66 + if (javaMajor(h) === 17) return h
  67 + }
  68 + } catch { /* 忽略不可读目录 */ }
  69 + }
  70 + return null
  71 +}
  72 +
  73 +// 仅在默认 JDK 不是 17 时才介入;找不到 17 则告警并沿用默认(不擅自失败)。
  74 +function ensureJava17() {
  75 + if (javaMajor(process.env.JAVA_HOME) === 17) {
  76 + console.log(`[test.mjs] JAVA_HOME 已是 Java 17:${process.env.JAVA_HOME}`)
  77 + return
  78 + }
  79 + const home = resolveJava17Home()
  80 + if (!home) {
  81 + console.warn('[test.mjs] WARN: 未找到 Java 17(JAVA17_HOME / JAVA_HOME / java_home -v 17 / 常见路径均未命中);'
  82 + + '将以默认 JDK 跑后端测试。若默认 JDK 过新,Mockito/Byte Buddy 可能在 mock 时整片报 error。')
  83 + return
  84 + }
  85 + process.env.JAVA_HOME = home
  86 + const sep = process.platform === 'win32' ? ';' : ':'
  87 + process.env.PATH = `${join(home, 'bin')}${sep}${process.env.PATH || ''}`
  88 + console.log(`[test.mjs] 固定 JAVA_HOME=Java 17 → ${home}`)
  89 +}
  90 +
32 91 // Stack detection (runtime, mode-agnostic)
33 92 const hasBackend = existsSync(join(PROJECT_ROOT, 'backend'))
34 93 const hasFrontend = existsSync(join(PROJECT_ROOT, 'frontend'))
... ... @@ -40,6 +99,9 @@ if (!hasBackend && !hasFrontend) {
40 99 const backendDir = join(PROJECT_ROOT, 'backend')
41 100 const frontendDir = join(PROJECT_ROOT, 'frontend')
42 101  
  102 +// 后端存在时,先把测试用 JDK 固定到 Java 17(见 ensureJava17 注释)。
  103 +if (hasBackend) ensureJava17()
  104 +
43 105 console.log('[test.mjs] 1/5 setup test db')
44 106 run('setup-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`)
45 107  
... ...