This commit is contained in:
101
src/test/java/com/codechecker/cache/detector/RedisWritePointDetectorTest.java
vendored
Normal file
101
src/test/java/com/codechecker/cache/detector/RedisWritePointDetectorTest.java
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package com.codechecker.cache.detector;
|
||||
|
||||
import com.codechecker.cache.TestSupport;
|
||||
import com.codechecker.cache.schema.SourceIndex;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class RedisWritePointDetectorTest {
|
||||
|
||||
@Test
|
||||
void detectsW04DirectObjectWrite() {
|
||||
String source = ""
|
||||
+ "package demo;\n"
|
||||
+ "import demo.model.DemoVo;\n"
|
||||
+ "public class DemoService {\n"
|
||||
+ " private RedisTemplate<String, DemoVo> redisTemplate;\n"
|
||||
+ " public void save(String key, DemoVo vo) {\n"
|
||||
+ " redisTemplate.opsForValue().set(key, vo, 60, TimeUnit.SECONDS);\n"
|
||||
+ " }\n"
|
||||
+ "}\n";
|
||||
String vo = ""
|
||||
+ "package demo.model;\n"
|
||||
+ "public class DemoVo { private String name; }\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(vo);
|
||||
index.addSource(source);
|
||||
|
||||
Set<String> patterns = new HashSet<>(Arrays.asList("W04"));
|
||||
List<WritePoint> wps = new RedisWritePointDetector(index, patterns)
|
||||
.detect("DemoService.java", source);
|
||||
|
||||
assertEquals(1, wps.size());
|
||||
WritePoint wp = wps.get(0);
|
||||
assertEquals("W04", wp.getPattern());
|
||||
assertEquals("demo.model.DemoVo", wp.getResolvedValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void detectsW05HashPut() {
|
||||
String source = ""
|
||||
+ "package demo;\n"
|
||||
+ "import demo.model.DemoVo;\n"
|
||||
+ "public class DemoService {\n"
|
||||
+ " private RedisTemplate<String, Object> redisTemplate;\n"
|
||||
+ " public void save(String key, String field, DemoVo vo) {\n"
|
||||
+ " redisTemplate.opsForHash().put(key, field, vo);\n"
|
||||
+ " }\n"
|
||||
+ "}\n";
|
||||
String vo = ""
|
||||
+ "package demo.model;\n"
|
||||
+ "public class DemoVo { private String name; }\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(vo);
|
||||
index.addSource(source);
|
||||
|
||||
Set<String> patterns = new HashSet<>(Arrays.asList("W05"));
|
||||
List<WritePoint> wps = new RedisWritePointDetector(index, patterns)
|
||||
.detect("DemoService.java", source);
|
||||
|
||||
assertEquals(1, wps.size());
|
||||
assertEquals("W05", wps.get(0).getPattern());
|
||||
assertEquals("demo.model.DemoVo", wps.get(0).getResolvedValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresLockAndLiteralWrites() {
|
||||
String source = TestSupport.fixture("fixtures/lock/LockService.txt");
|
||||
Set<String> patterns = new HashSet<>(Arrays.asList("W01", "W02", "W03", "W04", "W05"));
|
||||
List<WritePoint> wps = new RedisWritePointDetector(new SourceIndex(), patterns)
|
||||
.detect("LockService.java", source);
|
||||
assertTrue(wps.isEmpty(), "锁/计数器/token 写入应被忽略");
|
||||
}
|
||||
|
||||
@Test
|
||||
void stillDetectsW01ToW03() {
|
||||
String helper = TestSupport.fixture("fixtures/tenant/HelperOld.txt");
|
||||
String tenantVo = TestSupport.fixture("fixtures/tenant/TenantVO.txt");
|
||||
String tenantLink = TestSupport.fixture("fixtures/tenant/TenantLinkModel.txt");
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(tenantVo);
|
||||
index.addSource(tenantLink);
|
||||
index.addSource(helper);
|
||||
|
||||
Set<String> patterns = new HashSet<>(Arrays.asList("W01", "W02", "W03"));
|
||||
List<WritePoint> wps = new RedisWritePointDetector(index, patterns)
|
||||
.detect("Helper.java", helper);
|
||||
|
||||
assertEquals(1, wps.size());
|
||||
assertEquals("W01", wps.get(0).getPattern());
|
||||
}
|
||||
}
|
||||
68
src/test/java/com/codechecker/cache/key/RedisKeyResolverTest.java
vendored
Normal file
68
src/test/java/com/codechecker/cache/key/RedisKeyResolverTest.java
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package com.codechecker.cache.key;
|
||||
|
||||
import com.codechecker.cache.schema.SourceIndex;
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
|
||||
import com.github.javaparser.ast.expr.Expression;
|
||||
import com.github.javaparser.ast.expr.MethodCallExpr;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class RedisKeyResolverTest {
|
||||
|
||||
@Test
|
||||
void resolvesStringFormatWithConstant() {
|
||||
String source = ""
|
||||
+ "package demo;\n"
|
||||
+ "public class AttendanceService {\n"
|
||||
+ " private static final String ATTENDANCE_BASE_SETTING_CACHE_KEY = "
|
||||
+ "\"fbt:attendance:base_setting:cache:%s\";\n"
|
||||
+ " public void save(String tenantId) {\n"
|
||||
+ " String key = String.format(ATTENDANCE_BASE_SETTING_CACHE_KEY, tenantId);\n"
|
||||
+ " }\n"
|
||||
+ "}\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(source);
|
||||
CompilationUnit cu = StaticJavaParser.parse(source);
|
||||
ClassOrInterfaceDeclaration clazz = cu.getType(0).asClassOrInterfaceDeclaration();
|
||||
MethodCallExpr formatCall = cu.findAll(MethodCallExpr.class).stream()
|
||||
.filter(m -> "format".equals(m.getNameAsString()))
|
||||
.findFirst()
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
|
||||
String pattern = new RedisKeyResolver(index).resolve(
|
||||
formatCall, clazz, index.get("demo.AttendanceService"));
|
||||
assertEquals("fbt:attendance:base_setting:cache:*", pattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesConstantConcatAndBuildMethod() {
|
||||
String source = ""
|
||||
+ "package jnpf.util;\n"
|
||||
+ "public class TenantDbContentCacheHelper {\n"
|
||||
+ " private static final String CACHE_KEY_PREFIX = \"tenant:db:content:\";\n"
|
||||
+ " public String buildCacheKey(String encode) {\n"
|
||||
+ " return CACHE_KEY_PREFIX + encode;\n"
|
||||
+ " }\n"
|
||||
+ " public void cache(String encode) {\n"
|
||||
+ " String key = buildCacheKey(encode);\n"
|
||||
+ " }\n"
|
||||
+ "}\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(source);
|
||||
CompilationUnit cu = StaticJavaParser.parse(source);
|
||||
ClassOrInterfaceDeclaration clazz = cu.getType(0).asClassOrInterfaceDeclaration();
|
||||
MethodCallExpr buildCall = cu.findAll(MethodCallExpr.class).stream()
|
||||
.filter(m -> "buildCacheKey".equals(m.getNameAsString()))
|
||||
.findFirst()
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
|
||||
String pattern = new RedisKeyResolver(index).resolve(
|
||||
buildCall, clazz, index.get("jnpf.util.TenantDbContentCacheHelper"));
|
||||
assertEquals("tenant:db:content:*", pattern);
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class ReportBuilderTest {
|
||||
String md = new ReportBuilder("[缓存结构变更]").toMarkdown(report);
|
||||
|
||||
assertTrue(md.contains("- Key --> `saas:period-config:migration:current`"));
|
||||
assertFalse(md.contains("(key 未解析)"));
|
||||
assertFalse(md.contains("(key 无法解析)"));
|
||||
assertTrue(md.contains("> **位置**: `SaasPeriodConfigMigrationRedisSupport#putCurrent:41`"));
|
||||
assertTrue(md.contains("> **类型**: `MigrationCurrentVo`"));
|
||||
|
||||
@@ -158,10 +158,10 @@ class ReportBuilderTest {
|
||||
report.getKeyChanges().add(key);
|
||||
|
||||
String md = new ReportBuilder("[缓存结构变更]").toMarkdown(report);
|
||||
assertTrue(md.contains("- Key --> `req.getKey()` <font color=\"comment\">(key 未解析)</font>"));
|
||||
assertTrue(md.contains("- Key --> `req.getKey()` <font color=\"comment\">(key 无法解析)</font>"));
|
||||
assertTrue(md.contains("> **位置**: `ClockInXxxService#export:128`"));
|
||||
assertTrue(md.contains("> **类型**: `List<ClockInExportVo>`"));
|
||||
assertFalse(md.contains("unknown-key"));
|
||||
assertFalse(md.contains("`unknown-key`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
84
src/test/java/com/codechecker/cache/schema/JavaSchemaExtractorTest.java
vendored
Normal file
84
src/test/java/com/codechecker/cache/schema/JavaSchemaExtractorTest.java
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.codechecker.cache.schema;
|
||||
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
|
||||
import com.github.javaparser.ast.body.FieldDeclaration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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 JavaSchemaExtractorTest {
|
||||
|
||||
@Test
|
||||
void honorsJsonIgnoreAndPropertyRename() {
|
||||
String source = ""
|
||||
+ "package demo;\n"
|
||||
+ "import com.fasterxml.jackson.annotation.JsonIgnore;\n"
|
||||
+ "import com.fasterxml.jackson.annotation.JsonProperty;\n"
|
||||
+ "public class AnnotatedVo {\n"
|
||||
+ " @JsonProperty(\"display_name\")\n"
|
||||
+ " private String name;\n"
|
||||
+ " @JsonIgnore\n"
|
||||
+ " private String secret;\n"
|
||||
+ " private String visible;\n"
|
||||
+ "}\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(source);
|
||||
TypeSchema schema = new JavaSchemaExtractor(index, 8).extract("demo.AnnotatedVo");
|
||||
|
||||
assertTrue(schema.getFields().containsKey("display_name"));
|
||||
assertTrue(schema.getFields().containsKey("visible"));
|
||||
assertFalse(schema.getFields().containsKey("secret"));
|
||||
assertFalse(schema.getFields().containsKey("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void honorsFastjsonFieldAndClassIgnoreProperties() {
|
||||
String source = ""
|
||||
+ "package demo;\n"
|
||||
+ "import com.alibaba.fastjson.annotation.JSONField;\n"
|
||||
+ "import com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n"
|
||||
+ "@JsonIgnoreProperties({\"password\"})\n"
|
||||
+ "public class FastVo {\n"
|
||||
+ " @JSONField(name = \"user_id\")\n"
|
||||
+ " private String userId;\n"
|
||||
+ " @JSONField(serialize = false)\n"
|
||||
+ " private String token;\n"
|
||||
+ " private String password;\n"
|
||||
+ "}\n";
|
||||
|
||||
SourceIndex index = new SourceIndex();
|
||||
index.addSource(source);
|
||||
TypeSchema schema = new JavaSchemaExtractor(index, 8).extract("demo.FastVo");
|
||||
|
||||
assertTrue(schema.getFields().containsKey("user_id"));
|
||||
assertFalse(schema.getFields().containsKey("token"));
|
||||
assertFalse(schema.getFields().containsKey("password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonNameHelpersWorkOnFieldAnnotations() {
|
||||
CompilationUnit cu = StaticJavaParser.parse(""
|
||||
+ "class X {\n"
|
||||
+ " @com.fasterxml.jackson.annotation.JsonProperty(\"alias\")\n"
|
||||
+ " private String field;\n"
|
||||
+ "}");
|
||||
FieldDeclaration field = cu.getType(0).asClassOrInterfaceDeclaration().getFields().get(0);
|
||||
assertEquals("alias", AnnotationSupport.jsonName(field, "field"));
|
||||
assertTrue(AnnotationSupport.isSerialized(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void classIgnorePropertiesCollected() {
|
||||
CompilationUnit cu = StaticJavaParser.parse(""
|
||||
+ "@com.fasterxml.jackson.annotation.JsonIgnoreProperties({\"a\", \"b\"})\n"
|
||||
+ "class X {}");
|
||||
ClassOrInterfaceDeclaration type = cu.getType(0).asClassOrInterfaceDeclaration();
|
||||
assertTrue(AnnotationSupport.ignoredProperties(type).contains("a"));
|
||||
assertTrue(AnnotationSupport.ignoredProperties(type).contains("b"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user