16
16
17
17
package org .springframework .ai .azure .openai .aot ;
18
18
19
+ import java .util .HashSet ;
19
20
import java .util .Set ;
20
21
21
22
import com .azure .ai .openai .OpenAIAsyncClient ;
22
23
import com .azure .ai .openai .OpenAIClient ;
23
24
import com .azure .ai .openai .models .ChatChoice ;
24
25
import org .junit .jupiter .api .Test ;
26
+ import org .junit .jupiter .api .BeforeEach ;
25
27
26
28
import org .springframework .ai .aot .AiRuntimeHints ;
27
29
import org .springframework .aot .hint .RuntimeHints ;
28
30
import org .springframework .aot .hint .TypeReference ;
31
+ import org .springframework .aot .hint .MemberCategory ;
29
32
30
33
import static org .assertj .core .api .AssertionsForClassTypes .assertThat ;
31
34
import static org .springframework .aot .hint .predicate .RuntimeHintsPredicates .reflection ;
32
35
import static org .springframework .aot .hint .predicate .RuntimeHintsPredicates .resource ;
33
36
34
37
class AzureOpenAiRuntimeHintsTests {
35
38
39
+ private RuntimeHints runtimeHints ;
40
+
41
+ private AzureOpenAiRuntimeHints azureOpenAiRuntimeHints ;
42
+
43
+ @ BeforeEach
44
+ void setUp () {
45
+ runtimeHints = new RuntimeHints ();
46
+ azureOpenAiRuntimeHints = new AzureOpenAiRuntimeHints ();
47
+ }
48
+
36
49
@ Test
37
50
void registerHints () {
38
- RuntimeHints runtimeHints = new RuntimeHints ();
39
- AzureOpenAiRuntimeHints openAiRuntimeHints = new AzureOpenAiRuntimeHints ();
40
- openAiRuntimeHints .registerHints (runtimeHints , null );
51
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
41
52
42
53
Set <TypeReference > azureModelTypes = AiRuntimeHints .findClassesInPackage (ChatChoice .class .getPackageName (),
43
54
(metadataReader , metadataReaderFactory ) -> true );
@@ -50,4 +61,112 @@ void registerHints() {
50
61
assertThat (runtimeHints ).matches (resource ().forResource ("/azure-ai-openai.properties" ));
51
62
}
52
63
64
+ @ Test
65
+ void registerHintsWithNullClassLoader () {
66
+ // Test that registering hints with null ClassLoader works correctly
67
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
68
+
69
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIClient .class ));
70
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIAsyncClient .class ));
71
+ assertThat (runtimeHints ).matches (resource ().forResource ("/azure-ai-openai.properties" ));
72
+ }
73
+
74
+ @ Test
75
+ void registerHintsWithCustomClassLoader () {
76
+ // Test that registering hints with a custom ClassLoader works correctly
77
+ ClassLoader customClassLoader = Thread .currentThread ().getContextClassLoader ();
78
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , customClassLoader );
79
+
80
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIClient .class ));
81
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIAsyncClient .class ));
82
+ assertThat (runtimeHints ).matches (resource ().forResource ("/azure-ai-openai.properties" ));
83
+ }
84
+
85
+ @ Test
86
+ void allMemberCategoriesAreRegisteredForAzureTypes () {
87
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
88
+
89
+ Set <TypeReference > azureModelTypes = AiRuntimeHints .findClassesInPackage (ChatChoice .class .getPackageName (),
90
+ (metadataReader , metadataReaderFactory ) -> true );
91
+
92
+ // Verify that all MemberCategory values are registered for Azure model types
93
+ runtimeHints .reflection ().typeHints ().forEach (typeHint -> {
94
+ if (azureModelTypes .contains (typeHint .getType ())) {
95
+ Set <MemberCategory > expectedCategories = Set .of (MemberCategory .values ());
96
+ Set <MemberCategory > actualCategories = typeHint .getMemberCategories ();
97
+ assertThat (actualCategories .containsAll (expectedCategories )).isTrue ();
98
+ }
99
+ });
100
+ }
101
+
102
+ @ Test
103
+ void verifySpecificAzureOpenAiClasses () {
104
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
105
+
106
+ // Verify specific Azure OpenAI classes are registered
107
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIClient .class ));
108
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIAsyncClient .class ));
109
+ assertThat (runtimeHints ).matches (reflection ().onType (ChatChoice .class ));
110
+ }
111
+
112
+ @ Test
113
+ void emptyRuntimeHintsInitiallyContainsNoTypes () {
114
+ // Verify that fresh RuntimeHints instance contains no reflection hints
115
+ RuntimeHints emptyHints = new RuntimeHints ();
116
+ Set <TypeReference > emptyRegisteredTypes = new HashSet <>();
117
+ emptyHints .reflection ().typeHints ().forEach (typeHint -> emptyRegisteredTypes .add (typeHint .getType ()));
118
+
119
+ assertThat (emptyRegisteredTypes .size ()).isEqualTo (0 );
120
+ }
121
+
122
+ @ Test
123
+ void multipleRegistrationCallsAreIdempotent () {
124
+ // Register hints multiple times and verify no duplicates
125
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
126
+ int firstRegistrationCount = (int ) runtimeHints .reflection ().typeHints ().count ();
127
+
128
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
129
+ int secondRegistrationCount = (int ) runtimeHints .reflection ().typeHints ().count ();
130
+
131
+ assertThat (firstRegistrationCount ).isEqualTo (secondRegistrationCount );
132
+
133
+ // Verify resource hint registration is also idempotent
134
+ assertThat (runtimeHints ).matches (resource ().forResource ("/azure-ai-openai.properties" ));
135
+ }
136
+
137
+ @ Test
138
+ void verifyAzureModelTypesInPackageIsNotEmpty () {
139
+ Set <TypeReference > azureModelTypes = AiRuntimeHints .findClassesInPackage (ChatChoice .class .getPackageName (),
140
+ (metadataReader , metadataReaderFactory ) -> true );
141
+ assertThat (azureModelTypes .size ()).isGreaterThan (0 );
142
+ }
143
+
144
+ @ Test
145
+ void verifyResourceHintIsRegistered () {
146
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
147
+
148
+ // Verify the specific resource hint is registered
149
+ assertThat (runtimeHints ).matches (resource ().forResource ("/azure-ai-openai.properties" ));
150
+ }
151
+
152
+ @ Test
153
+ void verifyAllRegisteredTypesHaveReflectionHints () {
154
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
155
+
156
+ // Ensure every registered type has proper reflection hints
157
+ runtimeHints .reflection ().typeHints ().forEach (typeHint -> {
158
+ assertThat (typeHint .getType ()).isNotNull ();
159
+ assertThat (typeHint .getMemberCategories ().size ()).isGreaterThan (0 );
160
+ });
161
+ }
162
+
163
+ @ Test
164
+ void verifyClientTypesAreRegistered () {
165
+ azureOpenAiRuntimeHints .registerHints (runtimeHints , null );
166
+
167
+ // Verify both sync and async client types are properly registered
168
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIClient .class ));
169
+ assertThat (runtimeHints ).matches (reflection ().onType (OpenAIAsyncClient .class ));
170
+ }
171
+
53
172
}
0 commit comments