mirror of https://github.com/abpframework/abp.git
15 changed files with 362 additions and 45 deletions
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpBlobStoringModule), |
||||
|
typeof(AbpCachingModule))] |
||||
|
public class AbpBlobStoringAwsModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -1,10 +0,0 @@ |
|||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace Volo.Abp.BlobStoring.Azure |
|
||||
{ |
|
||||
[DependsOn(typeof(AbpBlobStoringModule))] |
|
||||
public class AbpBlobStoringAzureModule : AbpModule |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,22 @@ |
|||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
public class DefaultAwsBlobNameCalculator : IAwsBlobNameCalculator, ITransientDependency |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
|
||||
|
public DefaultAwsBlobNameCalculator(ICurrentTenant currentTenant) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
} |
||||
|
|
||||
|
public virtual string Calculate(BlobProviderArgs args) |
||||
|
{ |
||||
|
return CurrentTenant.Id == null |
||||
|
? $"host/{args.BlobName}" |
||||
|
: $"tenants/{CurrentTenant.Id.Value.ToString("D")}/{args.BlobName}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<UserSecretsId>9f0d2c00-80c1-435b-bfab-2c39c8249091</UserSecretsId> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Aws\Volo.Abp.BlobStoring.Aws.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
public class AbpBlobStoringAwsTestCommonBase : AbpIntegratedTest<AbpBlobStoringAwsTestCommonModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class AbpBlobStoringAwsTestBase : AbpIntegratedTest<AbpBlobStoringAwsTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Amazon.S3.Model; |
||||
|
using Amazon.S3.Util; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This module will not try to connect to aws.
|
||||
|
/// </summary>
|
||||
|
[DependsOn( |
||||
|
typeof(AbpBlobStoringAwsModule), |
||||
|
typeof(AbpBlobStoringTestModule) |
||||
|
)] |
||||
|
public class AbpBlobStoringAwsTestCommonModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpBlobStoringAwsTestCommonModule) |
||||
|
)] |
||||
|
public class AbpBlobStoringAwsTestModule : AbpModule |
||||
|
{ |
||||
|
private const string UserSecretsId = "9f0d2c00-80c1-435b-bfab-2c39c8249091"; |
||||
|
|
||||
|
private readonly string _randomContainerName = "abp-aws-test-container-" + Guid.NewGuid().ToString("N"); |
||||
|
|
||||
|
private AwsBlobProviderConfiguration _configuration; |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(builderAction: builder => |
||||
|
{ |
||||
|
builder.AddUserSecrets(UserSecretsId); |
||||
|
})); |
||||
|
|
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
var accessKeyId = configuration["Aws:AccessKeyId"]; |
||||
|
var secretAccessKey = configuration["Aws:SecretAccessKey"]; |
||||
|
var region = configuration["Aws:Region"]; |
||||
|
|
||||
|
Configure<AbpBlobStoringOptions>(options => |
||||
|
{ |
||||
|
options.Containers.ConfigureAll((containerName, containerConfiguration) => |
||||
|
{ |
||||
|
containerConfiguration.UseAws(aws => |
||||
|
{ |
||||
|
aws.AccessKeyId = accessKeyId; |
||||
|
aws.SecretAccessKey = secretAccessKey; |
||||
|
aws.Region = region; |
||||
|
aws.CreateContainerIfNotExists = true; |
||||
|
|
||||
|
_configuration = aws; |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationShutdown(ApplicationShutdownContext context) |
||||
|
{ |
||||
|
AsyncHelper.RunSync(() => DeleteBucketAsync(context)); |
||||
|
} |
||||
|
|
||||
|
private async Task DeleteBucketAsync(ApplicationShutdownContext context) |
||||
|
{ |
||||
|
var amazonS3Client = await context.ServiceProvider.GetService<IAmazonS3ClientFactory>() |
||||
|
.GetAmazonS3Client(_configuration); |
||||
|
|
||||
|
if (await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, _randomContainerName)) |
||||
|
{ |
||||
|
var blobs = await amazonS3Client.ListObjectsAsync(_randomContainerName); |
||||
|
|
||||
|
if (blobs.S3Objects.Any()) |
||||
|
{ |
||||
|
await amazonS3Client.DeleteObjectsAsync(new DeleteObjectsRequest |
||||
|
{ |
||||
|
BucketName = _randomContainerName, |
||||
|
Objects = blobs.S3Objects.Select(o => new KeyVersion {Key = o.Key}).ToList() |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
await amazonS3Client.DeleteBucketAsync(_randomContainerName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
/* |
||||
|
//Please set the correct connection string in secrets.json and continue the test.
|
||||
|
|
||||
|
public class AwsBlobContainer_Tests : BlobContainer_Tests<AbpBlobStoringAwsTestModule> |
||||
|
{ |
||||
|
public AwsBlobContainer_Tests() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using System; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
public class AwsBlobNameCalculatorTests : AbpBlobStoringAwsTestCommonBase |
||||
|
{ |
||||
|
private readonly IAwsBlobNameCalculator _calculator; |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
|
||||
|
private const string AwsContainerName = "/"; |
||||
|
private const string AwsSeparator = "/"; |
||||
|
|
||||
|
public AwsBlobNameCalculatorTests() |
||||
|
{ |
||||
|
_calculator = GetRequiredService<IAwsBlobNameCalculator>(); |
||||
|
_currentTenant = GetRequiredService<ICurrentTenant>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Default_Settings() |
||||
|
{ |
||||
|
_calculator.Calculate( |
||||
|
GetArgs("my-container", "my-blob") |
||||
|
).ShouldBe($"host{AwsSeparator}my-blob"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Default_Settings_With_TenantId() |
||||
|
{ |
||||
|
var tenantId = Guid.NewGuid(); |
||||
|
|
||||
|
using (_currentTenant.Change(tenantId)) |
||||
|
{ |
||||
|
_calculator.Calculate( |
||||
|
GetArgs("my-container", "my-blob") |
||||
|
).ShouldBe($"tenants{AwsSeparator}{tenantId:D}{AwsSeparator}my-blob"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static BlobProviderArgs GetArgs( |
||||
|
string containerName, |
||||
|
string blobName) |
||||
|
{ |
||||
|
return new BlobProviderGetArgs( |
||||
|
containerName, |
||||
|
new BlobContainerConfiguration().UseAws(x => |
||||
|
{ |
||||
|
x.ContainerName = containerName; |
||||
|
}), |
||||
|
blobName |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Aws |
||||
|
{ |
||||
|
public class DefaultAwsBlobNamingNormalizerProviderTests : AbpBlobStoringAwsTestCommonBase |
||||
|
{ |
||||
|
private readonly IBlobNamingNormalizer _blobNamingNormalizer; |
||||
|
|
||||
|
public DefaultAwsBlobNamingNormalizerProviderTests() |
||||
|
{ |
||||
|
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Lowercase() |
||||
|
{ |
||||
|
var filename = "ThisIsMyContainerName"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("thisismycontainername"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Only_Letters_Numbers_Dash() |
||||
|
{ |
||||
|
var filename = ",./this-i,./s-my-c,./ont,./ai+*/.=!@#$n^&*er-name.+/"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("this-is-my-container-name"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Dash() |
||||
|
{ |
||||
|
var filename = "-this--is----my-container----name-"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("this-is-my-container-name"); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Min_Length() |
||||
|
{ |
||||
|
var filename = "a"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.Length.ShouldBeGreaterThanOrEqualTo(3); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Max_Length() |
||||
|
{ |
||||
|
var filename = "abpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabp"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.Length.ShouldBeLessThanOrEqualTo(63); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue