Commit dbc345405fcc00b7ad2e1dcf36e665fd8075cd8d
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 | ... | ... |