From 92bd114e71e29cee3463afcfe0b089e8bb26a8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 08:54:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(module=5Ftype):=20=E5=AF=B9=E9=BD=90=20modu?= =?UTF-8?q?le=5Ftype=20=E8=A7=84=E8=8C=83=E5=A4=A7=E5=86=99=E5=B9=B6?= =?UTF-8?q?=E5=8A=A0=E9=98=B2=E5=9B=9E=E5=BD=92=E5=AE=88=E5=8D=AB=EF=BC=88?= =?UTF-8?q?=E9=98=B2=20similarasin/SIMILAR=5FASIN=20=E4=B9=8B=E7=B1=BB?= =?UTF-8?q?=E6=BC=82=E7=A7=BB=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - heartbeat 夹具 moduleType 改规范大写 SIMILAR_ASIN 并加断言锁定 - ModuleTypeAlignmentTest:扫描 src/main——MODULE_TYPE 常量须大写下划线、setModuleType("小写") 禁止(仅允许 legacy collectdata)——守卫写入/常量/夹具三者一致 - 全量扫描结果:生产代码写入均用常量大写,无存量漂移 --- .../config/ModuleTypeAlignmentTest.java | 83 +++++++++++++++++++ .../config/PythonContractFixtureTest.java | 2 + .../python-contract/heartbeat.request.json | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 backend-java/src/test/java/com/nanri/aiimage/config/ModuleTypeAlignmentTest.java diff --git a/backend-java/src/test/java/com/nanri/aiimage/config/ModuleTypeAlignmentTest.java b/backend-java/src/test/java/com/nanri/aiimage/config/ModuleTypeAlignmentTest.java new file mode 100644 index 00000000..3806428f --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/config/ModuleTypeAlignmentTest.java @@ -0,0 +1,83 @@ +package com.nanri.aiimage.config; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * module_type 对齐守卫(task 外防回归)。 + * + * 服务端 module_type 规范为大写下划线(SIMILAR_ASIN / COLLECT_DATA / …),写入 DB 的 + * 值必须与各 Service 的 MODULE_TYPE 常量一致;小写写法(如 similarasin)会导致按模块 + * 查找/心跳/handler 不命中。本测试扫描 src/main:① MODULE_TYPE 等常量取值必须大写; + * ② setModuleType("小写") 不允许(仅允许显式 legacy 兼容值 "collectdata")。 + */ +class ModuleTypeAlignmentTest { + + private static final Set ALLOWED_LEGACY = Set.of("collectdata"); + + private static final Pattern CONST_DECL = Pattern.compile( + "(?:MODULE_TYPE|LEGACY_MODULE_TYPE|_MODULE)\\s*=\\s*\"([A-Za-z0-9_]+)\""); + private static final Pattern WRITE_LITERAL = Pattern.compile( + "setModuleType\\s*\\(\\s*\"([A-Za-z0-9_]+)\""); + private static final Pattern UPPER = Pattern.compile("^[A-Z][A-Z0-9_]*$"); + + private static List javaFiles() throws IOException { + Path root = Path.of(System.getProperty("user.dir"), "src/main/java/com/nanri/aiimage"); + try (Stream s = Files.walk(root)) { + return s.filter(p -> p.toString().endsWith(".java")).toList(); + } + } + + @Test + void moduleTypeConstantsAreUppercase() throws IOException { + List violations = new ArrayList<>(); + for (Path f : javaFiles()) { + List lines = Files.readAllLines(f); + for (int i = 0; i < lines.size(); i++) { + Matcher m = CONST_DECL.matcher(lines.get(i)); + while (m.find()) { + String value = m.group(1); + if (!ALLOWED_LEGACY.contains(value) && !UPPER.matcher(value).matches()) { + violations.add(f + ":" + (i + 1) + " 小写/不规范模块常量: " + value); + } + } + } + } + assertTrue(violations.isEmpty(), "module_type 常量必须规范大写:\n " + String.join("\n ", violations)); + } + + @Test + void noLowercaseModuleTypeWrites() throws IOException { + List violations = new ArrayList<>(); + for (Path f : javaFiles()) { + List lines = Files.readAllLines(f); + for (int i = 0; i < lines.size(); i++) { + Matcher m = WRITE_LITERAL.matcher(lines.get(i)); + while (m.find()) { + String value = m.group(1); + if (!ALLOWED_LEGACY.contains(value) && !UPPER.matcher(value).matches()) { + violations.add(f + ":" + (i + 1) + " setModuleType(\"" + value + "\") 应用常量而非小写字面量"); + } + } + } + } + assertTrue(violations.isEmpty(), "写入 module_type 应用规范大写常量:\n " + String.join("\n ", violations)); + } + + @Test + void similarasinCanonicalValueLocksUpperSnake() { + // 锚定本次发现的隐患点:similarasin 的规范值为大写 SIMILAR_ASIN + assertTrue(UPPER.matcher("SIMILAR_ASIN").matches()); + } +} diff --git a/backend-java/src/test/java/com/nanri/aiimage/config/PythonContractFixtureTest.java b/backend-java/src/test/java/com/nanri/aiimage/config/PythonContractFixtureTest.java index 53d724cc..18e025b8 100644 --- a/backend-java/src/test/java/com/nanri/aiimage/config/PythonContractFixtureTest.java +++ b/backend-java/src/test/java/com/nanri/aiimage/config/PythonContractFixtureTest.java @@ -60,6 +60,8 @@ class PythonContractFixtureTest { JsonNode resp = json("heartbeat.response.json"); assertTrue(req.has("moduleType") && req.has("phase")); assertTrue(resp.has("alive") && resp.has("status")); + assertEquals("SIMILAR_ASIN", req.path("moduleType").asText(), + "夹具 moduleType 须用规范大写(与服务 MODULE_TYPE 常量一致,防小写漂移 bug)"); } @Test diff --git a/backend-java/src/test/resources/python-contract/heartbeat.request.json b/backend-java/src/test/resources/python-contract/heartbeat.request.json index 0ca768a4..3b1535ba 100644 --- a/backend-java/src/test/resources/python-contract/heartbeat.request.json +++ b/backend-java/src/test/resources/python-contract/heartbeat.request.json @@ -1,5 +1,5 @@ { - "moduleType": "similarasin", + "moduleType": "SIMILAR_ASIN", "phase": "search", "current": 3, "total": 10,