1- using Azure . Security . KeyVault . Secrets ;
1+ using Azure ;
2+ using Azure . Data . Tables ;
3+ using Azure . Security . KeyVault . Secrets ;
24
35using AzureOpenAIProxy . ApiApp . Extensions ;
46
79using Microsoft . Extensions . Configuration ;
810using Microsoft . Extensions . DependencyInjection ;
911
12+ using NSubstitute ;
13+
1014namespace AzureOpenAIProxy . ApiApp . Tests . Extensions ;
1115
1216public class ServiceCollectionExtensionsTests
@@ -206,4 +210,157 @@ public void Given_AppSettings_When_Invoked_AddKeyVaultService_Then_It_Should_Ret
206210 // Assert
207211 result ? . VaultUri . Should ( ) . BeEquivalentTo ( expected ) ;
208212 }
209- }
213+
214+ [ Fact ]
215+ public void Given_ServiceCollection_When_Invoked_AddTableStorageService_Then_It_Should_Contain_TableServiceClient ( )
216+ {
217+ // Arrange
218+ var services = new ServiceCollection ( ) ;
219+
220+ // Act
221+ services . AddTableStorageService ( ) ;
222+
223+ // Assert
224+ services . SingleOrDefault ( p => p . ServiceType == typeof ( TableServiceClient ) ) . Should ( ) . NotBeNull ( ) ;
225+ }
226+
227+ [ Fact ]
228+ public void Given_ServiceCollection_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception ( )
229+ {
230+ // Arrange
231+ var services = new ServiceCollection ( ) ;
232+ services . AddTableStorageService ( ) ;
233+
234+ // Act
235+ Action action = ( ) => services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
236+
237+ // Assert
238+ action . Should ( ) . Throw < InvalidOperationException > ( ) ;
239+ }
240+
241+ [ Fact ]
242+ public void Given_Empty_AzureSettings_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception ( )
243+ {
244+ // Arrange
245+ var services = new ServiceCollection ( ) ;
246+ var dict = new Dictionary < string , string > ( )
247+ {
248+ { "Azure" , string . Empty } ,
249+ } ;
250+ #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
251+ var config = new ConfigurationBuilder ( ) . AddInMemoryCollection ( dict ) . Build ( ) ;
252+ #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
253+ services . AddSingleton < IConfiguration > ( config ) ;
254+ services . AddTableStorageService ( ) ;
255+
256+ // Act
257+ Action action = ( ) => services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
258+
259+ // Assert
260+ action . Should ( ) . Throw < InvalidOperationException > ( ) ;
261+ }
262+
263+ [ Fact ]
264+ public void Given_Empty_KeyVaultSettings_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception ( )
265+ {
266+ // Arrange
267+ var services = new ServiceCollection ( ) ;
268+ var dict = new Dictionary < string , string > ( )
269+ {
270+ { "Azure:KeyVault" , string . Empty } ,
271+ } ;
272+ #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
273+ var config = new ConfigurationBuilder ( ) . AddInMemoryCollection ( dict ) . Build ( ) ;
274+ #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
275+ services . AddSingleton < IConfiguration > ( config ) ;
276+ services . AddTableStorageService ( ) ;
277+
278+ // Act
279+ Action action = ( ) => services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
280+
281+ // Assert
282+ action . Should ( ) . Throw < InvalidOperationException > ( ) ;
283+ }
284+
285+ [ Fact ]
286+ public void Given_Missing_SecretClient_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception ( )
287+ {
288+ // Arrange
289+ var services = new ServiceCollection ( ) ;
290+ var dict = new Dictionary < string , string > ( )
291+ {
292+ { "Azure:KeyVault:SecretNames:Storage" , "secret-name" } ,
293+ } ;
294+ #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
295+ var config = new ConfigurationBuilder ( ) . AddInMemoryCollection ( dict ) . Build ( ) ;
296+ #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
297+ services . AddSingleton < IConfiguration > ( config ) ;
298+ services . AddTableStorageService ( ) ;
299+
300+ // Act
301+ Action action = ( ) => services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
302+
303+ // Assert
304+ action . Should ( ) . Throw < InvalidOperationException > ( ) ;
305+ }
306+
307+ [ Theory ]
308+ [ InlineData ( default ( string ) , typeof ( KeyNotFoundException ) ) ]
309+ [ InlineData ( "" , typeof ( InvalidOperationException ) ) ]
310+ public void Given_NullOrEmpty_SecretName_When_Invoked_AddTableStorageService_Then_It_Shoud_Throw_Exception ( string ? secretName , Type exceptionType )
311+ {
312+ // Arrange
313+ var services = new ServiceCollection ( ) ;
314+ var dict = new Dictionary < string , string > ( )
315+ {
316+ { "Azure:KeyVault:SecretNames:Storage" , secretName } ,
317+ } ;
318+ #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
319+ var config = new ConfigurationBuilder ( ) . AddInMemoryCollection ( dict ) . Build ( ) ;
320+ #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
321+ services . AddSingleton < IConfiguration > ( config ) ;
322+
323+ var sc = Substitute . For < SecretClient > ( ) ;
324+ services . AddSingleton ( sc ) ;
325+
326+ services . AddTableStorageService ( ) ;
327+
328+ // Act
329+ Action action = ( ) => services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
330+
331+ // Assert
332+ action . Should ( ) . Throw < Exception > ( ) . Which . Should ( ) . BeOfType ( exceptionType ) ;
333+ }
334+
335+ [ Theory ]
336+ [ InlineData ( "secret-name" , "DefaultEndpointsProtocol=https;AccountName=account;AccountKey=ZmFrZWtleQ==;EndpointSuffix=core.windows.net" ) ]
337+ public void Given_AppSettings_When_Invoked_AddTableStorageService_Then_It_Should_Return_TableServiceClient ( string secretName , string connectionString )
338+ {
339+ // Arrange
340+ var services = new ServiceCollection ( ) ;
341+ var dict = new Dictionary < string , string > ( )
342+ {
343+ { "Azure:KeyVault:SecretNames:Storage" , secretName } ,
344+ } ;
345+ #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
346+ var config = new ConfigurationBuilder ( ) . AddInMemoryCollection ( dict ) . Build ( ) ;
347+ #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
348+ services . AddSingleton < IConfiguration > ( config ) ;
349+
350+ var sc = Substitute . For < SecretClient > ( ) ;
351+ var sp = new SecretProperties ( secretName ) ;
352+ var secret = SecretModelFactory . KeyVaultSecret ( sp , connectionString ) ;
353+
354+ sc . GetSecret ( secretName ) . Returns ( Response . FromValue ( secret , Substitute . For < Response > ( ) ) ) ;
355+ services . AddSingleton ( sc ) ;
356+
357+ services . AddTableStorageService ( ) ;
358+
359+ // Act
360+ var result = services . BuildServiceProvider ( ) . GetService < TableServiceClient > ( ) ;
361+
362+ // Assert
363+ result . Should ( ) . NotBeNull ( )
364+ . And . BeOfType < TableServiceClient > ( ) ;
365+ }
366+ }
0 commit comments