Skip to content

Commit 74e6417

Browse files
alxkmspring-builds
authored andcommitted
test: Add comprehensive runtime hints validation for Ollama GraalVM native image support (#4418)
Fixes #4418 Signed-off-by: Oleksandr Klymenko <[email protected]> (cherry picked from commit 17b9211)
1 parent d2fc62e commit 74e6417

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/aot/OllamaRuntimeHintsTests.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,95 @@ void registerHints() {
5353
assertThat(registeredTypes.contains(TypeReference.of(OllamaOptions.class))).isTrue();
5454
}
5555

56+
@Test
57+
void verifyNoProxyHintsAreRegistered() {
58+
RuntimeHints runtimeHints = new RuntimeHints();
59+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
60+
ollamaRuntimeHints.registerHints(runtimeHints, null);
61+
62+
// Ollama should only register reflection hints, not proxy hints
63+
assertThat(runtimeHints.proxies().jdkProxyHints().count()).isEqualTo(0);
64+
}
65+
66+
@Test
67+
void verifyNoSerializationHintsAreRegistered() {
68+
RuntimeHints runtimeHints = new RuntimeHints();
69+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
70+
ollamaRuntimeHints.registerHints(runtimeHints, null);
71+
72+
// Ollama should only register reflection hints, not serialization hints
73+
assertThat(runtimeHints.serialization().javaSerializationHints().count()).isEqualTo(0);
74+
}
75+
76+
@Test
77+
void verifyConstructorHintsAreRegistered() {
78+
RuntimeHints runtimeHints = new RuntimeHints();
79+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
80+
ollamaRuntimeHints.registerHints(runtimeHints, null);
81+
82+
// Verify that reflection hints include constructor access for JSON
83+
// deserialization
84+
boolean hasConstructorHints = runtimeHints.reflection()
85+
.typeHints()
86+
.anyMatch(typeHint -> typeHint.constructors().findAny().isPresent() || typeHint.getMemberCategories()
87+
.contains(org.springframework.aot.hint.MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
88+
89+
assertThat(hasConstructorHints).as("Should register constructor hints for JSON deserialization").isTrue();
90+
}
91+
92+
@Test
93+
void verifyEnumTypesAreRegistered() {
94+
RuntimeHints runtimeHints = new RuntimeHints();
95+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
96+
ollamaRuntimeHints.registerHints(runtimeHints, null);
97+
98+
Set<TypeReference> registeredTypes = new HashSet<>();
99+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
100+
101+
// Verify enum types are registered (critical for JSON deserialization)
102+
boolean hasEnumTypes = registeredTypes.stream()
103+
.anyMatch(tr -> tr.getName().contains("$") || tr.getName().toLowerCase().contains("role")
104+
|| tr.getName().toLowerCase().contains("type"));
105+
106+
assertThat(hasEnumTypes).as("Enum types should be registered for native image compatibility").isTrue();
107+
}
108+
109+
@Test
110+
void verifyResponseTypesAreRegistered() {
111+
RuntimeHints runtimeHints = new RuntimeHints();
112+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
113+
ollamaRuntimeHints.registerHints(runtimeHints, null);
114+
115+
Set<TypeReference> registeredTypes = new HashSet<>();
116+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
117+
118+
// Verify response wrapper types are registered
119+
assertThat(registeredTypes.stream().anyMatch(tr -> tr.getName().contains("Response")))
120+
.as("Response types should be registered")
121+
.isTrue();
122+
123+
assertThat(registeredTypes.stream().anyMatch(tr -> tr.getName().contains("ChatResponse")))
124+
.as("ChatResponse type should be registered")
125+
.isTrue();
126+
}
127+
128+
@Test
129+
void verifyToolRelatedClassesAreRegistered() {
130+
RuntimeHints runtimeHints = new RuntimeHints();
131+
OllamaRuntimeHints ollamaRuntimeHints = new OllamaRuntimeHints();
132+
ollamaRuntimeHints.registerHints(runtimeHints, null);
133+
134+
Set<TypeReference> registeredTypes = new HashSet<>();
135+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
136+
137+
// Verify tool-related classes are registered
138+
assertThat(registeredTypes.contains(TypeReference.of(OllamaApi.ChatRequest.Tool.class))).isTrue();
139+
140+
// Count tool-related classes
141+
long toolClassCount = registeredTypes.stream()
142+
.filter(typeRef -> typeRef.getName().toLowerCase().contains("tool"))
143+
.count();
144+
assertThat(toolClassCount).isGreaterThan(0);
145+
}
146+
56147
}

0 commit comments

Comments
 (0)