Skip to content

Commit 2dcc29a

Browse files
alxkmsobychacko
authored andcommitted
test: Enhanced test coverage for OpenAiRuntimeHintsTests
Signed-off-by: Alex Klimenko <[email protected]>
1 parent 0ba1546 commit 2dcc29a

File tree

1 file changed

+130
-2
lines changed

1 file changed

+130
-2
lines changed

models/spring-ai-openai/src/test/java/org/springframework/ai/openai/aot/OpenAiRuntimeHintsTests.java

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,33 @@
2020
import java.util.Set;
2121

2222
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.BeforeEach;
2324

2425
import org.springframework.ai.openai.OpenAiChatOptions;
2526
import org.springframework.ai.openai.api.OpenAiApi;
2627
import org.springframework.ai.openai.api.OpenAiAudioApi;
2728
import org.springframework.ai.openai.api.OpenAiImageApi;
2829
import org.springframework.aot.hint.RuntimeHints;
2930
import org.springframework.aot.hint.TypeReference;
31+
import org.springframework.aot.hint.MemberCategory;
3032

3133
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
3234
import static org.springframework.ai.aot.AiRuntimeHints.findJsonAnnotatedClassesInPackage;
3335

3436
class OpenAiRuntimeHintsTests {
3537

38+
private RuntimeHints runtimeHints;
39+
40+
private OpenAiRuntimeHints openAiRuntimeHints;
41+
42+
@BeforeEach
43+
void setUp() {
44+
runtimeHints = new RuntimeHints();
45+
openAiRuntimeHints = new OpenAiRuntimeHints();
46+
}
47+
3648
@Test
3749
void registerHints() {
38-
RuntimeHints runtimeHints = new RuntimeHints();
39-
OpenAiRuntimeHints openAiRuntimeHints = new OpenAiRuntimeHints();
4050
openAiRuntimeHints.registerHints(runtimeHints, null);
4151

4252
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage("org.springframework.ai.openai");
@@ -61,4 +71,122 @@ void registerHints() {
6171
assertThat(registeredTypes.contains(TypeReference.of(OpenAiChatOptions.class))).isTrue();
6272
}
6373

74+
@Test
75+
void registerHintsWithNullClassLoader() {
76+
// Test that registering hints with null ClassLoader works correctly
77+
openAiRuntimeHints.registerHints(runtimeHints, null);
78+
79+
Set<TypeReference> registeredTypes = new HashSet<>();
80+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
81+
82+
assertThat(registeredTypes.size()).isGreaterThan(0);
83+
}
84+
85+
@Test
86+
void registerHintsWithCustomClassLoader() {
87+
// Test that registering hints with a custom ClassLoader works correctly
88+
ClassLoader customClassLoader = Thread.currentThread().getContextClassLoader();
89+
openAiRuntimeHints.registerHints(runtimeHints, customClassLoader);
90+
91+
Set<TypeReference> registeredTypes = new HashSet<>();
92+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
93+
94+
assertThat(registeredTypes.size()).isGreaterThan(0);
95+
}
96+
97+
@Test
98+
void allMemberCategoriesAreRegistered() {
99+
openAiRuntimeHints.registerHints(runtimeHints, null);
100+
101+
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage("org.springframework.ai.openai");
102+
103+
// Verify that all MemberCategory values are registered for each type
104+
runtimeHints.reflection().typeHints().forEach(typeHint -> {
105+
if (jsonAnnotatedClasses.contains(typeHint.getType())) {
106+
Set<MemberCategory> expectedCategories = Set.of(MemberCategory.values());
107+
Set<MemberCategory> actualCategories = typeHint.getMemberCategories();
108+
assertThat(actualCategories.containsAll(expectedCategories)).isTrue();
109+
}
110+
});
111+
}
112+
113+
@Test
114+
void verifySpecificOpenAiApiClasses() {
115+
openAiRuntimeHints.registerHints(runtimeHints, null);
116+
117+
Set<TypeReference> registeredTypes = new HashSet<>();
118+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
119+
120+
// Verify specific OpenAI API classes are registered
121+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiApi.class))).isTrue();
122+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiAudioApi.class))).isTrue();
123+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiImageApi.class))).isTrue();
124+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiChatOptions.class))).isTrue();
125+
}
126+
127+
@Test
128+
void emptyRuntimeHintsInitiallyContainsNoTypes() {
129+
// Verify that fresh RuntimeHints instance contains no reflection hints
130+
RuntimeHints emptyHints = new RuntimeHints();
131+
Set<TypeReference> emptyRegisteredTypes = new HashSet<>();
132+
emptyHints.reflection().typeHints().forEach(typeHint -> emptyRegisteredTypes.add(typeHint.getType()));
133+
134+
assertThat(emptyRegisteredTypes.size()).isEqualTo(0);
135+
}
136+
137+
@Test
138+
void multipleRegistrationCallsAreIdempotent() {
139+
// Register hints multiple times and verify no duplicates
140+
openAiRuntimeHints.registerHints(runtimeHints, null);
141+
int firstRegistrationCount = (int) runtimeHints.reflection().typeHints().count();
142+
143+
openAiRuntimeHints.registerHints(runtimeHints, null);
144+
int secondRegistrationCount = (int) runtimeHints.reflection().typeHints().count();
145+
146+
assertThat(firstRegistrationCount).isEqualTo(secondRegistrationCount);
147+
}
148+
149+
@Test
150+
void verifyJsonAnnotatedClassesInPackageIsNotEmpty() {
151+
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage("org.springframework.ai.openai");
152+
assertThat(jsonAnnotatedClasses.size()).isGreaterThan(0);
153+
}
154+
155+
@Test
156+
void verifyAllRegisteredTypesHaveReflectionHints() {
157+
openAiRuntimeHints.registerHints(runtimeHints, null);
158+
159+
// Ensure every registered type has proper reflection hints
160+
runtimeHints.reflection().typeHints().forEach(typeHint -> {
161+
assertThat(typeHint.getType()).isNotNull();
162+
assertThat(typeHint.getMemberCategories().size()).isGreaterThan(0);
163+
});
164+
}
165+
166+
@Test
167+
void verifyEnumTypesAreRegistered() {
168+
openAiRuntimeHints.registerHints(runtimeHints, null);
169+
170+
Set<TypeReference> registeredTypes = new HashSet<>();
171+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
172+
173+
// Verify enum types are properly registered
174+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiApi.ChatCompletionFinishReason.class))).isTrue();
175+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiApi.OutputModality.class))).isTrue();
176+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiAudioApi.TtsModel.class))).isTrue();
177+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiAudioApi.WhisperModel.class))).isTrue();
178+
}
179+
180+
@Test
181+
void verifyNestedClassesAreRegistered() {
182+
openAiRuntimeHints.registerHints(runtimeHints, null);
183+
184+
Set<TypeReference> registeredTypes = new HashSet<>();
185+
runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType()));
186+
187+
// Verify nested classes are properly registered
188+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiApi.FunctionTool.class))).isTrue();
189+
assertThat(registeredTypes.contains(TypeReference.of(OpenAiApi.FunctionTool.Function.class))).isTrue();
190+
}
191+
64192
}

0 commit comments

Comments
 (0)