Expand entry-point and trigger detector coverage.
Detect fire/trigger wrappers as state-machine triggers, resolve Kafka topicPattern and additional Rabbit listener attributes, and add regression tests for WebFlux RouterFunction routes and messaging listeners. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class GenericEventDetectorFireTest {
|
||||
|
||||
@Test
|
||||
void shouldDetectFireMethodAsTrigger(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
enum OrderEvent { PAY, SHIP }
|
||||
class OrderService {
|
||||
private final StateMachineFacade facade;
|
||||
OrderService(StateMachineFacade facade) { this.facade = facade; }
|
||||
public void pay() {
|
||||
facade.fire(OrderEvent.PAY);
|
||||
}
|
||||
}
|
||||
class StateMachineFacade {
|
||||
public void fire(OrderEvent event) {}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
GenericEventDetector detector = new GenericEventDetector(context, context.getConstantResolver(), List.of());
|
||||
org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.OrderService");
|
||||
List<TriggerPoint> triggers = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());
|
||||
|
||||
assertThat(triggers).hasSize(1);
|
||||
assertThat(triggers.get(0).getMethodName()).isEqualTo("pay");
|
||||
assertThat(triggers.get(0).getEvent()).contains("PAY");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class MessagingDetectorTest {
|
||||
|
||||
@Test
|
||||
void shouldDetectRabbitListenerQueue(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class ReturnsListener {
|
||||
@RabbitListener(queues = "returns.queue")
|
||||
public void onReturn(String orderId) {}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("ReturnsListener.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
MessagingDetector detector = new MessagingDetector(context);
|
||||
org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.ReturnsListener");
|
||||
List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());
|
||||
|
||||
assertThat(entryPoints).hasSize(1);
|
||||
assertThat(entryPoints.get(0).getType()).isEqualTo(EntryPoint.Type.RABBIT);
|
||||
assertThat(entryPoints.get(0).getName()).isEqualTo("RABBIT: returns.queue");
|
||||
assertThat(entryPoints.get(0).getMetadata()).containsEntry("destination", "returns.queue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectKafkaListenerTopicsAndTopicPattern(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.kafka.annotation.KafkaListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class OrderKafkaListener {
|
||||
@KafkaListener(topics = {"orders.created", "orders.updated"})
|
||||
public void onOrderEvent(String payload) {}
|
||||
|
||||
@KafkaListener(topicPattern = "payments.*")
|
||||
public void onPaymentEvent(String payload) {}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderKafkaListener.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
MessagingDetector detector = new MessagingDetector(context);
|
||||
org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.OrderKafkaListener");
|
||||
List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());
|
||||
|
||||
assertThat(entryPoints).hasSize(2);
|
||||
assertThat(entryPoints).anyMatch(ep ->
|
||||
ep.getType() == EntryPoint.Type.KAFKA
|
||||
&& ep.getName().contains("orders.created")
|
||||
&& ep.getName().contains("orders.updated"));
|
||||
assertThat(entryPoints).anyMatch(ep ->
|
||||
ep.getType() == EntryPoint.Type.KAFKA
|
||||
&& "payments.*".equals(ep.getMetadata().get("destination")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SpringMvcDetectorTest {
|
||||
|
||||
@Test
|
||||
void shouldDetectWebFluxRouterFunctionBean(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
@Configuration
|
||||
public class ReactiveOrderApi {
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> orderRoutes() {
|
||||
return route().POST("/reactive/order", request -> ServerResponse.ok().build()).build();
|
||||
}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("ReactiveOrderApi.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
SpringMvcDetector detector = new SpringMvcDetector(context, context.getConstantResolver());
|
||||
org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.ReactiveOrderApi");
|
||||
List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());
|
||||
|
||||
assertThat(entryPoints).anyMatch(ep ->
|
||||
"POST /reactive/order".equals(ep.getName())
|
||||
&& "orderRoutes".equals(ep.getMethodName())
|
||||
&& "WebFlux Functional".equals(ep.getMetadata().get("style")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectRestControllerPostMapping(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@RestController
|
||||
@RequestMapping("/api/orders")
|
||||
public class OrderController {
|
||||
@PostMapping("/pay")
|
||||
public void pay() {}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderController.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
SpringMvcDetector detector = new SpringMvcDetector(context, context.getConstantResolver());
|
||||
org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.OrderController");
|
||||
List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());
|
||||
|
||||
assertThat(entryPoints).anyMatch(ep ->
|
||||
"POST /api/orders/pay".equals(ep.getName()) && "pay".equals(ep.getMethodName()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user