heauristic bean resolution
This commit is contained in:
@@ -14,8 +14,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.enricher.routing.HeuristicRoutingEngine;
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.enricher.routing.RoutingEngine;
|
||||||
|
|
||||||
public class TransitionLinkerEnricher implements AnalysisEnricher {
|
public class TransitionLinkerEnricher implements AnalysisEnricher {
|
||||||
|
|
||||||
|
private final RoutingEngine routingEngine = new HeuristicRoutingEngine();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enrich(AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
|
public void enrich(AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
|
||||||
if (result.getMetadata() == null || result.getMetadata().getCallChains() == null) {
|
if (result.getMetadata() == null || result.getMetadata().getCallChains() == null) {
|
||||||
@@ -125,156 +130,7 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
|
|
||||||
|
|
||||||
private boolean isRoutedToCorrectMachine(CallChain chain, String currentMachineName) {
|
private boolean isRoutedToCorrectMachine(CallChain chain, String currentMachineName) {
|
||||||
// First, check explicit variable targeting (like contextMachineId)
|
return routingEngine.isRoutedToCorrectMachine(chain, currentMachineName);
|
||||||
String targetVar = chain.getContextMachineId();
|
|
||||||
if (targetVar == null && chain.getTriggerPoint() != null) {
|
|
||||||
targetVar = chain.getTriggerPoint().getStateMachineId();
|
|
||||||
}
|
|
||||||
|
|
||||||
String simplifiedMachineName = currentMachineName != null ? currentMachineName.substring(currentMachineName.lastIndexOf('.') + 1).toLowerCase() : "";
|
|
||||||
|
|
||||||
if (targetVar != null && !targetVar.isEmpty()) {
|
|
||||||
targetVar = targetVar.toLowerCase();
|
|
||||||
// E.g., if target is "myStateMachine", ensure current machine name contains "my"
|
|
||||||
// If the variable name ends with StateMachine, we extract the prefix
|
|
||||||
if (targetVar.endsWith("statemachine")) {
|
|
||||||
String prefix = targetVar.substring(0, targetVar.length() - "statemachine".length());
|
|
||||||
if (!prefix.isEmpty() && !simplifiedMachineName.contains(prefix)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Generic approach combining Prefix, Package, and String-distance heuristics
|
|
||||||
// without relying on a hardcoded list of magic keywords.
|
|
||||||
if (chain.getMethodChain() != null && !chain.getMethodChain().isEmpty() && currentMachineName != null) {
|
|
||||||
String smPackage = getPackageName(currentMachineName);
|
|
||||||
String smSimple = getSimpleClassName(currentMachineName);
|
|
||||||
String smPrefix = getFirstCamelCaseWord(smSimple);
|
|
||||||
|
|
||||||
boolean hasPositiveMatch = false;
|
|
||||||
boolean hasStrongMismatch = false;
|
|
||||||
|
|
||||||
for (String method : chain.getMethodChain()) {
|
|
||||||
String chainClass = getClassNameOnly(method);
|
|
||||||
String chainPackage = getPackageName(chainClass);
|
|
||||||
String chainSimple = getSimpleClassName(chainClass);
|
|
||||||
String chainPrefix = getFirstCamelCaseWord(chainSimple);
|
|
||||||
|
|
||||||
// 1. Explicit Prefix Match (e.g. ElectronicsOrderService & ElectronicsStateMachine)
|
|
||||||
if (smPrefix != null && chainPrefix != null && smPrefix.equals(chainPrefix)) {
|
|
||||||
hasPositiveMatch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Explicit Sub-Package Match (e.g. com.company.electronics.service & com.company.electronics.sm)
|
|
||||||
// We consider it a match if they share a package segment beyond the first 2 (which are usually com.company)
|
|
||||||
String deepShared = getDeepSharedPackage(smPackage, chainPackage);
|
|
||||||
if (deepShared != null) {
|
|
||||||
hasPositiveMatch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if there is a strong mismatch.
|
|
||||||
// A strong mismatch happens if the chain class has a VERY distinct prefix/package
|
|
||||||
// that contradicts the SM's distinct prefix/package.
|
|
||||||
// Without magic keywords, we guess if a prefix is distinct if it's long enough and doesn't match.
|
|
||||||
if (smPrefix != null && chainPrefix != null && !smPrefix.equals(chainPrefix)) {
|
|
||||||
// They have different first CamelCase words.
|
|
||||||
// This could be Electronics vs ComputerStore, or it could be Common vs ComputerStore.
|
|
||||||
// If they diverge at a deep package level, it's a strong mismatch.
|
|
||||||
if (isDeepPackageDivergence(smPackage, chainPackage)) {
|
|
||||||
hasStrongMismatch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found a positive structural match, route it!
|
|
||||||
if (hasPositiveMatch) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no positive match, but we detected a strong structural mismatch, reject it!
|
|
||||||
if (hasStrongMismatch) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If neither, we allow it (fallback for common/shared endpoints without distinct domains)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPackageName(String fqn) {
|
|
||||||
if (fqn == null || !fqn.contains(".")) return "";
|
|
||||||
return fqn.substring(0, fqn.lastIndexOf('.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSimpleClassName(String fqn) {
|
|
||||||
if (fqn == null) return "";
|
|
||||||
if (!fqn.contains(".")) return fqn;
|
|
||||||
return fqn.substring(fqn.lastIndexOf('.') + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getClassNameOnly(String methodFqn) {
|
|
||||||
if (methodFqn == null) return "";
|
|
||||||
String clean = methodFqn;
|
|
||||||
if (clean.contains("(")) {
|
|
||||||
clean = clean.substring(0, clean.indexOf('('));
|
|
||||||
}
|
|
||||||
if (clean.contains(".")) {
|
|
||||||
clean = clean.substring(0, clean.lastIndexOf('.'));
|
|
||||||
}
|
|
||||||
return clean;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFirstCamelCaseWord(String simpleName) {
|
|
||||||
if (simpleName == null || simpleName.isEmpty()) return null;
|
|
||||||
// e.g. "ElectronicsOrderService" -> "Electronics"
|
|
||||||
String[] words = simpleName.split("(?<!^)(?=[A-Z])");
|
|
||||||
if (words.length > 0) {
|
|
||||||
return words[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDeepSharedPackage(String pkg1, String pkg2) {
|
|
||||||
if (pkg1 == null || pkg2 == null || pkg1.isEmpty() || pkg2.isEmpty()) return null;
|
|
||||||
String[] p1 = pkg1.split("\\.");
|
|
||||||
String[] p2 = pkg2.split("\\.");
|
|
||||||
|
|
||||||
// Find the deepest common segment index
|
|
||||||
int matchIdx = -1;
|
|
||||||
for (int i = 0; i < Math.min(p1.length, p2.length); i++) {
|
|
||||||
if (p1[i].equals(p2[i])) {
|
|
||||||
matchIdx = i;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If they share at least 3 segments (e.g. com.company.electronics), it's a deep match
|
|
||||||
if (matchIdx >= 2) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for(int i = 0; i <= matchIdx; i++) {
|
|
||||||
sb.append(p1[i]).append(".");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDeepPackageDivergence(String pkg1, String pkg2) {
|
|
||||||
if (pkg1 == null || pkg2 == null || pkg1.isEmpty() || pkg2.isEmpty()) return false;
|
|
||||||
String[] p1 = pkg1.split("\\.");
|
|
||||||
String[] p2 = pkg2.split("\\.");
|
|
||||||
|
|
||||||
// If they share exactly the root (com.company) but diverge at the 3rd segment (e.g. electronics vs computerstore)
|
|
||||||
// Then it's a divergence.
|
|
||||||
if (p1.length >= 3 && p2.length >= 3) {
|
|
||||||
return p1[0].equals(p2[0]) && p1[1].equals(p2[1]) && !p1[2].equals(p2[2]);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String simplify(String name) {
|
private String simplify(String name) {
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.enricher.routing;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class HeuristicRoutingEngine implements RoutingEngine {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoutedToCorrectMachine(CallChain chain, String currentMachineName) {
|
||||||
|
String targetVar = chain.getContextMachineId();
|
||||||
|
if (targetVar == null && chain.getTriggerPoint() != null) {
|
||||||
|
targetVar = chain.getTriggerPoint().getStateMachineId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String simplifiedMachineName = currentMachineName != null ? currentMachineName.substring(currentMachineName.lastIndexOf('.') + 1).toLowerCase() : "";
|
||||||
|
|
||||||
|
if (targetVar != null && !targetVar.isEmpty()) {
|
||||||
|
targetVar = targetVar.toLowerCase();
|
||||||
|
if (targetVar.endsWith("statemachine")) {
|
||||||
|
String prefix = targetVar.substring(0, targetVar.length() - "statemachine".length());
|
||||||
|
if (!prefix.isEmpty()) {
|
||||||
|
if (simplifiedMachineName.contains(prefix)) {
|
||||||
|
return true; // Explicit positive match
|
||||||
|
} else {
|
||||||
|
return false; // Explicit negative match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (simplifiedMachineName.contains(targetVar)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain.getMethodChain() != null && !chain.getMethodChain().isEmpty() && currentMachineName != null) {
|
||||||
|
String smPackage = getPackageName(currentMachineName);
|
||||||
|
String smSimple = getSimpleClassName(currentMachineName);
|
||||||
|
String smPrefix = getFirstCamelCaseWord(smSimple);
|
||||||
|
|
||||||
|
boolean hasPositiveMatch = false;
|
||||||
|
boolean hasStrongMismatch = false;
|
||||||
|
|
||||||
|
for (String method : chain.getMethodChain()) {
|
||||||
|
String chainClass = getClassNameOnly(method);
|
||||||
|
String chainPackage = getPackageName(chainClass);
|
||||||
|
String chainSimple = getSimpleClassName(chainClass);
|
||||||
|
String chainPrefix = getFirstCamelCaseWord(chainSimple);
|
||||||
|
|
||||||
|
if (smPrefix != null && chainPrefix != null && smPrefix.equals(chainPrefix)) {
|
||||||
|
hasPositiveMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDomainMatch(smPackage, chainPackage, smPrefix, chainPrefix)) {
|
||||||
|
hasPositiveMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDomainMismatch(smPackage, chainPackage, smPrefix, chainPrefix)) {
|
||||||
|
hasStrongMismatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPositiveMatch) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hasStrongMismatch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDomainMatch(String smPackage, String chainPackage, String smPrefix, String chainPrefix) {
|
||||||
|
if (smPackage == null || chainPackage == null || smPackage.isEmpty() || chainPackage.isEmpty()) return false;
|
||||||
|
|
||||||
|
if (smPackage.startsWith(chainPackage) || chainPackage.startsWith(smPackage)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find deepest common package root
|
||||||
|
String[] p1 = smPackage.split("\\.");
|
||||||
|
String[] p2 = chainPackage.split("\\.");
|
||||||
|
int matchIdx = -1;
|
||||||
|
for (int i = 0; i < Math.min(p1.length, p2.length); i++) {
|
||||||
|
if (p1[i].equals(p2[i])) {
|
||||||
|
matchIdx = i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the state machine's prefix is part of the shared common package,
|
||||||
|
// then the state machine represents the parent domain of the caller.
|
||||||
|
if (smPrefix != null && matchIdx >= 0) {
|
||||||
|
String lowerPrefix = smPrefix.toLowerCase();
|
||||||
|
for (int i = 0; i <= matchIdx; i++) {
|
||||||
|
if (p1[i].toLowerCase().contains(lowerPrefix) || lowerPrefix.contains(p1[i].toLowerCase())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDomainMismatch(String smPackage, String chainPackage, String smPrefix, String chainPrefix) {
|
||||||
|
if (smPackage == null || chainPackage == null || smPackage.isEmpty() || chainPackage.isEmpty()) return false;
|
||||||
|
|
||||||
|
String[] p1 = smPackage.split("\\.");
|
||||||
|
String[] p2 = chainPackage.split("\\.");
|
||||||
|
|
||||||
|
int matchIdx = -1;
|
||||||
|
for (int i = 0; i < Math.min(p1.length, p2.length); i++) {
|
||||||
|
if (p1[i].equals(p2[i])) {
|
||||||
|
matchIdx = i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> smDivergentTerms = new HashSet<>();
|
||||||
|
if (smPrefix != null) smDivergentTerms.add(smPrefix.toLowerCase());
|
||||||
|
for (int i = matchIdx + 1; i < p1.length; i++) {
|
||||||
|
smDivergentTerms.add(p1[i].toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> chainDivergentTerms = new HashSet<>();
|
||||||
|
if (chainPrefix != null) chainDivergentTerms.add(chainPrefix.toLowerCase());
|
||||||
|
for (int i = matchIdx + 1; i < p2.length; i++) {
|
||||||
|
chainDivergentTerms.add(p2[i].toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!smDivergentTerms.isEmpty() && !chainDivergentTerms.isEmpty()) {
|
||||||
|
Set<String> intersection = new HashSet<>(smDivergentTerms);
|
||||||
|
intersection.retainAll(chainDivergentTerms);
|
||||||
|
return intersection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> extractDomainTerms(String pkg, String prefix) {
|
||||||
|
Set<String> terms = new HashSet<>();
|
||||||
|
if (pkg != null && !pkg.isEmpty()) {
|
||||||
|
String[] segments = pkg.split("\\.");
|
||||||
|
// Take segments from index 2 onwards if length > 2
|
||||||
|
int start = segments.length > 2 ? 2 : 0;
|
||||||
|
for (int i = start; i < segments.length; i++) {
|
||||||
|
terms.add(segments[i].toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prefix != null && !prefix.isEmpty()) {
|
||||||
|
terms.add(prefix.toLowerCase());
|
||||||
|
}
|
||||||
|
return terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPackageName(String fqn) {
|
||||||
|
if (fqn == null || !fqn.contains(".")) return "";
|
||||||
|
return fqn.substring(0, fqn.lastIndexOf('.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSimpleClassName(String fqn) {
|
||||||
|
if (fqn == null) return "";
|
||||||
|
if (!fqn.contains(".")) return fqn;
|
||||||
|
return fqn.substring(fqn.lastIndexOf('.') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getClassNameOnly(String methodFqn) {
|
||||||
|
if (methodFqn == null) return "";
|
||||||
|
String clean = methodFqn;
|
||||||
|
if (clean.contains("(")) {
|
||||||
|
clean = clean.substring(0, clean.indexOf('('));
|
||||||
|
}
|
||||||
|
if (clean.contains(".")) {
|
||||||
|
clean = clean.substring(0, clean.lastIndexOf('.'));
|
||||||
|
}
|
||||||
|
return clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFirstCamelCaseWord(String simpleName) {
|
||||||
|
if (simpleName == null || simpleName.isEmpty()) return null;
|
||||||
|
String[] words = simpleName.split("(?<!^)(?=[A-Z])");
|
||||||
|
if (words.length > 0) {
|
||||||
|
return words[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.enricher.routing;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||||
|
|
||||||
|
public interface RoutingEngine {
|
||||||
|
boolean isRoutedToCorrectMachine(CallChain chain, String currentMachineName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.enricher.routing;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||||
|
import org.junit.jupiter.api.Tag;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@Tag("heuristic_bean_resolution")
|
||||||
|
public class HeuristicRoutingEngineTest {
|
||||||
|
|
||||||
|
private final HeuristicRoutingEngine engine = new HeuristicRoutingEngine();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeepPackageDivergenceMismatch() {
|
||||||
|
// This is the bug case: sharing a deep root, but diverging into different domains
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.corp.division.project.orders.OrderService.pay()"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.corp.division.project.payments.PaymentStateMachine";
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// They share com.acme.corp.division.project, but diverge into orders vs payments
|
||||||
|
// This should be a strong mismatch, so it should return false
|
||||||
|
assertFalse(result, "Deep package divergence into different domains should be rejected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSameDomainMatch() {
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.ecommerce.orders.OrderService.process()"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.ecommerce.orders.OrderStateMachine";
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// Same exact domain, should match
|
||||||
|
assertTrue(result, "Same domain should be accepted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubPackageMatch() {
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.ecommerce.orders.impl.OrderServiceImpl.process()"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.ecommerce.orders.OrderStateMachine";
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// Subpackage should match
|
||||||
|
assertTrue(result, "Sub-packages of the same domain should be accepted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSharedDomainTermMatch() {
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.orders.web.OrderController.submit()"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.orders.service.OrderStateMachine";
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// Different subpackages, but they share the "order" domain term and common prefix
|
||||||
|
assertTrue(result, "Divergent packages that share a domain term should be accepted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitTargetVariableMatch() {
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.common.GlobalTrigger.fire()"))
|
||||||
|
.contextMachineId("paymentStateMachine") // Explicitly targets payment
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.corp.payments.PaymentStateMachine";
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// Mismatched domains, but explicit variable targeting works
|
||||||
|
assertTrue(result, "Explicit variable target matching the machine name should be accepted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitTargetVariableMismatch() {
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.methodChain(Arrays.asList("com.acme.common.GlobalTrigger.fire()"))
|
||||||
|
.contextMachineId("paymentStateMachine") // Explicitly targets payment
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String machineName = "com.acme.corp.orders.OrderStateMachine"; // But this is Order
|
||||||
|
|
||||||
|
boolean result = engine.isRoutedToCorrectMachine(chain, machineName);
|
||||||
|
|
||||||
|
// Explicit variable targeting completely conflicts
|
||||||
|
assertFalse(result, "Explicit variable target mismatching the machine name should be rejected");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user