Skip to content

Commit d61f23f

Browse files
Copilotphrocker
andcommitted
Complete endpoint scanning integration and testing
Co-authored-by: phrocker <[email protected]>
1 parent 3395238 commit d61f23f

File tree

3 files changed

+239
-0
lines changed

3 files changed

+239
-0
lines changed

ai-agent/src/main/java/io/sentrius/agent/analysis/agents/agents/VerbRegistry.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import io.github.classgraph.ClassGraph;
44
import io.github.classgraph.ScanResult;
5+
import io.sentrius.sso.core.dto.capabilities.EndpointDescriptor;
56
import io.sentrius.sso.core.dto.ztat.AgentExecution;
67
import io.sentrius.sso.core.dto.ztat.ZtatRequestDTO;
78
import io.sentrius.sso.core.exceptions.ZtatException;
89
import io.sentrius.sso.core.model.verbs.OutputInterpreterIfc;
910
import io.sentrius.sso.core.model.verbs.Verb;
1011
import io.sentrius.sso.core.model.verbs.VerbResponse;
1112
import io.sentrius.sso.core.services.agents.ZeroTrustClientService;
13+
import io.sentrius.sso.core.services.capabilities.EndpointScanningService;
1214
import lombok.RequiredArgsConstructor;
1315
import lombok.extern.slf4j.Slf4j;
1416
import org.springframework.context.ApplicationContext;
@@ -18,8 +20,10 @@
1820
import java.lang.reflect.InvocationTargetException;
1921
import java.lang.reflect.Method;
2022
import java.util.HashMap;
23+
import java.util.List;
2124
import java.util.Map;
2225
import java.util.concurrent.TimeUnit;
26+
import java.util.stream.Collectors;
2327

