feat: 二阶段

This commit is contained in:
2026-07-15 17:38:02 +08:00
parent d884aa36ff
commit bb406cd354
28 changed files with 1076 additions and 79 deletions

View File

@@ -1,5 +1,7 @@
package com.codechecker.cache;
import com.codechecker.cache.detector.CacheReadHint;
import com.codechecker.cache.detector.MqReadHintDetector;
import com.codechecker.cache.detector.MqWritePointDetector;
import com.codechecker.cache.detector.WritePoint;
import com.codechecker.cache.diff.ChangeType;
@@ -19,6 +21,7 @@ import java.util.Set;
import java.util.stream.Collectors;
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 MqScenarioTest {
@@ -120,4 +123,63 @@ class MqScenarioTest {
assertTrue(md.contains("> **通道**: Kafka"), md);
assertTrue(md.contains("> **类型**: List<CheckItemDetailVo>"), md);
}
@Test
void messageBuilderProducerResolvesDutyImNotice() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
Set<String> patterns = new HashSet<>();
patterns.add("MQ02");
patterns.add("MQ04");
WritePoint wp = new MqWritePointDetector(index, patterns)
.detect("DutyImNoticeProducer.java", producer).stream()
.filter(w -> "MQ04".equals(w.getPattern()))
.findFirst()
.orElseThrow(() -> new AssertionError("应命中 MQ04"));
assertEquals("duty-im-notice-topic", wp.getResolvedKeyPattern());
assertTrue(wp.getResolvedValueType().endsWith("DutyImNotice"));
}
@Test
void mqReadHintEnrichesWritePointByDestination() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
String consumer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeConsumer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
index.addSource(consumer);
List<CacheReadHint> hints = new MqReadHintDetector(index)
.detect("DutyImNoticeConsumer.java", consumer);
assertFalse(hints.isEmpty());
Set<String> patterns = new HashSet<>();
patterns.add("MQ02");
patterns.add("MQ04");
WritePoint wp = new MqWritePointDetector(index, patterns)
.detect("DutyImNoticeProducer.java", producer).stream()
.filter(w -> "MQ04".equals(w.getPattern()))
.findFirst()
.orElseThrow(() -> new AssertionError("应命中 MQ04"));
// 模拟无泛型 Message 导致类型缺失时MQ-R 可按 destination 补强
wp.setResolvedValueType(null);
wp.setConfidence(0.4);
CacheReadHint hint = hints.get(0);
assertEquals(wp.getResolvedKeyPattern(), hint.getResolvedKeyPattern());
if (hint.getResolvedValueType() != null) {
wp.setResolvedValueType(hint.getResolvedValueType());
wp.setConfidence(Math.max(wp.getConfidence(), hint.getConfidence()));
}
assertTrue(wp.getResolvedValueType().endsWith("DutyImNotice"));
assertTrue(wp.getConfidence() >= 0.8);
}
}

View File

@@ -21,7 +21,9 @@ class ConfigLoaderTest {
assertTrue(config.getDetection().getPatterns().contains("W01"));
assertTrue(config.getDetection().getMqPatterns().contains("MQ01"));
assertTrue(config.getDetection().getMqPatterns().contains("MQ-K01"));
assertFalse(config.getDetection().isMqReadHintsEnabled());
assertTrue(config.getDetection().getMqPatterns().contains("MQ04"));
assertTrue(config.getDetection().getMqPatterns().contains("MQ-K03"));
assertTrue(config.getDetection().isMqReadHintsEnabled());
assertFalse(config.isScanTestSources());
}

View File

@@ -0,0 +1,51 @@
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.List;
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 MqReadHintDetectorTest {
@Test
void detectsRocketMqListenerGenericType() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
String consumer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeConsumer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
index.addSource(consumer);
List<CacheReadHint> hints = new MqReadHintDetector(index)
.detect("DutyImNoticeConsumer.java", consumer);
assertFalse(hints.isEmpty());
CacheReadHint hint = hints.get(0);
assertTrue(hint.getResolvedValueType().endsWith("DutyImNotice"));
assertEquals("duty-im-notice-topic", hint.getResolvedKeyPattern());
assertFalse(hint.isRootArray());
}
@Test
void detectsKafkaListenerParseObject() {
String vo = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyVo.txt");
String listener = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyListener.txt");
SourceIndex index = new SourceIndex();
index.addSource(vo);
index.addSource(listener);
List<CacheReadHint> hints = new MqReadHintDetector(index)
.detect("PatrolNotifyListener.java", listener);
assertTrue(hints.stream().anyMatch(h ->
h.getResolvedValueType() != null
&& h.getResolvedValueType().endsWith("PatrolNotifyVo")
&& "patrol-notify-topic".equals(h.getResolvedKeyPattern())));
}
}

