From dbc345405fcc00b7ad2e1dcf36e665fd8075cd8d Mon Sep 17 00:00:00 2001 From: zichun Date: Mon, 1 Jun 2026 15:52:48 +0800 Subject: [PATCH] chore(infra): test.mjs 固定后端测试 JDK 为 Java 17 --- scripts/test.mjs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/scripts/test.mjs b/scripts/test.mjs index 0ad78da..c609ace 100644 --- a/scripts/test.mjs +++ b/scripts/test.mjs @@ -9,7 +9,7 @@ // 命令字符串来自 docs/04 §零(构建/lint/单测/e2e)——由 skeleton-gen 在 Plan 期填充。 import { spawnSync } from 'node:child_process' -import { existsSync } from 'node:fs' +import { existsSync, readdirSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' @@ -29,6 +29,65 @@ function run(label, command, cwd = PROJECT_ROOT) { } } +// ── JDK 固定(后端)───────────────────────────────────────────────── +// 本项目锁定 Java 17(docs/04 §零)。但开发机默认 JDK 可能更新(如 JDK 25), +// 而 Maven Surefire fork 出的测试 JVM 会沿用默认 JDK:Mockito 自带的 Byte Buddy +// 不支持过新的 class file 版本(JDK 25 = 69,Byte Buddy 仅到 Java 22 = 66), +// 导致 `Mockito cannot mock class ...` 在 setUp 阶段整片报 error。 +// 这里在跑后端 Maven 前,把本进程(及其 spawnSync 子进程)的 JAVA_HOME 固定到 +// 一个 Java 17 运行时;不改写全局/用户 profile,仅影响本次测试闸进程树。 +function javaMajor(javaHome) { + if (!javaHome) return null + const bin = join(javaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java') + if (!existsSync(bin)) return null + const res = spawnSync(bin, ['-version'], { encoding: 'utf8' }) + const out = `${res.stdout || ''}${res.stderr || ''}` + const m = out.match(/version "(\d+)/) // "17.0.19" → 17;"25.0.2" → 25 + return m ? Number(m[1]) : null +} + +function resolveJava17Home() { + // 1) 显式覆盖:JAVA17_HOME + if (javaMajor(process.env.JAVA17_HOME) === 17) return process.env.JAVA17_HOME + // 2) 现有 JAVA_HOME 恰好已是 17 + if (javaMajor(process.env.JAVA_HOME) === 17) return process.env.JAVA_HOME + // 3) macOS:/usr/libexec/java_home -v 17 + if (process.platform === 'darwin') { + const r = spawnSync('/usr/libexec/java_home', ['-v', '17'], { encoding: 'utf8' }) + if (r.status === 0) { const h = (r.stdout || '').trim(); if (javaMajor(h) === 17) return h } + } + // 4) 常见 Linux 安装位置(best-effort) + for (const base of ['/usr/lib/jvm', '/opt/java', '/opt']) { + if (!existsSync(base)) continue + try { + for (const name of readdirSync(base)) { + if (!/17/.test(name)) continue + const h = join(base, name) + if (javaMajor(h) === 17) return h + } + } catch { /* 忽略不可读目录 */ } + } + return null +} + +// 仅在默认 JDK 不是 17 时才介入;找不到 17 则告警并沿用默认(不擅自失败)。 +function ensureJava17() { + if (javaMajor(process.env.JAVA_HOME) === 17) { + console.log(`[test.mjs] JAVA_HOME 已是 Java 17:${process.env.JAVA_HOME}`) + return + } + const home = resolveJava17Home() + if (!home) { + console.warn('[test.mjs] WARN: 未找到 Java 17(JAVA17_HOME / JAVA_HOME / java_home -v 17 / 常见路径均未命中);' + + '将以默认 JDK 跑后端测试。若默认 JDK 过新,Mockito/Byte Buddy 可能在 mock 时整片报 error。') + return + } + process.env.JAVA_HOME = home + const sep = process.platform === 'win32' ? ';' : ':' + process.env.PATH = `${join(home, 'bin')}${sep}${process.env.PATH || ''}` + console.log(`[test.mjs] 固定 JAVA_HOME=Java 17 → ${home}`) +} + // Stack detection (runtime, mode-agnostic) const hasBackend = existsSync(join(PROJECT_ROOT, 'backend')) const hasFrontend = existsSync(join(PROJECT_ROOT, 'frontend')) @@ -40,6 +99,9 @@ if (!hasBackend && !hasFrontend) { const backendDir = join(PROJECT_ROOT, 'backend') const frontendDir = join(PROJECT_ROOT, 'frontend') +// 后端存在时,先把测试用 JDK 固定到 Java 17(见 ensureJava17 注释)。 +if (hasBackend) ensureJava17() + console.log('[test.mjs] 1/5 setup test db') run('setup-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) -- libgit2 0.22.2