diff --git a/.gitignore b/.gitignore index a7f4a50..0df7221 100644 --- a/.gitignore +++ b/.gitignore @@ -243,4 +243,4 @@ ModelManifest.xml # FAKE - F# Make .fake/ -/tests/GeekLearning.Integration.Test/appsettings.development.json +appsettings.development.json diff --git a/src/GeekLearning.Storage/IStore{TOptions}.cs b/src/GeekLearning.Storage/IStore{TOptions}.cs new file mode 100644 index 0000000..709f787 --- /dev/null +++ b/src/GeekLearning.Storage/IStore{TOptions}.cs @@ -0,0 +1,7 @@ +namespace GeekLearning.Storage +{ + public interface IStore : IStore + where TOptions : class, IStorageStoreOptions, new() + { + } +} diff --git a/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs new file mode 100644 index 0000000..228bea9 --- /dev/null +++ b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs @@ -0,0 +1,76 @@ +namespace GeekLearning.Storage.Internal +{ + using Microsoft.Extensions.Options; + using System; + using System.IO; + using System.Threading.Tasks; + + public class GenericStoreProxy : IStore, IStore + where TOptions : class, IStorageStoreOptions, new() + { + private IStore innerStore; + + public GenericStoreProxy(IStorageFactory factory, IOptions options) + { + this.innerStore = factory.GetStore(nameof(TOptions), options.Value); + } + + public string Name + { + get + { + return innerStore.Name; + } + } + + public Task DeleteAsync(IPrivateFileReference file) + { + return innerStore.DeleteAsync(file); + } + + public Task GetAsync(Uri file, bool withMetadata) + { + return innerStore.GetAsync(file, withMetadata); + } + + public Task GetAsync(IPrivateFileReference file, bool withMetadata) + { + return innerStore.GetAsync(file, withMetadata); + } + + public Task ListAsync(string path, bool recursive, bool withMetadata) + { + return innerStore.ListAsync(path, recursive, withMetadata); + } + + public Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) + { + return innerStore.ListAsync(path, searchPattern, recursive, withMetadata); + } + + public Task ReadAllBytesAsync(IPrivateFileReference file) + { + return innerStore.ReadAllBytesAsync(file); + } + + public Task ReadAllTextAsync(IPrivateFileReference file) + { + return innerStore.ReadAllTextAsync(file); + } + + public Task ReadAsync(IPrivateFileReference file) + { + return innerStore.ReadAsync(file); + } + + public Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) + { + return innerStore.SaveAsync(data, file, contentType); + } + + public Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) + { + return innerStore.SaveAsync(data, file, contentType); + } + } +} diff --git a/src/GeekLearning.Storage/StorageExtensions.cs b/src/GeekLearning.Storage/StorageExtensions.cs index e6e5909..7fabe92 100644 --- a/src/GeekLearning.Storage/StorageExtensions.cs +++ b/src/GeekLearning.Storage/StorageExtensions.cs @@ -8,6 +8,7 @@ public static class StorageExtensions public static IServiceCollection AddStorage(this IServiceCollection services) { services.TryAddTransient(); + services.TryAdd(ServiceDescriptor.Transient(typeof(IStore<>), typeof(Internal.GenericStoreProxy<>))); return services; } } diff --git a/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs b/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs new file mode 100644 index 0000000..94299db --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs @@ -0,0 +1,37 @@ +namespace GeekLearning.Storage.Integration.Test +{ + using Microsoft.Extensions.DependencyInjection; + using Storage; + using System.Linq; + using System.Threading.Tasks; + using Xunit; + + [Collection(nameof(IntegrationCollection))] + [Trait("Kind", "Integration")] + public class GenericIStoreTests + { + private StoresFixture storeFixture; + + public GenericIStoreTests(StoresFixture fixture) + { + this.storeFixture = fixture; + } + + [Fact] + public async Task GenericListRootFiles() + { + var store = this.storeFixture.Services.GetRequiredService>(); + + var expected = new string[] { "TextFile.txt", "template.hbs" }; + + var results = await store.ListAsync(null); + + var missingFiles = expected.Except(results.Select(f => f.Path)).ToArray(); + + var unexpectedFiles = results.Select(f => f.Path).Except(expected).ToArray(); + + Assert.Empty(missingFiles); + Assert.Empty(unexpectedFiles); + } + } +} diff --git a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs index 4787584..19e3e75 100644 --- a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs +++ b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs @@ -20,12 +20,15 @@ public StoresFixture() { this.BasePath = PlatformServices.Default.Application.ApplicationBasePath; + var containerId = Guid.NewGuid().ToString("N").ToLower(); + var builder = new ConfigurationBuilder() .SetBasePath(BasePath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.development.json", optional: true) .AddInMemoryCollection(new KeyValuePair[] { - new KeyValuePair("Storage:Stores:azure:Parameters:Container", Guid.NewGuid().ToString("N").ToLower()) + new KeyValuePair("Storage:Stores:azure:Parameters:Container", containerId), + new KeyValuePair("TestStore:Parameters:Container", containerId) }); this.Configuration = builder.Build(); @@ -40,6 +43,7 @@ public StoresFixture() .AddFileSystemExtendedProperties(o => { }); services.Configure(Configuration.GetSection("Storage")); + services.Configure(Configuration.GetSection("TestStore")); this.Services = services.BuildServiceProvider(); diff --git a/tests/GeekLearning.Storage.Integration.Test/TestStore.cs b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs new file mode 100644 index 0000000..1df5a25 --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs @@ -0,0 +1,11 @@ +namespace GeekLearning.Storage.Integration.Test +{ + using System.Collections.Generic; + + public class TestStore : IStorageStoreOptions + { + public string Provider { get; set; } + + public Dictionary Parameters { get; set; } + } +} diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json deleted file mode 100644 index 739585f..0000000 --- a/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Storage": { - "Stores": { - "filesystem": { - "Provider": "FileSystem", - "Parameters": { - "Path": "Templates" - } - }, - "azure": { - "Provider": "Azure", - "Parameters": { - "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=glstoragetests;AccountKey=91+UllcfvxK/ghaN3tFUD6/QJZ7t/A4hL0vN9ha587syUxcD3SzCmYuAybBcwbwx77NjV+4/1WXqFTlwwxdA5Q==;", - "Container": "templates" - } - } - } - } -} \ No newline at end of file diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.json index c016376..7b59261 100644 --- a/tests/GeekLearning.Storage.Integration.Test/appsettings.json +++ b/tests/GeekLearning.Storage.Integration.Test/appsettings.json @@ -17,5 +17,11 @@ } }, "ExtendedPropertiesFolderNameFormat": ".{0}-extended-properties" + }, + "TestStore": { + "Provider": "FileSystem", + "Parameters": { + "Path": "Templates" + } } }