2428
@Slf4j
2529
@Component
@@ -29,6 +33,8 @@ public class VerbRegistry {
2933
private final ApplicationContext applicationContext;
3034

3135
private final ZeroTrustClientService zeroTrustClientService;
36+
37+
private final EndpointScanningService endpointScanningService;
3238

3339
private final Map<String, AgentVerb> verbs = new HashMap<>();
3440
private final Map<String, Object> instances = new HashMap<>();
@@ -167,4 +173,30 @@ public VerbResponse execute(AgentExecution agentExecution, VerbResponse priorRes
167173
public Map<String, AgentVerb> getVerbs() {
168174
return new HashMap<>(verbs);
169175
}
176+
177+
/**
178+
* Gets endpoint descriptors for all registered verbs.
179+
* This provides integration with the centralized endpoint scanning system.
180+
*/
181+
public List<EndpointDescriptor> getVerbDescriptors() {
182+
return endpointScanningService.getAllEndpoints()
183+
.stream()
184+
.filter(endpoint -> "VERB".equals(endpoint.getType()))
185+
.filter(endpoint -> verbs.containsKey(endpoint.getName()))
186+
.collect(Collectors.toList());
187+
}
188+
189+
/**
190+
* Gets all available AI-callable verb descriptors.
191+
* This can be used by agents to understand what capabilities are available.
192+
*/
193+
public List<EndpointDescriptor> getAiCallableVerbDescriptors() {
194+
return getVerbDescriptors()
195+
.stream()
196+
.filter(endpoint -> {
197+
Boolean isAiCallable = (Boolean) endpoint.getMetadata().get("isAiCallable");
198+
return isAiCallable != null && isAiCallable;
199+
})
200+
.collect(Collectors.toList());
201+
}
170202
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package io.sentrius.sso.controllers.api;
2+
3+
import io.sentrius.sso.core.dto.capabilities.EndpointDescriptor;
4+
import io.sentrius.sso.core.services.capabilities.EndpointScanningService;
5+
import org.junit.jupiter.api.Test;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.test.context.TestPropertySource;
9+
10+
import java.util.List;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
14+
/**
15+
* Integration test for CapabilitiesApiController.
16+
* This test runs with the full Spring context to verify that endpoint scanning works correctly.
17+
*/
18+
@SpringBootTest
19+
@TestPropertySource(properties = {
20+
"spring.datasource.url=jdbc:h2:mem:testdb",
21+
"spring.jpa.hibernate.ddl-auto=create-drop"
22+
})
23+
public class CapabilitiesApiControllerIntegrationTest {
24+
25+
@Autowired
26+
private EndpointScanningService endpointScanningService;
27+
28+
@Test
29+
public void testEndpointScanning() {
30+
// When
31+
List<EndpointDescriptor> allEndpoints = endpointScanningService.getAllEndpoints();
32+
33+
// Then
34+
assertNotNull(allEndpoints);
35+
36+
System.out.println("=== ENDPOINT SCANNING RESULTS ===");
37+
System.out.println("Total endpoints found: " + allEndpoints.size());
38+
39+
// Count by type
40+
long restCount = allEndpoints.stream().filter(e -> "REST".equals(e.getType())).count();
41+
long verbCount = allEndpoints.stream().filter(e -> "VERB".equals(e.getType())).count();
42+
43+
System.out.println("REST endpoints: " + restCount);
44+
System.out.println("VERB endpoints: " + verbCount);
45+
46+
// Print first 10 endpoints for inspection
47+
System.out.println("\n=== SAMPLE ENDPOINTS ===");
48+
allEndpoints.stream().limit(10).forEach(endpoint -> {
49+
System.out.println(String.format("%s: %s [%s] - %s",
50+
endpoint.getType(),
51+
endpoint.getName(),
52+
endpoint.getHttpMethod() != null ? endpoint.getHttpMethod() + " " + endpoint.getPath() : "N/A",
53+
endpoint.getDescription()));
54+
});
55+
56+
// Verify we found some endpoints
57+
assertTrue(allEndpoints.size() > 0, "Should have found some endpoints in full Spring context");
58+
59+
// Verify we found some REST endpoints (from the API controllers)
60+
assertTrue(restCount > 0, "Should have found REST endpoints from API controllers");
61+
62+
// Look for our new capabilities endpoint
63+
boolean foundCapabilitiesEndpoint = allEndpoints.stream()
64+
.anyMatch(e -> "REST".equals(e.getType()) &&
65+
e.getPath() != null &&
66+
e.getPath().contains("/api/v1/capabilities"));
67+
68+
assertTrue(foundCapabilitiesEndpoint, "Should have found our new capabilities endpoint");
69+
70+
// Look for some existing endpoints
71+
boolean foundUserApiEndpoint = allEndpoints.stream()
72+
.anyMatch(e -> "REST".equals(e.getType()) &&
73+
e.getClassName().contains("UserApiController"));
74+
75+
assertTrue(foundUserApiEndpoint, "Should have found UserApiController endpoints");
76+
}
77+
78+
@Test
79+
public void testEndpointFiltering() {
80+
// When
81+
List<EndpointDescriptor> allEndpoints = endpointScanningService.getAllEndpoints();
82+
83+
// Filter REST endpoints
84+
List<EndpointDescriptor> restEndpoints = allEndpoints.stream()
85+
.filter(e -> "REST".equals(e.getType()))
86+
.toList();
87+
88+
// Filter VERB endpoints
89+
List<EndpointDescriptor> verbEndpoints = allEndpoints.stream()
90+
.filter(e -> "VERB".equals(e.getType()))
91+
.toList();
92+
93+
// Then
94+
System.out.println("\n=== FILTERING TEST ===");
95+
System.out.println("Total: " + allEndpoints.size());
96+
System.out.println("REST only: " + restEndpoints.size());
97+
System.out.println("VERB only: " + verbEndpoints.size());
98+
99+
assertEquals(allEndpoints.size(), restEndpoints.size() + verbEndpoints.size(),
100+
"Total should equal sum of REST and VERB endpoints");
101+
102+
// Verify REST endpoints have paths
103+
restEndpoints.forEach(endpoint -> {
104+
assertNotNull(endpoint.getPath(), "REST endpoint should have a path");
105+
assertNotNull(endpoint.getHttpMethod(), "REST endpoint should have HTTP method");
106+
});
107+
}
108+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package io.sentrius.sso.core.services.capabilities;
2+
3+
import io.sentrius.sso.core.dto.capabilities.EndpointDescriptor;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.Test;
6+
import org.mockito.Mock;
7+
import org.mockito.MockitoAnnotations;
8+
import org.springframework.context.ApplicationContext;
9+
10+
import java.util.List;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
14+
/**
15+
* Test class for EndpointScanningService.
16+
* Validates that the service can discover both REST endpoints and Verb methods.
17+
*/
18+
public class EndpointScanningServiceTest {
19+
20+
@Mock
21+
private ApplicationContext applicationContext;
22+
23+
private EndpointScanningService endpointScanningService;
24+
25+
@BeforeEach
26+
void setUp() {
27+
MockitoAnnotations.openMocks(this);
28+
endpointScanningService = new EndpointScanningService(applicationContext);
29+
}
30+
31+
@Test
32+
void testGetAllEndpoints() {
33+
// When
34+
List<EndpointDescriptor> endpoints = endpointScanningService.getAllEndpoints();
35+
36+
// Then
37+
assertNotNull(endpoints);
38+
System.out.println("Found " + endpoints.size() + " endpoints");
39+
40+
// Log some information about what was found
41+
long restCount = endpoints.stream().filter(e -> "REST".equals(e.getType())).count();
42+
long verbCount = endpoints.stream().filter(e -> "VERB".equals(e.getType())).count();
43+
44+
System.out.println("Found " + restCount + " REST endpoints and " + verbCount + " VERB endpoints");
45+
46+
// Print first few endpoints for inspection
47+
endpoints.stream().limit(10).forEach(endpoint -> {
48+
System.out.println("Endpoint: " + endpoint.getName() +
49+
" (Type: " + endpoint.getType() +
50+
", Class: " + endpoint.getClassName() + ")");
51+
});
52+
53+
// In a test environment, we might not have full Spring context loaded,
54+
// so the test is mainly to verify the service doesn't crash
55+
// The real validation will be done when the service runs in the full application
56+
}
57+
58+
@Test
59+
void testRefreshEndpoints() {
60+
// Given - get initial count
61+
List<EndpointDescriptor> initialEndpoints = endpointScanningService.getAllEndpoints();
62+
int initialCount = initialEndpoints.size();
63+
64+
// When - refresh
65+
endpointScanningService.refreshEndpoints();
66+
List<EndpointDescriptor> refreshedEndpoints = endpointScanningService.getAllEndpoints();
67+
68+
// Then - should have same count (since we're not loading new classes in test environment)
69+
assertEquals(initialCount, refreshedEndpoints.size(),
70+
"Refresh should maintain endpoint count in test environment");
71+
}
72+
73+
@Test
74+
void testEndpointDescriptorStructure() {
75+
// When
76+
List<EndpointDescriptor> endpoints = endpointScanningService.getAllEndpoints();
77+
78+
// Then - verify structure of endpoints
79+
for (EndpointDescriptor endpoint : endpoints) {
80+
assertNotNull(endpoint.getName(), "Endpoint name should not be null");
81+
assertNotNull(endpoint.getType(), "Endpoint type should not be null");
82+
assertNotNull(endpoint.getClassName(), "Endpoint class name should not be null");
83+
assertNotNull(endpoint.getMethodName(), "Endpoint method name should not be null");
84+
85+
assertTrue(endpoint.getType().equals("REST") || endpoint.getType().equals("VERB"),
86+
"Endpoint type should be REST or VERB");
87+
88+
if ("REST".equals(endpoint.getType())) {
89+
assertNotNull(endpoint.getHttpMethod(), "REST endpoint should have HTTP method");
90+
assertNotNull(endpoint.getPath(), "REST endpoint should have path");
91+
}
92+
93+
if ("VERB".equals(endpoint.getType()) && endpoint.getMetadata() != null) {
94+
assertTrue(endpoint.getMetadata().containsKey("isAiCallable"),
95+
"VERB endpoint should have isAiCallable metadata");
96+
}
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)