From 2766d6916e930e1f8310ea72769a17ec0321e50d Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Wed, 27 Mar 2024 12:43:30 -0500 Subject: [PATCH] Ran dotnet format --- .editorconfig | 12 +- .../Extensions/TaskExtensions.cs | 23 +- .../MinioConnectionStringBuilder.cs | 135 ++-- .../Storage/MinioFileStorage.cs | 683 +++++++++--------- ...MinioFileStorageConnectionStringBuilder.cs | 57 +- .../Storage/MinioFileStorageOptions.cs | 35 +- .../ConnectionStringBuilderTests.cs | 101 ++- ...FileStorageConnectionStringBuilderTests.cs | 119 ++- .../Storage/MinioFileStorageTests.cs | 221 +++--- 9 files changed, 691 insertions(+), 695 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9d3abe5..50615ba 100644 --- a/.editorconfig +++ b/.editorconfig @@ -42,10 +42,10 @@ csharp_indent_labels = one_less_than_current csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion # avoid this. unless absolutely necessary -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_property = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:error +dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_event = false:error # Types: use keywords instead of BCL types, and permit var only when the type is clear csharp_style_var_for_built_in_types = false:suggestion @@ -154,6 +154,10 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false +# Custom +csharp_style_namespace_declarations = file_scoped:error +dotnet_diagnostic.IDE0005.severity = error # Using directive is unnecessary. + # C++ Files [*.{cpp,h,in}] curly_bracket_next_line = true diff --git a/src/Foundatio.Minio/Extensions/TaskExtensions.cs b/src/Foundatio.Minio/Extensions/TaskExtensions.cs index 675790a..d6c51be 100644 --- a/src/Foundatio.Minio/Extensions/TaskExtensions.cs +++ b/src/Foundatio.Minio/Extensions/TaskExtensions.cs @@ -2,20 +2,19 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; -namespace Foundatio.Extensions +namespace Foundatio.Extensions; + +internal static class TaskExtensions { - internal static class TaskExtensions + [DebuggerStepThrough] + public static ConfiguredTaskAwaitable AnyContext(this Task task) { - [DebuggerStepThrough] - public static ConfiguredTaskAwaitable AnyContext(this Task task) - { - return task.ConfigureAwait(false); - } + return task.ConfigureAwait(false); + } - [DebuggerStepThrough] - public static ConfiguredTaskAwaitable AnyContext(this Task task) - { - return task.ConfigureAwait(false); - } + [DebuggerStepThrough] + public static ConfiguredTaskAwaitable AnyContext(this Task task) + { + return task.ConfigureAwait(false); } } diff --git a/src/Foundatio.Minio/MinioConnectionStringBuilder.cs b/src/Foundatio.Minio/MinioConnectionStringBuilder.cs index fd86c7d..47238b6 100644 --- a/src/Foundatio.Minio/MinioConnectionStringBuilder.cs +++ b/src/Foundatio.Minio/MinioConnectionStringBuilder.cs @@ -1,89 +1,88 @@ using System; using System.Linq; -namespace Foundatio +namespace Foundatio; + +public class MinioConnectionStringBuilder { - public class MinioConnectionStringBuilder - { - public string AccessKey { get; set; } + public string AccessKey { get; set; } - public string SecretKey { get; set; } + public string SecretKey { get; set; } - public string Region { get; set; } + public string Region { get; set; } - public string EndPoint { get; set; } + public string EndPoint { get; set; } - protected MinioConnectionStringBuilder() { } + protected MinioConnectionStringBuilder() { } - protected MinioConnectionStringBuilder(string connectionString) - { - if (String.IsNullOrEmpty(connectionString)) - throw new ArgumentNullException(nameof(connectionString)); - Parse(connectionString); - } + protected MinioConnectionStringBuilder(string connectionString) + { + if (String.IsNullOrEmpty(connectionString)) + throw new ArgumentNullException(nameof(connectionString)); + Parse(connectionString); + } - private void Parse(string connectionString) + private void Parse(string connectionString) + { + foreach (var option in connectionString + .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Where(kvp => kvp.Contains('=')) + .Select(kvp => kvp.Split(new[] { '=' }, 2))) { - foreach (var option in connectionString - .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) - .Where(kvp => kvp.Contains('=')) - .Select(kvp => kvp.Split(new[] { '=' }, 2))) + var optionKey = option[0].Trim(); + var optionValue = option[1].Trim(); + if (!ParseItem(optionKey, optionValue)) { - var optionKey = option[0].Trim(); - var optionValue = option[1].Trim(); - if (!ParseItem(optionKey, optionValue)) - { - throw new ArgumentException($"The option '{optionKey}' cannot be recognized in connection string.", nameof(connectionString)); - } + throw new ArgumentException($"The option '{optionKey}' cannot be recognized in connection string.", nameof(connectionString)); } } + } - protected virtual bool ParseItem(string key, string value) + protected virtual bool ParseItem(string key, string value) + { + if (String.Equals(key, "AccessKey", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Access Key", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "AccessKeyId", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Access Key Id", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Id", StringComparison.OrdinalIgnoreCase)) { - if (String.Equals(key, "AccessKey", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Access Key", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "AccessKeyId", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Access Key Id", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Id", StringComparison.OrdinalIgnoreCase)) - { - AccessKey = value; - return true; - } - if (String.Equals(key, "SecretKey", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Secret Key", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "SecretAccessKey", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Secret Access Key", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "Secret", StringComparison.OrdinalIgnoreCase)) - { - SecretKey = value; - return true; - } - if (String.Equals(key, "Region", StringComparison.OrdinalIgnoreCase)) - { - Region = value; - return true; - } - if (String.Equals(key, "EndPoint", StringComparison.OrdinalIgnoreCase) || - String.Equals(key, "End Point", StringComparison.OrdinalIgnoreCase)) - { - EndPoint = value; - return true; - } - return false; + AccessKey = value; + return true; } - - public override string ToString() + if (String.Equals(key, "SecretKey", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Secret Key", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "SecretAccessKey", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Secret Access Key", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "Secret", StringComparison.OrdinalIgnoreCase)) + { + SecretKey = value; + return true; + } + if (String.Equals(key, "Region", StringComparison.OrdinalIgnoreCase)) + { + Region = value; + return true; + } + if (String.Equals(key, "EndPoint", StringComparison.OrdinalIgnoreCase) || + String.Equals(key, "End Point", StringComparison.OrdinalIgnoreCase)) { - var connectionString = string.Empty; - if (!string.IsNullOrEmpty(AccessKey)) - connectionString += "AccessKey=" + AccessKey + ";"; - if (!string.IsNullOrEmpty(SecretKey)) - connectionString += "SecretKey=" + SecretKey + ";"; - if (!string.IsNullOrEmpty(Region)) - connectionString += "Region=" + Region + ";"; - if (!string.IsNullOrEmpty(EndPoint)) - connectionString += "EndPoint=" + EndPoint + ";"; - return connectionString; + EndPoint = value; + return true; } + return false; + } + + public override string ToString() + { + var connectionString = string.Empty; + if (!string.IsNullOrEmpty(AccessKey)) + connectionString += "AccessKey=" + AccessKey + ";"; + if (!string.IsNullOrEmpty(SecretKey)) + connectionString += "SecretKey=" + SecretKey + ";"; + if (!string.IsNullOrEmpty(Region)) + connectionString += "Region=" + Region + ";"; + if (!string.IsNullOrEmpty(EndPoint)) + connectionString += "EndPoint=" + EndPoint + ";"; + return connectionString; } } diff --git a/src/Foundatio.Minio/Storage/MinioFileStorage.cs b/src/Foundatio.Minio/Storage/MinioFileStorage.cs index d41e448..67f8ae2 100644 --- a/src/Foundatio.Minio/Storage/MinioFileStorage.cs +++ b/src/Foundatio.Minio/Storage/MinioFileStorage.cs @@ -16,436 +16,435 @@ using Minio.DataModel.Args; using Minio.Exceptions; -namespace Foundatio.Storage +namespace Foundatio.Storage; + +public class MinioFileStorage : IFileStorage { - public class MinioFileStorage : IFileStorage + private readonly string _bucket; + private readonly bool _shouldAutoCreateBucket; + private bool _bucketExistsChecked; + private readonly IMinioClient _client; + private readonly ISerializer _serializer; + private readonly ILogger _logger; + + public MinioFileStorage(MinioFileStorageOptions options) { - private readonly string _bucket; - private readonly bool _shouldAutoCreateBucket; - private bool _bucketExistsChecked; - private readonly IMinioClient _client; - private readonly ISerializer _serializer; - private readonly ILogger _logger; - - public MinioFileStorage(MinioFileStorageOptions options) - { - if (options == null) - throw new ArgumentNullException(nameof(options)); + if (options == null) + throw new ArgumentNullException(nameof(options)); - _serializer = options.Serializer ?? DefaultSerializer.Instance; - _logger = options.LoggerFactory?.CreateLogger(GetType()) ?? NullLogger.Instance; + _serializer = options.Serializer ?? DefaultSerializer.Instance; + _logger = options.LoggerFactory?.CreateLogger(GetType()) ?? NullLogger.Instance; - (var client, string bucket) = CreateClient(options); - _client = client; - _bucket = bucket; - _shouldAutoCreateBucket = options.AutoCreateBucket; - } - - public MinioFileStorage(Builder builder) - : this(builder(new MinioFileStorageOptionsBuilder()).Build()) { } + (var client, string bucket) = CreateClient(options); + _client = client; + _bucket = bucket; + _shouldAutoCreateBucket = options.AutoCreateBucket; + } - ISerializer IHaveSerializer.Serializer => _serializer; - public IMinioClient Client => _client; + public MinioFileStorage(Builder builder) + : this(builder(new MinioFileStorageOptionsBuilder()).Build()) { } - private async Task EnsureBucketExists() - { - if (!_shouldAutoCreateBucket || _bucketExistsChecked) - return; + ISerializer IHaveSerializer.Serializer => _serializer; + public IMinioClient Client => _client; - _logger.LogTrace("Checking if bucket {Bucket} exists", _bucket); - bool found = await _client.BucketExistsAsync(new BucketExistsArgs().WithBucket(_bucket)).AnyContext(); - if (!found) - { - _logger.LogInformation("Creating {Bucket}", _bucket); - await _client.MakeBucketAsync(new MakeBucketArgs().WithBucket(_bucket)).AnyContext(); - _logger.LogInformation("Created {Bucket}", _bucket); - } + private async Task EnsureBucketExists() + { + if (!_shouldAutoCreateBucket || _bucketExistsChecked) + return; - _bucketExistsChecked = true; + _logger.LogTrace("Checking if bucket {Bucket} exists", _bucket); + bool found = await _client.BucketExistsAsync(new BucketExistsArgs().WithBucket(_bucket)).AnyContext(); + if (!found) + { + _logger.LogInformation("Creating {Bucket}", _bucket); + await _client.MakeBucketAsync(new MakeBucketArgs().WithBucket(_bucket)).AnyContext(); + _logger.LogInformation("Created {Bucket}", _bucket); } - [Obsolete($"Use {nameof(GetFileStreamAsync)} with {nameof(FileAccess)} instead to define read or write behaviour of stream")] - public Task GetFileStreamAsync(string path, CancellationToken cancellationToken = default) - => GetFileStreamAsync(path, StreamMode.Read, cancellationToken); + _bucketExistsChecked = true; + } - public async Task GetFileStreamAsync(string path, StreamMode streamMode, CancellationToken cancellationToken = default) - { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); + [Obsolete($"Use {nameof(GetFileStreamAsync)} with {nameof(FileAccess)} instead to define read or write behaviour of stream")] + public Task GetFileStreamAsync(string path, CancellationToken cancellationToken = default) + => GetFileStreamAsync(path, StreamMode.Read, cancellationToken); - if (streamMode is StreamMode.Write) - throw new NotSupportedException($"Stream mode {streamMode} is not supported."); + public async Task GetFileStreamAsync(string path, StreamMode streamMode, CancellationToken cancellationToken = default) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); - await EnsureBucketExists().AnyContext(); + if (streamMode is StreamMode.Write) + throw new NotSupportedException($"Stream mode {streamMode} is not supported."); - string normalizedPath = NormalizePath(path); - _logger.LogTrace("Getting file stream for {Path}", normalizedPath); + await EnsureBucketExists().AnyContext(); - try - { - Stream result = new MemoryStream(); - await _client.GetObjectAsync(new GetObjectArgs().WithBucket(_bucket).WithObject(normalizedPath).WithCallbackStream(async (stream, _) => await stream.CopyToAsync(result).AnyContext()), cancellationToken).AnyContext(); - result.Seek(0, SeekOrigin.Begin); - return result; - } - catch (Exception ex) - { - _logger.LogError(ex, "Unable to get file stream for {Path}: {Message}", normalizedPath, ex.Message); - return null; - } - } + string normalizedPath = NormalizePath(path); + _logger.LogTrace("Getting file stream for {Path}", normalizedPath); - public async Task GetFileInfoAsync(string path) + try { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); + Stream result = new MemoryStream(); + await _client.GetObjectAsync(new GetObjectArgs().WithBucket(_bucket).WithObject(normalizedPath).WithCallbackStream(async (stream, _) => await stream.CopyToAsync(result).AnyContext()), cancellationToken).AnyContext(); + result.Seek(0, SeekOrigin.Begin); + return result; + } + catch (Exception ex) + { + _logger.LogError(ex, "Unable to get file stream for {Path}: {Message}", normalizedPath, ex.Message); + return null; + } + } - await EnsureBucketExists().AnyContext(); + public async Task GetFileInfoAsync(string path) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); - string normalizedPath = NormalizePath(path); - _logger.LogTrace("Getting file info for {Path}", normalizedPath); + await EnsureBucketExists().AnyContext(); - try - { - var metadata = await _client.StatObjectAsync(new StatObjectArgs().WithBucket(_bucket).WithObject(normalizedPath)).AnyContext(); - if (metadata.ExtraHeaders.TryGetValue("X-Minio-Error-Code", out string errorCode) && (String.Equals(errorCode, "NoSuchBucket") || String.Equals(errorCode, "NoSuchKey"))) - return null; - - return new FileSpec - { - Path = normalizedPath, - Size = metadata.Size, - Created = metadata.LastModified.ToUniversalTime(), - Modified = metadata.LastModified.ToUniversalTime() - }; - } - catch (Exception ex) - { - _logger.LogError(ex, "Unable to get file info for {Path}: {Message}", normalizedPath, ex.Message); + string normalizedPath = NormalizePath(path); + _logger.LogTrace("Getting file info for {Path}", normalizedPath); + + try + { + var metadata = await _client.StatObjectAsync(new StatObjectArgs().WithBucket(_bucket).WithObject(normalizedPath)).AnyContext(); + if (metadata.ExtraHeaders.TryGetValue("X-Minio-Error-Code", out string errorCode) && (String.Equals(errorCode, "NoSuchBucket") || String.Equals(errorCode, "NoSuchKey"))) return null; - } - } - public async Task ExistsAsync(string path) + return new FileSpec + { + Path = normalizedPath, + Size = metadata.Size, + Created = metadata.LastModified.ToUniversalTime(), + Modified = metadata.LastModified.ToUniversalTime() + }; + } + catch (Exception ex) { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); + _logger.LogError(ex, "Unable to get file info for {Path}: {Message}", normalizedPath, ex.Message); + return null; + } + } - await EnsureBucketExists().AnyContext(); + public async Task ExistsAsync(string path) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); - string normalizedPath = NormalizePath(path); - _logger.LogTrace("Checking if {Path} exists", normalizedPath); + await EnsureBucketExists().AnyContext(); - try - { - var metadata = await _client.StatObjectAsync(new StatObjectArgs().WithBucket(_bucket).WithObject(normalizedPath)).AnyContext(); - if (metadata.ExtraHeaders.TryGetValue("X-Minio-Error-Code", out string errorCode) && (String.Equals(errorCode, "NoSuchBucket") || String.Equals(errorCode, "NoSuchKey"))) - return false; + string normalizedPath = NormalizePath(path); + _logger.LogTrace("Checking if {Path} exists", normalizedPath); - return true; - } - catch (Exception ex) when (ex is ObjectNotFoundException or BucketNotFoundException) - { - _logger.LogDebug(ex, "Unable to check if {Path} exists: {Message}", normalizedPath, ex.Message); + try + { + var metadata = await _client.StatObjectAsync(new StatObjectArgs().WithBucket(_bucket).WithObject(normalizedPath)).AnyContext(); + if (metadata.ExtraHeaders.TryGetValue("X-Minio-Error-Code", out string errorCode) && (String.Equals(errorCode, "NoSuchBucket") || String.Equals(errorCode, "NoSuchKey"))) return false; - } - } - public async Task SaveFileAsync(string path, Stream stream, CancellationToken cancellationToken = default) + return true; + } + catch (Exception ex) when (ex is ObjectNotFoundException or BucketNotFoundException) { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); - if (stream == null) - throw new ArgumentNullException(nameof(stream)); + _logger.LogDebug(ex, "Unable to check if {Path} exists: {Message}", normalizedPath, ex.Message); + return false; + } + } - await EnsureBucketExists().AnyContext(); + public async Task SaveFileAsync(string path, Stream stream, CancellationToken cancellationToken = default) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); + if (stream == null) + throw new ArgumentNullException(nameof(stream)); - string normalizedPath = NormalizePath(path); - _logger.LogTrace("Saving {Path}", normalizedPath); + await EnsureBucketExists().AnyContext(); - var seekableStream = stream.CanSeek ? stream : new MemoryStream(); - if (!stream.CanSeek) - { - await stream.CopyToAsync(seekableStream).AnyContext(); - seekableStream.Seek(0, SeekOrigin.Begin); - } + string normalizedPath = NormalizePath(path); + _logger.LogTrace("Saving {Path}", normalizedPath); - try - { - await _client.PutObjectAsync(new PutObjectArgs().WithBucket(_bucket).WithObject(normalizedPath).WithStreamData(seekableStream).WithObjectSize(seekableStream.Length - seekableStream.Position), cancellationToken).AnyContext(); - return true; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error saving {Path}: {Message}", normalizedPath, ex.Message); - return false; - } - finally - { - if (!stream.CanSeek) - seekableStream.Dispose(); - } + var seekableStream = stream.CanSeek ? stream : new MemoryStream(); + if (!stream.CanSeek) + { + await stream.CopyToAsync(seekableStream).AnyContext(); + seekableStream.Seek(0, SeekOrigin.Begin); } - public async Task RenameFileAsync(string path, string newPath, CancellationToken cancellationToken = default) + try + { + await _client.PutObjectAsync(new PutObjectArgs().WithBucket(_bucket).WithObject(normalizedPath).WithStreamData(seekableStream).WithObjectSize(seekableStream.Length - seekableStream.Position), cancellationToken).AnyContext(); + return true; + } + catch (Exception ex) { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); - if (String.IsNullOrEmpty(newPath)) - throw new ArgumentNullException(nameof(newPath)); + _logger.LogError(ex, "Error saving {Path}: {Message}", normalizedPath, ex.Message); + return false; + } + finally + { + if (!stream.CanSeek) + seekableStream.Dispose(); + } + } - await EnsureBucketExists().AnyContext(); + public async Task RenameFileAsync(string path, string newPath, CancellationToken cancellationToken = default) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); + if (String.IsNullOrEmpty(newPath)) + throw new ArgumentNullException(nameof(newPath)); - string normalizedPath = NormalizePath(path); - string normalizedNewPath = NormalizePath(newPath); - _logger.LogInformation("Renaming {Path} to {NewPath}", normalizedPath, normalizedNewPath); + await EnsureBucketExists().AnyContext(); - return await CopyFileAsync(normalizedPath, normalizedNewPath, cancellationToken).AnyContext() && - await DeleteFileAsync(normalizedPath, cancellationToken).AnyContext(); - } + string normalizedPath = NormalizePath(path); + string normalizedNewPath = NormalizePath(newPath); + _logger.LogInformation("Renaming {Path} to {NewPath}", normalizedPath, normalizedNewPath); - public async Task CopyFileAsync(string path, string targetPath, CancellationToken cancellationToken = default) - { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); - if (String.IsNullOrEmpty(targetPath)) - throw new ArgumentNullException(nameof(targetPath)); + return await CopyFileAsync(normalizedPath, normalizedNewPath, cancellationToken).AnyContext() && + await DeleteFileAsync(normalizedPath, cancellationToken).AnyContext(); + } - await EnsureBucketExists().AnyContext(); + public async Task CopyFileAsync(string path, string targetPath, CancellationToken cancellationToken = default) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); + if (String.IsNullOrEmpty(targetPath)) + throw new ArgumentNullException(nameof(targetPath)); - string normalizedPath = NormalizePath(path); - string normalizedTargetPath = NormalizePath(targetPath); - _logger.LogInformation("Copying {Path} to {TargetPath}", normalizedPath, normalizedTargetPath); + await EnsureBucketExists().AnyContext(); - try - { - var copySourceArgs = new CopySourceObjectArgs().WithBucket(_bucket).WithObject(normalizedPath); + string normalizedPath = NormalizePath(path); + string normalizedTargetPath = NormalizePath(targetPath); + _logger.LogInformation("Copying {Path} to {TargetPath}", normalizedPath, normalizedTargetPath); - await _client.CopyObjectAsync(new CopyObjectArgs() - .WithBucket(_bucket) - .WithObject(normalizedTargetPath) - .WithCopyObjectSource(copySourceArgs), cancellationToken).AnyContext(); - return true; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error copying {Path} to {TargetPath}: {Message}", normalizedPath, normalizedTargetPath, ex.Message); - return false; - } - } + try + { + var copySourceArgs = new CopySourceObjectArgs().WithBucket(_bucket).WithObject(normalizedPath); - public async Task DeleteFileAsync(string path, CancellationToken cancellationToken = default) + await _client.CopyObjectAsync(new CopyObjectArgs() + .WithBucket(_bucket) + .WithObject(normalizedTargetPath) + .WithCopyObjectSource(copySourceArgs), cancellationToken).AnyContext(); + return true; + } + catch (Exception ex) { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException(nameof(path)); + _logger.LogError(ex, "Error copying {Path} to {TargetPath}: {Message}", normalizedPath, normalizedTargetPath, ex.Message); + return false; + } + } - await EnsureBucketExists().AnyContext(); + public async Task DeleteFileAsync(string path, CancellationToken cancellationToken = default) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); - string normalizedPath = NormalizePath(path); - _logger.LogTrace("Deleting {Path}", normalizedPath); + await EnsureBucketExists().AnyContext(); - try - { - await _client.RemoveObjectAsync(new RemoveObjectArgs().WithBucket(_bucket).WithObject(normalizedPath), cancellationToken).AnyContext(); - return true; - } - catch (Exception ex) - { - _logger.LogError(ex, "Unable to delete {Path}: {Message}", normalizedPath, ex.Message); - return false; - } - } + string normalizedPath = NormalizePath(path); + _logger.LogTrace("Deleting {Path}", normalizedPath); - public async Task DeleteFilesAsync(string searchPattern = null, CancellationToken cancellation = default) + try { - await EnsureBucketExists().AnyContext(); + await _client.RemoveObjectAsync(new RemoveObjectArgs().WithBucket(_bucket).WithObject(normalizedPath), cancellationToken).AnyContext(); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Unable to delete {Path}: {Message}", normalizedPath, ex.Message); + return false; + } + } - var files = await GetFileListAsync(searchPattern, cancellationToken: cancellation).AnyContext(); - _logger.LogInformation("Deleting {FileCount} files matching {SearchPattern}", files.Count, searchPattern); - if (files.Count == 0) - { - _logger.LogTrace("Finished deleting {FileCount} files matching {SearchPattern}", files.Count, searchPattern); - return 0; - } + public async Task DeleteFilesAsync(string searchPattern = null, CancellationToken cancellation = default) + { + await EnsureBucketExists().AnyContext(); - var result = await _client.RemoveObjectsAsync(new RemoveObjectsArgs().WithBucket(_bucket).WithObjects(files.Select(spec => NormalizePath(spec.Path)).ToList()), cancellation).AnyContext(); - var resetEvent = new AutoResetEvent(false); - result.Subscribe(error => - { - _logger.LogError("Error deleting {Path}: {Message}", error.Key, error.Message); - resetEvent.Set(); - }, () => resetEvent.Set()); - resetEvent.WaitOne(); - - int count = await result.Count(); - _logger.LogTrace("Finished deleting {FileCount} files matching {SearchPattern}", count, searchPattern); - return count; + var files = await GetFileListAsync(searchPattern, cancellationToken: cancellation).AnyContext(); + _logger.LogInformation("Deleting {FileCount} files matching {SearchPattern}", files.Count, searchPattern); + if (files.Count == 0) + { + _logger.LogTrace("Finished deleting {FileCount} files matching {SearchPattern}", files.Count, searchPattern); + return 0; } - public async Task GetPagedFileListAsync(int pageSize = 100, string searchPattern = null, CancellationToken cancellationToken = default) + var result = await _client.RemoveObjectsAsync(new RemoveObjectsArgs().WithBucket(_bucket).WithObjects(files.Select(spec => NormalizePath(spec.Path)).ToList()), cancellation).AnyContext(); + var resetEvent = new AutoResetEvent(false); + result.Subscribe(error => { - if (pageSize <= 0) - return PagedFileListResult.Empty; + _logger.LogError("Error deleting {Path}: {Message}", error.Key, error.Message); + resetEvent.Set(); + }, () => resetEvent.Set()); + resetEvent.WaitOne(); + + int count = await result.Count(); + _logger.LogTrace("Finished deleting {FileCount} files matching {SearchPattern}", count, searchPattern); + return count; + } - await EnsureBucketExists().AnyContext(); + public async Task GetPagedFileListAsync(int pageSize = 100, string searchPattern = null, CancellationToken cancellationToken = default) + { + if (pageSize <= 0) + return PagedFileListResult.Empty; - var result = new PagedFileListResult(_ => GetFiles(searchPattern, 1, pageSize, cancellationToken)); - await result.NextPageAsync().AnyContext(); - return result; - } + await EnsureBucketExists().AnyContext(); - private async Task GetFiles(string searchPattern, int page, int pageSize, CancellationToken cancellationToken) - { - int pagingLimit = pageSize; - int skip = (page - 1) * pagingLimit; - if (pagingLimit < Int32.MaxValue) - pagingLimit++; - - var list = (await GetFileListAsync(searchPattern, pagingLimit, skip, cancellationToken).AnyContext()).ToList(); - bool hasMore = false; - if (list.Count == pagingLimit) - { - hasMore = true; - list.RemoveAt(pagingLimit - 1); - } + var result = new PagedFileListResult(_ => GetFiles(searchPattern, 1, pageSize, cancellationToken)); + await result.NextPageAsync().AnyContext(); + return result; + } - return new NextPageResult - { - Success = true, - HasMore = hasMore, - Files = list, - NextPageFunc = hasMore ? _ => GetFiles(searchPattern, page + 1, pageSize, cancellationToken) : null - }; + private async Task GetFiles(string searchPattern, int page, int pageSize, CancellationToken cancellationToken) + { + int pagingLimit = pageSize; + int skip = (page - 1) * pagingLimit; + if (pagingLimit < Int32.MaxValue) + pagingLimit++; + + var list = (await GetFileListAsync(searchPattern, pagingLimit, skip, cancellationToken).AnyContext()).ToList(); + bool hasMore = false; + if (list.Count == pagingLimit) + { + hasMore = true; + list.RemoveAt(pagingLimit - 1); } - private Task> GetFileListAsync(string searchPattern = null, int? limit = null, int? skip = null, CancellationToken cancellationToken = default) + return new NextPageResult { - if (limit is <= 0) - return Task.FromResult(new List()); + Success = true, + HasMore = hasMore, + Files = list, + NextPageFunc = hasMore ? _ => GetFiles(searchPattern, page + 1, pageSize, cancellationToken) : null + }; + } - var list = new List(); - var criteria = GetRequestCriteria(searchPattern); + private Task> GetFileListAsync(string searchPattern = null, int? limit = null, int? skip = null, CancellationToken cancellationToken = default) + { + if (limit is <= 0) + return Task.FromResult(new List()); - _logger.LogTrace( - s => s.Property("SearchPattern", searchPattern).Property("Limit", limit).Property("Skip", skip), - "Getting file list recursively matching {Prefix} and {Pattern}...", criteria.Prefix, criteria.Pattern - ); + var list = new List(); + var criteria = GetRequestCriteria(searchPattern); - ExceptionDispatchInfo exception = null; - var resetEvent = new AutoResetEvent(false); - var observable = _client.ListObjectsAsync(new ListObjectsArgs().WithBucket(_bucket).WithPrefix(criteria.Prefix).WithRecursive(true), cancellationToken); - observable.Subscribe(item => - { - if (item.IsDir) - return; + _logger.LogTrace( + s => s.Property("SearchPattern", searchPattern).Property("Limit", limit).Property("Skip", skip), + "Getting file list recursively matching {Prefix} and {Pattern}...", criteria.Prefix, criteria.Pattern + ); - if (criteria.Pattern != null && !criteria.Pattern.IsMatch(item.Key)) - { - _logger.LogTrace("Skipping {Path}: Doesn't match pattern", item.Key); - return; - } + ExceptionDispatchInfo exception = null; + var resetEvent = new AutoResetEvent(false); + var observable = _client.ListObjectsAsync(new ListObjectsArgs().WithBucket(_bucket).WithPrefix(criteria.Prefix).WithRecursive(true), cancellationToken); + observable.Subscribe(item => + { + if (item.IsDir) + return; - list.Add(item); - }, error => - { - if (error.GetType().ToString() != "Minio.EmptyBucketOperation") - { - _logger.LogError(error, "Error getting file list: {Message}", error.Message); - exception = ExceptionDispatchInfo.Capture(error); - } - resetEvent.Set(); - }, - () => resetEvent.Set() - ); - resetEvent.WaitOne(); - exception?.Throw(); - - if (skip.HasValue) - list = list.Skip(skip.Value).ToList(); - - if (limit.HasValue) - list = list.Take(limit.Value).ToList(); - - return Task.FromResult(list.Select(blob => new FileSpec + if (criteria.Pattern != null && !criteria.Pattern.IsMatch(item.Key)) { - Path = blob.Key, - Size = (long)blob.Size, - Modified = DateTime.Parse(blob.LastModified), - Created = DateTime.Parse(blob.LastModified) - }).ToList()); - } + _logger.LogTrace("Skipping {Path}: Doesn't match pattern", item.Key); + return; + } - private string NormalizePath(string path) + list.Add(item); + }, error => { - return path?.Replace('\\', '/'); - } + if (error.GetType().ToString() != "Minio.EmptyBucketOperation") + { + _logger.LogError(error, "Error getting file list: {Message}", error.Message); + exception = ExceptionDispatchInfo.Capture(error); + } + resetEvent.Set(); + }, + () => resetEvent.Set() + ); + resetEvent.WaitOne(); + exception?.Throw(); - private class SearchCriteria - { - public string Prefix { get; set; } - public Regex Pattern { get; set; } - } + if (skip.HasValue) + list = list.Skip(skip.Value).ToList(); + + if (limit.HasValue) + list = list.Take(limit.Value).ToList(); - private SearchCriteria GetRequestCriteria(string searchPattern) + return Task.FromResult(list.Select(blob => new FileSpec { - if (String.IsNullOrEmpty(searchPattern)) - return new SearchCriteria { Prefix = String.Empty }; + Path = blob.Key, + Size = (long)blob.Size, + Modified = DateTime.Parse(blob.LastModified), + Created = DateTime.Parse(blob.LastModified) + }).ToList()); + } - string normalizedSearchPattern = NormalizePath(searchPattern); - int wildcardPos = normalizedSearchPattern.IndexOf('*'); - bool hasWildcard = wildcardPos >= 0; + private string NormalizePath(string path) + { + return path?.Replace('\\', '/'); + } - string prefix = normalizedSearchPattern; - Regex patternRegex = null; + private class SearchCriteria + { + public string Prefix { get; set; } + public Regex Pattern { get; set; } + } - if (hasWildcard) - { - patternRegex = new Regex($"^{Regex.Escape(normalizedSearchPattern).Replace("\\*", ".*?")}$"); - int slashPos = normalizedSearchPattern.LastIndexOf('/'); - prefix = slashPos >= 0 ? normalizedSearchPattern.Substring(0, slashPos) : String.Empty; - } + private SearchCriteria GetRequestCriteria(string searchPattern) + { + if (String.IsNullOrEmpty(searchPattern)) + return new SearchCriteria { Prefix = String.Empty }; - return new SearchCriteria - { - Prefix = prefix, - Pattern = patternRegex - }; + string normalizedSearchPattern = NormalizePath(searchPattern); + int wildcardPos = normalizedSearchPattern.IndexOf('*'); + bool hasWildcard = wildcardPos >= 0; + + string prefix = normalizedSearchPattern; + Regex patternRegex = null; + + if (hasWildcard) + { + patternRegex = new Regex($"^{Regex.Escape(normalizedSearchPattern).Replace("\\*", ".*?")}$"); + int slashPos = normalizedSearchPattern.LastIndexOf('/'); + prefix = slashPos >= 0 ? normalizedSearchPattern.Substring(0, slashPos) : String.Empty; } - private (IMinioClient Client, string Bucket) CreateClient(MinioFileStorageOptions options) + return new SearchCriteria { - var connectionString = new MinioFileStorageConnectionStringBuilder(options.ConnectionString); + Prefix = prefix, + Pattern = patternRegex + }; + } - string endpoint; - bool secure; - if (connectionString.EndPoint.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - endpoint = connectionString.EndPoint.Substring(8); - secure = true; - } - else - { - endpoint = connectionString.EndPoint.StartsWith("http://", StringComparison.OrdinalIgnoreCase) - ? connectionString.EndPoint.Substring(7) - : connectionString.EndPoint; - secure = false; - } + private (IMinioClient Client, string Bucket) CreateClient(MinioFileStorageOptions options) + { + var connectionString = new MinioFileStorageConnectionStringBuilder(options.ConnectionString); - var client = new MinioClient() - .WithEndpoint(endpoint) - .WithCredentials(connectionString.AccessKey, connectionString.SecretKey); + string endpoint; + bool secure; + if (connectionString.EndPoint.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + endpoint = connectionString.EndPoint.Substring(8); + secure = true; + } + else + { + endpoint = connectionString.EndPoint.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + ? connectionString.EndPoint.Substring(7) + : connectionString.EndPoint; + secure = false; + } - if (!String.IsNullOrEmpty(connectionString.Region)) - client.WithRegion(connectionString.Region ?? String.Empty); + var client = new MinioClient() + .WithEndpoint(endpoint) + .WithCredentials(connectionString.AccessKey, connectionString.SecretKey); - client.Build(); + if (!String.IsNullOrEmpty(connectionString.Region)) + client.WithRegion(connectionString.Region ?? String.Empty); - if (secure) - client.WithSSL(); + client.Build(); - return (client, connectionString.Bucket); - } + if (secure) + client.WithSSL(); - public void Dispose() { } + return (client, connectionString.Bucket); } + + public void Dispose() { } } diff --git a/src/Foundatio.Minio/Storage/MinioFileStorageConnectionStringBuilder.cs b/src/Foundatio.Minio/Storage/MinioFileStorageConnectionStringBuilder.cs index bf28137..c487a16 100644 --- a/src/Foundatio.Minio/Storage/MinioFileStorageConnectionStringBuilder.cs +++ b/src/Foundatio.Minio/Storage/MinioFileStorageConnectionStringBuilder.cs @@ -1,41 +1,40 @@ using System; -namespace Foundatio.Storage +namespace Foundatio.Storage; + +public class MinioFileStorageConnectionStringBuilder : MinioConnectionStringBuilder { - public class MinioFileStorageConnectionStringBuilder : MinioConnectionStringBuilder - { - private string _bucket; + private string _bucket; - public MinioFileStorageConnectionStringBuilder() - { - } + public MinioFileStorageConnectionStringBuilder() + { + } - public MinioFileStorageConnectionStringBuilder(string connectionString) : base(connectionString) - { - } + public MinioFileStorageConnectionStringBuilder(string connectionString) : base(connectionString) + { + } - public string Bucket - { - get => string.IsNullOrEmpty(_bucket) ? "storage" : _bucket; - set => _bucket = value; - } + public string Bucket + { + get => string.IsNullOrEmpty(_bucket) ? "storage" : _bucket; + set => _bucket = value; + } - protected override bool ParseItem(string key, string value) + protected override bool ParseItem(string key, string value) + { + if (String.Equals(key, "Bucket", StringComparison.OrdinalIgnoreCase)) { - if (String.Equals(key, "Bucket", StringComparison.OrdinalIgnoreCase)) - { - Bucket = value; - return true; - } - return base.ParseItem(key, value); + Bucket = value; + return true; } + return base.ParseItem(key, value); + } - public override string ToString() - { - var connectionString = base.ToString(); - if (!string.IsNullOrEmpty(_bucket)) - connectionString += "Bucket=" + Bucket + ";"; - return connectionString; - } + public override string ToString() + { + var connectionString = base.ToString(); + if (!string.IsNullOrEmpty(_bucket)) + connectionString += "Bucket=" + Bucket + ";"; + return connectionString; } } diff --git a/src/Foundatio.Minio/Storage/MinioFileStorageOptions.cs b/src/Foundatio.Minio/Storage/MinioFileStorageOptions.cs index 0c17a10..f855165 100644 --- a/src/Foundatio.Minio/Storage/MinioFileStorageOptions.cs +++ b/src/Foundatio.Minio/Storage/MinioFileStorageOptions.cs @@ -1,27 +1,26 @@ using System; -namespace Foundatio.Storage +namespace Foundatio.Storage; + +public class MinioFileStorageOptions : SharedOptions { - public class MinioFileStorageOptions : SharedOptions + public string ConnectionString { get; set; } + public bool AutoCreateBucket { get; set; } +} + +public class MinioFileStorageOptionsBuilder : SharedOptionsBuilder +{ + public MinioFileStorageOptionsBuilder ConnectionString(string connectionString) { - public string ConnectionString { get; set; } - public bool AutoCreateBucket { get; set; } + if (String.IsNullOrEmpty(connectionString)) + throw new ArgumentNullException(nameof(connectionString)); + Target.ConnectionString = connectionString; + return this; } - public class MinioFileStorageOptionsBuilder : SharedOptionsBuilder + public MinioFileStorageOptionsBuilder AutoCreateBuckets(bool shouldAutoCreateBuckets = true) { - public MinioFileStorageOptionsBuilder ConnectionString(string connectionString) - { - if (String.IsNullOrEmpty(connectionString)) - throw new ArgumentNullException(nameof(connectionString)); - Target.ConnectionString = connectionString; - return this; - } - - public MinioFileStorageOptionsBuilder AutoCreateBuckets(bool shouldAutoCreateBuckets = true) - { - Target.AutoCreateBucket = shouldAutoCreateBuckets; - return this; - } + Target.AutoCreateBucket = shouldAutoCreateBuckets; + return this; } } diff --git a/tests/Foundatio.Minio.Tests/ConnectionStringBuilderTests.cs b/tests/Foundatio.Minio.Tests/ConnectionStringBuilderTests.cs index f6e157f..b974e4b 100644 --- a/tests/Foundatio.Minio.Tests/ConnectionStringBuilderTests.cs +++ b/tests/Foundatio.Minio.Tests/ConnectionStringBuilderTests.cs @@ -1,73 +1,72 @@ using System; using Xunit; -namespace Foundatio.Minio.Tests +namespace Foundatio.Minio.Tests; + +public abstract class ConnectionStringBuilderTests { - public abstract class ConnectionStringBuilderTests - { - protected abstract MinioConnectionStringBuilder CreateConnectionStringBuilder(string connectionString); + protected abstract MinioConnectionStringBuilder CreateConnectionStringBuilder(string connectionString); - protected abstract MinioConnectionStringBuilder CreateConnectionStringBuilder(); + protected abstract MinioConnectionStringBuilder CreateConnectionStringBuilder(); - public virtual void InvalidKeyShouldThrow() - { - var exception = Assert.Throws("connectionString", () => CreateConnectionStringBuilder("wrongaccess=TestAccessKey;SecretKey=TestSecretKey")); - Assert.Equal("The option 'wrongaccess' cannot be recognized in connection string. (Parameter 'connectionString')", exception.Message); - } + public virtual void InvalidKeyShouldThrow() + { + var exception = Assert.Throws("connectionString", () => CreateConnectionStringBuilder("wrongaccess=TestAccessKey;SecretKey=TestSecretKey")); + Assert.Equal("The option 'wrongaccess' cannot be recognized in connection string. (Parameter 'connectionString')", exception.Message); + } - public virtual void CanParseAccessKey() + public virtual void CanParseAccessKey() + { + foreach (string key in new[] { "AccessKey", "AccessKeyId", "Access Key", "Access Key ID", "Id", "accessKey", "access key", "access key id", "id" }) { - foreach (string key in new[] { "AccessKey", "AccessKeyId", "Access Key", "Access Key ID", "Id", "accessKey", "access key", "access key id", "id" }) - { - var connectionStringBuilder = CreateConnectionStringBuilder($"{key}=TestAccessKey;SecretKey=TestSecretKey;"); - Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); - Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); - Assert.Null(connectionStringBuilder.Region); - } + var connectionStringBuilder = CreateConnectionStringBuilder($"{key}=TestAccessKey;SecretKey=TestSecretKey;"); + Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); + Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); + Assert.Null(connectionStringBuilder.Region); } + } - public virtual void CanParseSecretKey() + public virtual void CanParseSecretKey() + { + foreach (string key in new[] { "SecretKey", "Secret Key", "Secret", "secretKey", "secret key", "secret" }) { - foreach (string key in new[] { "SecretKey", "Secret Key", "Secret", "secretKey", "secret key", "secret" }) - { - var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;{key}=TestSecretKey;"); - Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); - Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); - Assert.Null(connectionStringBuilder.Region); - } + var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;{key}=TestSecretKey;"); + Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); + Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); + Assert.Null(connectionStringBuilder.Region); } + } - public virtual void CanParseRegion() + public virtual void CanParseRegion() + { + foreach (string key in new[] { "Region", "region" }) { - foreach (string key in new[] { "Region", "region" }) - { - var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestRegion;"); - Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); - Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); - Assert.Equal("TestRegion", connectionStringBuilder.Region); - } + var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestRegion;"); + Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); + Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); + Assert.Equal("TestRegion", connectionStringBuilder.Region); } + } - public virtual void CanParseEndPoint() + public virtual void CanParseEndPoint() + { + foreach (string key in new[] { "EndPoint", "End Point", "endPoint", "end point" }) { - foreach (string key in new[] { "EndPoint", "End Point", "endPoint", "end point" }) - { - var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestEndPoint;"); - Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); - Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); - Assert.Equal("TestEndPoint", connectionStringBuilder.EndPoint); - } + var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestEndPoint;"); + Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); + Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); + Assert.Equal("TestEndPoint", connectionStringBuilder.EndPoint); } + } - public virtual void CanGenerateConnectionString() - { - var connectionStringBuilder = CreateConnectionStringBuilder(); - connectionStringBuilder.AccessKey = "TestAccessKey"; - connectionStringBuilder.SecretKey = "TestSecretKey"; - connectionStringBuilder.Region = "TestRegion"; - connectionStringBuilder.EndPoint = "TestEndPoint"; + public virtual void CanGenerateConnectionString() + { + var connectionStringBuilder = CreateConnectionStringBuilder(); + connectionStringBuilder.AccessKey = "TestAccessKey"; + connectionStringBuilder.SecretKey = "TestSecretKey"; + connectionStringBuilder.Region = "TestRegion"; + connectionStringBuilder.EndPoint = "TestEndPoint"; - Assert.Equal("AccessKey=TestAccessKey;SecretKey=TestSecretKey;Region=TestRegion;EndPoint=TestEndPoint;", connectionStringBuilder.ToString()); - } + Assert.Equal("AccessKey=TestAccessKey;SecretKey=TestSecretKey;Region=TestRegion;EndPoint=TestEndPoint;", connectionStringBuilder.ToString()); } } diff --git a/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageConnectionStringBuilderTests.cs b/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageConnectionStringBuilderTests.cs index 41fd1e0..03a8e01 100644 --- a/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageConnectionStringBuilderTests.cs +++ b/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageConnectionStringBuilderTests.cs @@ -1,79 +1,78 @@ using Foundatio.Storage; using Xunit; -namespace Foundatio.Minio.Tests.Storage +namespace Foundatio.Minio.Tests.Storage; + +public class MinioFileStorageConnectionStringBuilderTests : ConnectionStringBuilderTests { - public class MinioFileStorageConnectionStringBuilderTests : ConnectionStringBuilderTests + protected override MinioConnectionStringBuilder CreateConnectionStringBuilder(string connectionString) { - protected override MinioConnectionStringBuilder CreateConnectionStringBuilder(string connectionString) - { - return new MinioFileStorageConnectionStringBuilder(connectionString); - } + return new MinioFileStorageConnectionStringBuilder(connectionString); + } - protected override MinioConnectionStringBuilder CreateConnectionStringBuilder() - { - return new MinioFileStorageConnectionStringBuilder(); - } + protected override MinioConnectionStringBuilder CreateConnectionStringBuilder() + { + return new MinioFileStorageConnectionStringBuilder(); + } - [Fact] - public override void InvalidKeyShouldThrow() - { - base.InvalidKeyShouldThrow(); - } + [Fact] + public override void InvalidKeyShouldThrow() + { + base.InvalidKeyShouldThrow(); + } - [Fact] - public override void CanParseAccessKey() - { - base.CanParseAccessKey(); - } + [Fact] + public override void CanParseAccessKey() + { + base.CanParseAccessKey(); + } - [Fact] - public override void CanParseSecretKey() - { - base.CanParseSecretKey(); - } + [Fact] + public override void CanParseSecretKey() + { + base.CanParseSecretKey(); + } - [Fact] - public override void CanParseRegion() - { - base.CanParseRegion(); - } + [Fact] + public override void CanParseRegion() + { + base.CanParseRegion(); + } - [Fact] - public override void CanParseEndPoint() - { - base.CanParseEndPoint(); - } + [Fact] + public override void CanParseEndPoint() + { + base.CanParseEndPoint(); + } - [Fact] - public override void CanGenerateConnectionString() - { - base.CanGenerateConnectionString(); - } + [Fact] + public override void CanGenerateConnectionString() + { + base.CanGenerateConnectionString(); + } - [Fact] - public void CanParseBucket() + [Fact] + public void CanParseBucket() + { + foreach (var key in new[] { "Bucket", "bucket" }) { - foreach (var key in new[] { "Bucket", "bucket" }) - { - var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestBucket"); - Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); - Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); - Assert.Equal("TestBucket", ((MinioFileStorageConnectionStringBuilder)connectionStringBuilder).Bucket); - Assert.Null(connectionStringBuilder.Region); - } + var connectionStringBuilder = CreateConnectionStringBuilder($"AccessKey=TestAccessKey;SecretKey=TestSecretKey;{key}=TestBucket"); + Assert.Equal("TestAccessKey", connectionStringBuilder.AccessKey); + Assert.Equal("TestSecretKey", connectionStringBuilder.SecretKey); + Assert.Equal("TestBucket", ((MinioFileStorageConnectionStringBuilder)connectionStringBuilder).Bucket); + Assert.Null(connectionStringBuilder.Region); } + } - [Fact] - public void CanGenerateConnectionStringWithBucket() - { - var connectionStringBuilder = (MinioFileStorageConnectionStringBuilder)CreateConnectionStringBuilder(); - connectionStringBuilder.AccessKey = "TestAccessKey"; - connectionStringBuilder.SecretKey = "TestSecretKey"; - connectionStringBuilder.Region = "TestRegion"; - connectionStringBuilder.Bucket = "TestBucket"; + [Fact] + public void CanGenerateConnectionStringWithBucket() + { + var connectionStringBuilder = (MinioFileStorageConnectionStringBuilder)CreateConnectionStringBuilder(); + connectionStringBuilder.AccessKey = "TestAccessKey"; + connectionStringBuilder.SecretKey = "TestSecretKey"; + connectionStringBuilder.Region = "TestRegion"; + connectionStringBuilder.Bucket = "TestBucket"; - Assert.Equal("AccessKey=TestAccessKey;SecretKey=TestSecretKey;Region=TestRegion;Bucket=TestBucket;", connectionStringBuilder.ToString()); - } + Assert.Equal("AccessKey=TestAccessKey;SecretKey=TestSecretKey;Region=TestRegion;Bucket=TestBucket;", connectionStringBuilder.ToString()); } } diff --git a/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageTests.cs b/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageTests.cs index 2cf5434..a2fb73a 100644 --- a/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageTests.cs +++ b/tests/Foundatio.Minio.Tests/Storage/MinioFileStorageTests.cs @@ -6,136 +6,135 @@ using Xunit; using Xunit.Abstractions; -namespace Foundatio.Minio.Tests.Storage +namespace Foundatio.Minio.Tests.Storage; + +public class MinioFileStorageTests : FileStorageTestsBase { - public class MinioFileStorageTests : FileStorageTestsBase - { - private const string BUCKET_NAME = "foundatio"; + private const string BUCKET_NAME = "foundatio"; - public MinioFileStorageTests(ITestOutputHelper output) : base(output) { } + public MinioFileStorageTests(ITestOutputHelper output) : base(output) { } - protected override IFileStorage GetStorage() - { - var section = Configuration.GetSection("Minio"); - var connectionStringBuilder = new MinioFileStorageConnectionStringBuilder - { - AccessKey = section["ACCESS_KEY_ID"], - SecretKey = section["SECRET_ACCESS_KEY"], - EndPoint = section["ENDPOINT"], - Bucket = BUCKET_NAME - }; - if (String.IsNullOrEmpty(connectionStringBuilder.AccessKey) || String.IsNullOrEmpty(connectionStringBuilder.SecretKey)) - return null; - - return new MinioFileStorage(o => o.ConnectionString(connectionStringBuilder.ToString()).AutoCreateBuckets().LoggerFactory(Log)); - } - - [Fact] - public override Task CanGetEmptyFileListOnMissingDirectoryAsync() - { - return base.CanGetEmptyFileListOnMissingDirectoryAsync(); - } + protected override IFileStorage GetStorage() + { + var section = Configuration.GetSection("Minio"); + var connectionStringBuilder = new MinioFileStorageConnectionStringBuilder + { + AccessKey = section["ACCESS_KEY_ID"], + SecretKey = section["SECRET_ACCESS_KEY"], + EndPoint = section["ENDPOINT"], + Bucket = BUCKET_NAME + }; + if (String.IsNullOrEmpty(connectionStringBuilder.AccessKey) || String.IsNullOrEmpty(connectionStringBuilder.SecretKey)) + return null; + + return new MinioFileStorage(o => o.ConnectionString(connectionStringBuilder.ToString()).AutoCreateBuckets().LoggerFactory(Log)); + } - [Fact] - public override Task CanGetFileListForSingleFolderAsync() - { - return base.CanGetFileListForSingleFolderAsync(); - } + [Fact] + public override Task CanGetEmptyFileListOnMissingDirectoryAsync() + { + return base.CanGetEmptyFileListOnMissingDirectoryAsync(); + } - [Fact] - public override Task CanGetPagedFileListForSingleFolderAsync() - { - return base.CanGetPagedFileListForSingleFolderAsync(); - } + [Fact] + public override Task CanGetFileListForSingleFolderAsync() + { + return base.CanGetFileListForSingleFolderAsync(); + } - [Fact] - public override Task CanGetFileInfoAsync() - { - return base.CanGetFileInfoAsync(); - } + [Fact] + public override Task CanGetPagedFileListForSingleFolderAsync() + { + return base.CanGetPagedFileListForSingleFolderAsync(); + } - [Fact] - public override Task CanGetNonExistentFileInfoAsync() - { - return base.CanGetNonExistentFileInfoAsync(); - } + [Fact] + public override Task CanGetFileInfoAsync() + { + return base.CanGetFileInfoAsync(); + } - [Fact] - public override Task CanSaveFilesAsync() - { - return base.CanSaveFilesAsync(); - } + [Fact] + public override Task CanGetNonExistentFileInfoAsync() + { + return base.CanGetNonExistentFileInfoAsync(); + } - [Fact] - public override Task CanManageFilesAsync() - { - return base.CanManageFilesAsync(); - } + [Fact] + public override Task CanSaveFilesAsync() + { + return base.CanSaveFilesAsync(); + } - [Fact] - public override Task CanRenameFilesAsync() - { - return base.CanRenameFilesAsync(); - } + [Fact] + public override Task CanManageFilesAsync() + { + return base.CanManageFilesAsync(); + } - [Fact] - public override Task CanConcurrentlyManageFilesAsync() - { - return base.CanConcurrentlyManageFilesAsync(); - } + [Fact] + public override Task CanRenameFilesAsync() + { + return base.CanRenameFilesAsync(); + } - [Fact] - public override void CanUseDataDirectory() - { - base.CanUseDataDirectory(); - } + [Fact] + public override Task CanConcurrentlyManageFilesAsync() + { + return base.CanConcurrentlyManageFilesAsync(); + } - [Fact] - public override Task CanDeleteEntireFolderAsync() - { - return base.CanDeleteEntireFolderAsync(); - } + [Fact] + public override void CanUseDataDirectory() + { + base.CanUseDataDirectory(); + } - [Fact] - public override Task CanDeleteEntireFolderWithWildcardAsync() - { - return base.CanDeleteEntireFolderWithWildcardAsync(); - } + [Fact] + public override Task CanDeleteEntireFolderAsync() + { + return base.CanDeleteEntireFolderAsync(); + } - [Fact] - public override Task CanDeleteFolderWithMultiFolderWildcardsAsync() - { - return base.CanDeleteFolderWithMultiFolderWildcardsAsync(); - } + [Fact] + public override Task CanDeleteEntireFolderWithWildcardAsync() + { + return base.CanDeleteEntireFolderWithWildcardAsync(); + } - [Fact] - public override Task CanDeleteSpecificFilesAsync() - { - return base.CanDeleteSpecificFilesAsync(); - } + [Fact] + public override Task CanDeleteFolderWithMultiFolderWildcardsAsync() + { + return base.CanDeleteFolderWithMultiFolderWildcardsAsync(); + } - [Fact] - public override Task CanDeleteNestedFolderAsync() - { - return base.CanDeleteNestedFolderAsync(); - } + [Fact] + public override Task CanDeleteSpecificFilesAsync() + { + return base.CanDeleteSpecificFilesAsync(); + } - [Fact] - public override Task CanDeleteSpecificFilesInNestedFolderAsync() - { - return base.CanDeleteSpecificFilesInNestedFolderAsync(); - } + [Fact] + public override Task CanDeleteNestedFolderAsync() + { + return base.CanDeleteNestedFolderAsync(); + } - [Fact] - public override Task CanRoundTripSeekableStreamAsync() - { - return base.CanRoundTripSeekableStreamAsync(); - } + [Fact] + public override Task CanDeleteSpecificFilesInNestedFolderAsync() + { + return base.CanDeleteSpecificFilesInNestedFolderAsync(); + } - [Fact] - public override Task WillRespectStreamOffsetAsync() - { - return base.WillRespectStreamOffsetAsync(); - } + [Fact] + public override Task CanRoundTripSeekableStreamAsync() + { + return base.CanRoundTripSeekableStreamAsync(); + } + + [Fact] + public override Task WillRespectStreamOffsetAsync() + { + return base.WillRespectStreamOffsetAsync(); } }