Skip to content

Commit f7e6b34

Browse files
authored
test: Add comprehensive edge case and validation tests for runtime hints registration (#4028)
Adds 4 targeted test cases to strengthen runtime hints functionality across multiple components: - ToolRuntimeHintsTests: Null ClassLoader handling - Ensures tool hints registration doesn't fail when ClassLoader parameter is null (common in AOT processing) - AiRuntimeHintsTests: Record validation - Confirms records with @JsonProperty parameters are properly discovered for hint registration Enum validation - Verifies enums with @JsonInclude annotations are correctly identified for reflection hints - JdbcChatMemoryRepositoryRuntimeHintsTest: Null ClassLoader robustness - Validates JDBC chat memory hints registration handles null ClassLoader gracefully These tests prevent runtime failures in native images by ensuring proper discovery of JSON-annotated classes (records/enums), robust hint registration under various ClassLoader conditions, and reliable chat memory persistence in GraalVM environments. Signed-off-by: Alex Klimenko <[email protected]>
1 parent 879350a commit f7e6b34

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/aot/hint/JdbcChatMemoryRepositoryRuntimeHintsTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.core.io.support.SpringFactoriesLoader;
3535

3636
import static org.assertj.core.api.Assertions.assertThat;
37+
import static org.assertj.core.api.Assertions.assertThatNoException;
3738

3839
/**
3940
* @author Jonathan Leijendekker
@@ -72,6 +73,12 @@ void dataSourceHasHints() {
7273
assertThat(RuntimeHintsPredicates.reflection().onType(DataSource.class)).accepts(this.hints);
7374
}
7475

76+
@Test
77+
void registerHintsWithNullClassLoader() {
78+
assertThatNoException()
79+
.isThrownBy(() -> this.jdbcChatMemoryRepositoryRuntimeHints.registerHints(this.hints, null));
80+
}
81+
7582
private static Stream<String> getSchemaFileNames() throws IOException {
7683
var resources = new PathMatchingResourcePatternResolver()
7784
.getResources("classpath*:org/springframework/ai/chat/memory/repository/jdbc/schema-*.sql");

spring-ai-model/src/test/java/org/springframework/ai/aot/AiRuntimeHintsTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
import org.springframework.aot.hint.TypeReference;
2828
import org.springframework.util.Assert;
2929

30+
import static org.assertj.core.api.Assertions.assertThat;
31+
3032
class AiRuntimeHintsTests {
3133

3234
@Test
33-
void discoverRelevantClasses() throws Exception {
35+
void discoverRelevantClasses() {
3436
var classes = AiRuntimeHints.findJsonAnnotatedClassesInPackage(TestApi.class);
3537
var included = Set.of(TestApi.Bar.class, TestApi.Foo.class)
3638
.stream()
@@ -40,6 +42,24 @@ void discoverRelevantClasses() throws Exception {
4042
Assert.state(classes.containsAll(included), "there should be all of the enumerated classes. ");
4143
}
4244

45+
@Test
46+
void verifyRecordWithJsonPropertyIncluded() {
47+
var classes = AiRuntimeHints.findJsonAnnotatedClassesInPackage(TestApi.class);
48+
49+
// Foo record should be included due to @JsonProperty on parameter
50+
var recordClass = TypeReference.of(TestApi.Foo.class.getName());
51+
assertThat(classes).contains(recordClass);
52+
}
53+
54+
@Test
55+
void verifyEnumWithJsonIncludeAnnotation() {
56+
var classes = AiRuntimeHints.findJsonAnnotatedClassesInPackage(TestApi.class);
57+
58+
// Bar enum should be included due to @JsonInclude
59+
var enumClass = TypeReference.of(TestApi.Bar.class.getName());
60+
assertThat(classes).contains(enumClass);
61+
}
62+
4363
@JsonInclude
4464
static class TestApi {
4565

spring-ai-model/src/test/java/org/springframework/ai/aot/ToolRuntimeHintsTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.aot.hint.RuntimeHints;
2323

2424
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
25+
import static org.assertj.core.api.Assertions.assertThatCode;
2526
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
2627

2728
/**
@@ -37,4 +38,13 @@ void registerHints() {
3738
assertThat(runtimeHints).matches(reflection().onType(DefaultToolCallResultConverter.class));
3839
}
3940

41+
@Test
42+
void registerHintsWithNullClassLoader() {
43+
RuntimeHints runtimeHints = new RuntimeHints();
44+
ToolRuntimeHints toolRuntimeHints = new ToolRuntimeHints();
45+
46+
// Should not throw exception with null ClassLoader
47+
assertThatCode(() -> toolRuntimeHints.registerHints(runtimeHints, null)).doesNotThrowAnyException();
48+
}
49+
4050
}

0 commit comments

Comments
 (0)