1
+ using System . Text . Json ;
2
+
3
+ using AzureOpenAIProxy . AppHost . Tests . Fixtures ;
4
+
5
+ using FluentAssertions ;
6
+
7
+ using IdentityModel . Client ;
8
+
9
+ namespace AzureOpenAIProxy . AppHost . Tests . ApiApp . Endpoints ;
10
+
11
+ public class AdminCreateResourcesOpenApiTests ( AspireAppHostFixture host ) : IClassFixture < AspireAppHostFixture >
12
+ {
13
+ [ Fact ]
14
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path ( )
15
+ {
16
+ // Arrange
17
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
18
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
19
+
20
+ // Act
21
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
22
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
23
+
24
+ // Assert
25
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
26
+ . GetProperty ( "/admin/resources" ) ;
27
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
28
+ }
29
+
30
+ [ Fact ]
31
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Verb ( )
32
+ {
33
+ // Arrange
34
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
35
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
36
+
37
+ // Act
38
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
39
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
40
+
41
+ // Assert
42
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
43
+ . GetProperty ( "/admin/resources" )
44
+ . GetProperty ( "post" ) ;
45
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
46
+ }
47
+
48
+ [ Theory ]
49
+ [ InlineData ( "admin" ) ]
50
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tags ( string tag )
51
+ {
52
+ // Arrange
53
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
54
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
55
+
56
+ // Act
57
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
58
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
59
+
60
+ // Assert
61
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
62
+ . GetProperty ( "/admin/resources" )
63
+ . GetProperty ( "post" )
64
+ . GetProperty ( "tags" ) ;
65
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Array ) ;
66
+ result . EnumerateArray ( ) . Select ( p => p . GetString ( ) ) . Should ( ) . Contain ( tag ) ;
67
+ }
68
+
69
+ [ Theory ]
70
+ [ InlineData ( "summary" ) ]
71
+ [ InlineData ( "description" ) ]
72
+ [ InlineData ( "operationId" ) ]
73
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Value ( string attribute )
74
+ {
75
+ // Arrange
76
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
77
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
78
+
79
+ // Act
80
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
81
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
82
+
83
+ // Assert
84
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
85
+ . GetProperty ( "/admin/resources" )
86
+ . GetProperty ( "post" )
87
+ . GetProperty ( attribute ) ;
88
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . String ) ;
89
+ }
90
+
91
+ [ Theory ]
92
+ [ InlineData ( "requestBody" ) ]
93
+ [ InlineData ( "responses" ) ]
94
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Object ( string attribute )
95
+ {
96
+ // Arrange
97
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
98
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
99
+
100
+ // Act
101
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
102
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
103
+
104
+ // Assert
105
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
106
+ . GetProperty ( "/admin/resources" )
107
+ . GetProperty ( "post" )
108
+ . GetProperty ( attribute ) ;
109
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
110
+ }
111
+
112
+ [ Theory ]
113
+ [ InlineData ( "200" ) ]
114
+ [ InlineData ( "400" ) ]
115
+ [ InlineData ( "401" ) ]
116
+ [ InlineData ( "500" ) ]
117
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response ( string attribute )
118
+ {
119
+ // Arrange
120
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
121
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
122
+
123
+ // Act
124
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
125
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
126
+
127
+ // Assert
128
+ var result = openapi ! . RootElement . GetProperty ( "paths" )
129
+ . GetProperty ( "/admin/resources" )
130
+ . GetProperty ( "post" )
131
+ . GetProperty ( "responses" )
132
+ . GetProperty ( attribute ) ;
133
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
134
+ }
135
+
136
+ [ Fact ]
137
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Schemas ( )
138
+ {
139
+ // Arrange
140
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
141
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
142
+
143
+ // Act
144
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
145
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
146
+
147
+ // Assert
148
+ var result = openapi ! . RootElement . GetProperty ( "components" )
149
+ . GetProperty ( "schemas" ) ;
150
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
151
+ }
152
+
153
+ [ Fact ]
154
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Model ( )
155
+ {
156
+ // Arrange
157
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
158
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
159
+
160
+ // Act
161
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
162
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
163
+
164
+ // Assert
165
+ var result = openapi ! . RootElement . GetProperty ( "components" )
166
+ . GetProperty ( "schemas" )
167
+ . GetProperty ( "AdminResourceDetails" ) ;
168
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
169
+ }
170
+
171
+ [ Theory ]
172
+ [ InlineData ( "resourceId" , true ) ]
173
+ [ InlineData ( "friendlyName" , true ) ]
174
+ [ InlineData ( "deploymentName" , true ) ]
175
+ [ InlineData ( "resourceType" , true ) ]
176
+ [ InlineData ( "endpoint" , true ) ]
177
+ [ InlineData ( "apiKey" , true ) ]
178
+ [ InlineData ( "region" , true ) ]
179
+ [ InlineData ( "isActive" , true ) ]
180
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Required ( string attribute , bool isRequired )
181
+ {
182
+ // Arrange
183
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
184
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
185
+
186
+ // Act
187
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
188
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
189
+
190
+ // Assert
191
+ var result = openapi ! . RootElement . GetProperty ( "components" )
192
+ . GetProperty ( "schemas" )
193
+ . GetProperty ( "AdminResourceDetails" )
194
+ . TryGetStringArray ( "required" )
195
+ . ToList ( ) ;
196
+ result . Contains ( attribute ) . Should ( ) . Be ( isRequired ) ;
197
+ }
198
+
199
+ [ Theory ]
200
+ [ InlineData ( "resourceId" ) ]
201
+ [ InlineData ( "friendlyName" ) ]
202
+ [ InlineData ( "deploymentName" ) ]
203
+ [ InlineData ( "resourceType" ) ]
204
+ [ InlineData ( "endpoint" ) ]
205
+ [ InlineData ( "apiKey" ) ]
206
+ [ InlineData ( "region" ) ]
207
+ [ InlineData ( "isActive" ) ]
208
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Property ( string attribute )
209
+ {
210
+ // Arrange
211
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
212
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
213
+
214
+ // Act
215
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
216
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
217
+
218
+ // Assert
219
+ var result = openapi ! . RootElement . GetProperty ( "components" )
220
+ . GetProperty ( "schemas" )
221
+ . GetProperty ( "AdminResourceDetails" )
222
+ . GetProperty ( "properties" )
223
+ . GetProperty ( attribute ) ;
224
+ result . ValueKind . Should ( ) . Be ( JsonValueKind . Object ) ;
225
+ }
226
+
227
+ [ Theory ]
228
+ [ InlineData ( "resourceId" , "string" ) ]
229
+ [ InlineData ( "friendlyName" , "string" ) ]
230
+ [ InlineData ( "deploymentName" , "string" ) ]
231
+ [ InlineData ( "resourceType" , "string" ) ]
232
+ [ InlineData ( "endpoint" , "string" ) ]
233
+ [ InlineData ( "apiKey" , "string" ) ]
234
+ [ InlineData ( "region" , "string" ) ]
235
+ [ InlineData ( "isActive" , "boolean" ) ]
236
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Type ( string attribute , string type )
237
+ {
238
+ // Arrange
239
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
240
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
241
+
242
+ // Act
243
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
244
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
245
+
246
+ // Assert
247
+ var result = openapi ! . RootElement . GetProperty ( "components" )
248
+ . GetProperty ( "schemas" )
249
+ . GetProperty ( "AdminResourceDetails" )
250
+ . GetProperty ( "properties" )
251
+ . GetProperty ( attribute ) ;
252
+
253
+ if ( ! result . TryGetProperty ( "type" , out var typeProperty ) )
254
+ {
255
+ var refPath = result . TryGetString ( "$ref" ) . TrimStart ( '#' , '/' ) . Split ( '/' ) ;
256
+ var refSchema = openapi . RootElement ;
257
+
258
+ foreach ( var part in refPath )
259
+ {
260
+ refSchema = refSchema . GetProperty ( part ) ;
261
+ }
262
+
263
+ typeProperty = refSchema . GetProperty ( "type" ) ;
264
+ }
265
+
266
+ typeProperty . GetString ( ) . Should ( ) . Be ( type ) ;
267
+ }
268
+
269
+ [ Fact ]
270
+ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Validate_ResourceType_As_Enum ( )
271
+ {
272
+ // Arrange
273
+ using var httpClient = host . App ! . CreateHttpClient ( "apiapp" ) ;
274
+ await host . ResourceNotificationService . WaitForResourceAsync ( "apiapp" , KnownResourceStates . Running ) . WaitAsync ( TimeSpan . FromSeconds ( 30 ) ) ;
275
+
276
+ // Act
277
+ var json = await httpClient . GetStringAsync ( "/swagger/v1.0.0/swagger.json" ) ;
278
+ var openapi = JsonSerializer . Deserialize < JsonDocument > ( json ) ;
279
+
280
+ // Assert
281
+ var result = openapi ! . RootElement . GetProperty ( "components" )
282
+ . GetProperty ( "schemas" )
283
+ . GetProperty ( "AdminResourceDetails" )
284
+ . GetProperty ( "properties" )
285
+ . GetProperty ( "resourceType" ) ;
286
+
287
+ var refPath = result . TryGetString ( "$ref" ) . TrimStart ( '#' , '/' ) . Split ( '/' ) ;
288
+ var refSchema = openapi . RootElement ;
289
+
290
+ foreach ( var part in refPath )
291
+ {
292
+ refSchema = refSchema . GetProperty ( part ) ;
293
+ }
294
+
295
+ var enumValues = refSchema . GetProperty ( "enum" )
296
+ . EnumerateArray ( )
297
+ . Select ( p => p . GetString ( ) )
298
+ . ToList ( ) ;
299
+
300
+ enumValues . Should ( ) . BeEquivalentTo ( [ "none" , "chat" , "image" ] ) ;
301
+ }
302
+ }
0 commit comments