fix(module_type): 对齐 module_type 规范大写并加防回归守卫(防 similarasin/SIMILAR_ASIN 之类漂移)

- heartbeat 夹具 moduleType 改规范大写 SIMILAR_ASIN 并加断言锁定
- ModuleTypeAlignmentTest:扫描 src/main——MODULE_TYPE 常量须大写下划线、setModuleType("小写") 禁止(仅允许 legacy collectdata)——守卫写入/常量/夹具三者一致
- 全量扫描结果:生产代码写入均用常量大写,无存量漂移
This commit is contained in:
2026-09-05 08:54:06 +08:00
parent e69d82e7b1
commit 92bd114e71
3 changed files with 86 additions and 1 deletions
@@ -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<String> 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<Path> javaFiles() throws IOException {
Path root = Path.of(System.getProperty("user.dir"), "src/main/java/com/nanri/aiimage");
try (Stream<Path> s = Files.walk(root)) {
return s.filter(p -> p.toString().endsWith(".java")).toList();
}
}
@Test
void moduleTypeConstantsAreUppercase() throws IOException {
List<String> violations = new ArrayList<>();
for (Path f : javaFiles()) {
List<String> 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<String> violations = new ArrayList<>();
for (Path f : javaFiles()) {
List<String> 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());
}
}
@@ -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
@@ -1,5 +1,5 @@
{
"moduleType": "similarasin",
"moduleType": "SIMILAR_ASIN",
"phase": "search",
"current": 3,
"total": 10,