feat: 删除pom
Some checks failed
Redis序列化结构检查 / redis-schema-check (push) Has been cancelled

This commit is contained in:
2026-07-13 15:54:38 +08:00
parent 436460cfdb
commit 30e530c0bf
39 changed files with 164 additions and 159 deletions

View File

@@ -0,0 +1,92 @@
package com.codechecker.redis;
import com.codechecker.redis.detector.RedisWritePointDetector;
import com.codechecker.redis.detector.WritePoint;
import com.codechecker.redis.diff.ChangeType;
import com.codechecker.redis.diff.SchemaChange;
import com.codechecker.redis.diff.SchemaDiffer;
import com.codechecker.redis.schema.JavaSchemaExtractor;
import com.codechecker.redis.schema.SourceIndex;
import com.codechecker.redis.schema.TypeSchema;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* 端到端组件级验证:租户缓存由 TenantVO 变为 CacheEnvelope{vo, expiresAtMs} 的结构变更。
*/
class TenantScenarioTest {
private static final Set<String> PATTERNS = new HashSet<>();
static {
PATTERNS.add("W01");
PATTERNS.add("W02");
PATTERNS.add("W03");
}
@Test
void detectsTenantEnvelopeWrapping() {
String tenantVo = TestSupport.fixture("fixtures/tenant/TenantVO.txt");
String tenantLink = TestSupport.fixture("fixtures/tenant/TenantLinkModel.txt");
String helperOld = TestSupport.fixture("fixtures/tenant/HelperOld.txt");
String helperNew = TestSupport.fixture("fixtures/tenant/HelperNew.txt");
SourceIndex oldIndex = new SourceIndex();
oldIndex.addSource(tenantVo);
oldIndex.addSource(tenantLink);
oldIndex.addSource(helperOld);
SourceIndex newIndex = new SourceIndex();
newIndex.addSource(tenantVo);
newIndex.addSource(tenantLink);
newIndex.addSource(helperNew);
WritePoint oldWp = single(new RedisWritePointDetector(oldIndex, PATTERNS)
.detect("Helper.java", helperOld));
WritePoint newWp = single(new RedisWritePointDetector(newIndex, PATTERNS)
.detect("Helper.java", helperNew));
// key 推断
assertEquals("tenant:db:content:*", oldWp.getResolvedKeyPattern());
assertEquals("tenant:db:content:*", newWp.getResolvedKeyPattern());
// 写入点配对签名一致
assertEquals(oldWp.signature(), newWp.signature());
// value 类型推断
assertEquals("jnpf.model.TenantVO", oldWp.getResolvedValueType());
assertNotNull(newWp.getResolvedValueType());
assertTrue(newWp.getResolvedValueType().endsWith("CacheEnvelope"));
JavaSchemaExtractor oldEx = new JavaSchemaExtractor(oldIndex, 8);
JavaSchemaExtractor newEx = new JavaSchemaExtractor(newIndex, 8);
TypeSchema oldSchema = oldEx.extract(oldWp.getResolvedValueType(), oldWp.isRootArray());
TypeSchema newSchema = newEx.extract(newWp.getResolvedValueType(), newWp.isRootArray());
// 旧结构包含顶层 dbName、linkList[].id
assertTrue(oldSchema.getFields().containsKey("dbName"));
assertTrue(oldSchema.getFields().containsKey("linkList[].id"));
// 新结构包含 vo.dbName、expiresAtMs
assertTrue(newSchema.getFields().containsKey("vo.dbName"));
assertTrue(newSchema.getFields().containsKey("expiresAtMs"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldSchema, newSchema);
List<ChangeType> types = changes.stream().map(SchemaChange::getChangeType).collect(Collectors.toList());
assertTrue(types.contains(ChangeType.WRAPPER_ADDED), "应检测到包装层 vo");
assertTrue(types.contains(ChangeType.FIELD_PATH_MOVED), "应检测到字段路径迁移");
assertTrue(types.contains(ChangeType.FIELD_ADDED), "应检测到 expiresAtMs 新增");
}
private WritePoint single(List<WritePoint> wps) {
assertEquals(1, wps.size(), "应恰好检测到 1 个写入点");
return wps.get(0);
}
}

View File

@@ -0,0 +1,33 @@
package com.codechecker.redis;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;
/**
* 测试通用工具:加载 classpath 下的 fixture 文本。
*/
public final class TestSupport {
private TestSupport() {
}
public static String fixture(String path) {
try (InputStream in = TestSupport.class.getClassLoader().getResourceAsStream(path)) {
if (in == null) {
throw new IllegalArgumentException("fixture 不存在: " + path);
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] chunk = new byte[8192];
int read;
while ((read = in.read(chunk)) != -1) {
buffer.write(chunk, 0, read);
}
return new String(buffer.toByteArray(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@@ -0,0 +1,28 @@
package com.codechecker.redis.analyze;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class GlobMatcherTest {
@Test
void matchesPrefixWildcard() {
assertTrue(GlobMatcher.matches("tenant:db:content:*", "tenant:db:content:abc"));
assertTrue(GlobMatcher.matches("*:lock", "device:add:lock"));
assertTrue(GlobMatcher.matches("*lock*", "abTaskDetailUpdate:lock:x"));
assertTrue(GlobMatcher.matches("loginCount:*", "loginCount:13800000000"));
}
@Test
void matchesDoubleStarPath() {
assertTrue(GlobMatcher.matches("**/test/**", "jnpf-x/src/test/java/Foo.java"));
assertFalse(GlobMatcher.matches("**/test/**", "jnpf-x/src/main/java/Foo.java"));
}
@Test
void literalNoMatch() {
assertFalse(GlobMatcher.matches("tenant:db:content:*", "other:key"));
}
}

View File

@@ -0,0 +1,41 @@
package com.codechecker.redis.config;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ConfigLoaderTest {
@Test
void loadsDefaultsWhenNoBusinessConfig() {
CheckerConfig config = ConfigLoader.load(null);
assertEquals("notify", config.getMode());
assertTrue(config.getBlockSeverities().contains("P0"));
assertTrue(config.getDetection().getPatterns().contains("W01"));
assertFalse(config.isScanTestSources());
}
@Test
void businessConfigOverridesDefaults(@org.junit.jupiter.api.io.TempDir Path tmp) throws IOException {
Path cfg = tmp.resolve("biz.yaml");
Files.write(cfg, ("mode: block\n"
+ "include_modules:\n - jnpf-tenant\n"
+ "notify:\n enabled: false\n").getBytes(StandardCharsets.UTF_8));
CheckerConfig config = ConfigLoader.load(cfg);
assertEquals("block", config.getMode());
assertTrue(config.isBlockMode());
assertEquals(1, config.getIncludeModules().size());
assertEquals("jnpf-tenant", config.getIncludeModules().get(0));
// 未覆盖项保留默认
assertFalse(config.getNotify().isEnabled());
assertTrue(config.getBlockSeverities().contains("P2"));
}
}

View File

@@ -0,0 +1,64 @@
package com.codechecker.redis.diff;
import com.codechecker.redis.schema.FieldSchema;
import com.codechecker.redis.schema.JsonType;
import com.codechecker.redis.schema.TypeSchema;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SchemaDifferTest {
@Test
void detectsWrapperMoveAndAddition() {
TypeSchema oldS = new TypeSchema("TenantVO");
oldS.add(new FieldSchema("dbName", JsonType.STRING, "String"));
oldS.add(new FieldSchema("linkList", JsonType.ARRAY, "List"));
oldS.add(new FieldSchema("linkList[]", JsonType.OBJECT, "TenantLinkModel"));
oldS.add(new FieldSchema("linkList[].id", JsonType.STRING, "String"));
TypeSchema newS = new TypeSchema("CacheEnvelope");
newS.add(new FieldSchema("vo", JsonType.OBJECT, "TenantVO"));
newS.add(new FieldSchema("vo.dbName", JsonType.STRING, "String"));
newS.add(new FieldSchema("vo.linkList", JsonType.ARRAY, "List"));
newS.add(new FieldSchema("vo.linkList[]", JsonType.OBJECT, "TenantLinkModel"));
newS.add(new FieldSchema("vo.linkList[].id", JsonType.STRING, "String"));
newS.add(new FieldSchema("expiresAtMs", JsonType.NUMBER, "Long"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
List<ChangeType> types = changes.stream().map(SchemaChange::getChangeType).collect(Collectors.toList());
assertTrue(types.contains(ChangeType.WRAPPER_ADDED), "应检测到包装层新增");
assertTrue(types.contains(ChangeType.FIELD_PATH_MOVED), "应检测到字段路径迁移");
assertTrue(types.contains(ChangeType.FIELD_ADDED), "应检测到新增字段 expiresAtMs");
long moved = changes.stream().filter(c -> c.getChangeType() == ChangeType.FIELD_PATH_MOVED).count();
assertEquals(2, moved, "dbName 与 linkList[].id 均应迁移");
}
@Test
void detectsTypeChange() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("count", JsonType.STRING, "String"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("count", JsonType.NUMBER, "Integer"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
assertEquals(Severity.P0, changes.get(0).getSeverity());
}
@Test
void noChangeWhenIdentical() {
TypeSchema a = new TypeSchema("A");
a.add(new FieldSchema("x", JsonType.STRING, "String"));
TypeSchema b = new TypeSchema("A");
b.add(new FieldSchema("x", JsonType.STRING, "String"));
assertTrue(new SchemaDiffer().diff(a, b).isEmpty());
}
}