View File

@@ -28,6 +28,9 @@ class MqWritePointDetectorTest {
Set<String> patterns = new HashSet<>();
patterns.add("MQ01");
patterns.add("MQ02");
patterns.add("MQ03");
patterns.add("MQ04");
patterns.add("MQ05");
List<WritePoint> wps = new MqWritePointDetector(index, patterns)
.detect("WalletDeductProducer.java", producer);
@@ -63,4 +66,110 @@ class MqWritePointDetectorTest {
assertTrue(wp.getResolvedValueType().endsWith("CheckItemDetailVo"));
assertTrue(wp.isRootArray());
}
@Test
void detectsMessageBuilderAsyncSendAsMq04() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
Set<String> patterns = allRocketPatterns();
List<WritePoint> wps = new MqWritePointDetector(index, patterns)
.detect("DutyImNoticeProducer.java", producer);
WritePoint mq04 = findByPattern(wps, "MQ04");
assertEquals(WritePoint.CHANNEL_ROCKETMQ, mq04.getChannel());
assertEquals("duty-im-notice-topic", mq04.getResolvedKeyPattern());
assertTrue(mq04.getResolvedValueType().endsWith("DutyImNotice"), mq04.getResolvedValueType());
}
@Test
void detectsConvertAndSendAsMq03() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
WritePoint mq03 = findByPattern(
new MqWritePointDetector(index, allRocketPatterns())
.detect("DutyImNoticeProducer.java", producer),
"MQ03");
assertTrue(mq03.getResolvedValueType().endsWith("DutyImNotice"));
}
@Test
void detectsJsonStringSyncSendAsMq05() {
String notice = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNotice.txt");
String producer = TestSupport.fixture("fixtures/mq/rocket-im/DutyImNoticeProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(notice);
index.addSource(producer);
WritePoint mq05 = findByPattern(
new MqWritePointDetector(index, allRocketPatterns())
.detect("DutyImNoticeProducer.java", producer),
"MQ05");
assertTrue(mq05.getResolvedValueType().endsWith("DutyImNotice"));
}
@Test
void detectsProducerRecordSendAsMqK03() {
String vo = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyVo.txt");
String producer = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(vo);
index.addSource(producer);
Set<String> patterns = allKafkaPatterns();
WritePoint wp = findByPattern(
new MqWritePointDetector(index, patterns).detect("PatrolNotifyProducer.java", producer),
"MQ-K03");
assertEquals("patrol-notify-topic", wp.getResolvedKeyPattern());
assertTrue(wp.getResolvedValueType().endsWith("PatrolNotifyVo"));
}
@Test
void detectsKafkaJsonStringAsMqK04() {
String vo = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyVo.txt");
String producer = TestSupport.fixture("fixtures/mq/kafka-record/PatrolNotifyProducer.txt");
SourceIndex index = new SourceIndex();
index.addSource(vo);
index.addSource(producer);
WritePoint wp = findByPattern(
new MqWritePointDetector(index, allKafkaPatterns())
.detect("PatrolNotifyProducer.java", producer),
"MQ-K04");
assertTrue(wp.getResolvedValueType().endsWith("PatrolNotifyVo"));
}
private static Set<String> allRocketPatterns() {
Set<String> patterns = new HashSet<>();
patterns.add("MQ01");
patterns.add("MQ02");
patterns.add("MQ03");
patterns.add("MQ04");
patterns.add("MQ05");
return patterns;
}
private static Set<String> allKafkaPatterns() {
Set<String> patterns = new HashSet<>();
patterns.add("MQ-K01");
patterns.add("MQ-K02");
patterns.add("MQ-K03");
patterns.add("MQ-K04");
return patterns;
}
private static WritePoint findByPattern(List<WritePoint> wps, String pattern) {
return wps.stream()
.filter(w -> pattern.equals(w.getPattern()))
.findFirst()
.orElseThrow(() -> new AssertionError("缺少模式 " + pattern + ",实际: " + wps));
}
}