diff --git a/test/AzureOpenAIProxy.ApiApp.Tests/Extensions/ServiceCollectionExtensionsTests.cs b/test/AzureOpenAIProxy.ApiApp.Tests/Extensions/ServiceCollectionExtensionsTests.cs index 5a77eda8..f2697cd3 100644 --- a/test/AzureOpenAIProxy.ApiApp.Tests/Extensions/ServiceCollectionExtensionsTests.cs +++ b/test/AzureOpenAIProxy.ApiApp.Tests/Extensions/ServiceCollectionExtensionsTests.cs @@ -1,4 +1,6 @@ -using Azure.Security.KeyVault.Secrets; +using Azure; +using Azure.Data.Tables; +using Azure.Security.KeyVault.Secrets; using AzureOpenAIProxy.ApiApp.Extensions; @@ -7,6 +9,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using NSubstitute; + namespace AzureOpenAIProxy.ApiApp.Tests.Extensions; public class ServiceCollectionExtensionsTests @@ -206,4 +210,157 @@ public void Given_AppSettings_When_Invoked_AddKeyVaultService_Then_It_Should_Ret // Assert result?.VaultUri.Should().BeEquivalentTo(expected); } -} + + [Fact] + public void Given_ServiceCollection_When_Invoked_AddTableStorageService_Then_It_Should_Contain_TableServiceClient() + { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddTableStorageService(); + + // Assert + services.SingleOrDefault(p => p.ServiceType == typeof(TableServiceClient)).Should().NotBeNull(); + } + + [Fact] + public void Given_ServiceCollection_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception() + { + // Arrange + var services = new ServiceCollection(); + services.AddTableStorageService(); + + // Act + Action action = () => services.BuildServiceProvider().GetService(); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void Given_Empty_AzureSettings_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception() + { + // Arrange + var services = new ServiceCollection(); + var dict = new Dictionary() + { + { "Azure", string.Empty}, + }; +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + services.AddSingleton(config); + services.AddTableStorageService(); + + // Act + Action action = () => services.BuildServiceProvider().GetService(); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void Given_Empty_KeyVaultSettings_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception() + { + // Arrange + var services = new ServiceCollection(); + var dict = new Dictionary() + { + { "Azure:KeyVault", string.Empty }, + }; +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + services.AddSingleton(config); + services.AddTableStorageService(); + + // Act + Action action = () => services.BuildServiceProvider().GetService(); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void Given_Missing_SecretClient_When_Invoked_AddTableStorageService_Then_It_Should_Throw_Exception() + { + // Arrange + var services = new ServiceCollection(); + var dict = new Dictionary() + { + { "Azure:KeyVault:SecretNames:Storage", "secret-name" }, + }; +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + services.AddSingleton(config); + services.AddTableStorageService(); + + // Act + Action action = () => services.BuildServiceProvider().GetService(); + + // Assert + action.Should().Throw(); + } + + [Theory] + [InlineData(default(string), typeof(KeyNotFoundException))] + [InlineData("", typeof(InvalidOperationException))] + public void Given_NullOrEmpty_SecretName_When_Invoked_AddTableStorageService_Then_It_Shoud_Throw_Exception(string? secretName, Type exceptionType) + { + // Arrange + var services = new ServiceCollection(); + var dict = new Dictionary() + { + { "Azure:KeyVault:SecretNames:Storage", secretName }, + }; +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + services.AddSingleton(config); + + var sc = Substitute.For(); + services.AddSingleton(sc); + + services.AddTableStorageService(); + + // Act + Action action = () => services.BuildServiceProvider().GetService(); + + // Assert + action.Should().Throw().Which.Should().BeOfType(exceptionType); + } + + [Theory] + [InlineData("secret-name", "DefaultEndpointsProtocol=https;AccountName=account;AccountKey=ZmFrZWtleQ==;EndpointSuffix=core.windows.net")] + public void Given_AppSettings_When_Invoked_AddTableStorageService_Then_It_Should_Return_TableServiceClient(string secretName, string connectionString) + { + // Arrange + var services = new ServiceCollection(); + var dict = new Dictionary() + { + { "Azure:KeyVault:SecretNames:Storage", secretName }, + }; +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. + services.AddSingleton(config); + + var sc = Substitute.For(); + var sp = new SecretProperties(secretName); + var secret = SecretModelFactory.KeyVaultSecret(sp,connectionString); + + sc.GetSecret(secretName).Returns(Response.FromValue(secret, Substitute.For())); + services.AddSingleton(sc); + + services.AddTableStorageService(); + + // Act + var result = services.BuildServiceProvider().GetService(); + + // Assert + result.Should().NotBeNull() + .And.BeOfType(); + } +} \ No newline at end of file