Browse Source

Asset folder per app.

pull/732/head
Sebastian 5 years ago
parent
commit
76f496db91
  1. 1
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/ConfigAppPlansProvider.cs
  2. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetExtensions.cs
  3. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetPermanentDeleter.cs
  4. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs
  5. 80
      backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs
  6. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs
  7. 12
      backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs
  8. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/RebuildFiles.cs
  9. 2
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  10. 2
      backend/src/Squidex.Infrastructure.RabbitMq/Squidex.Infrastructure.RabbitMq.csproj
  11. 2
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  12. 2
      backend/src/Squidex.Web/Services/UrlGenerator.cs
  13. 23
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  14. 12
      backend/src/Squidex/Squidex.csproj
  15. 14
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs
  16. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs
  17. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs
  18. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs
  19. 158
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs
  20. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs
  21. 18
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs

1
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/ConfigAppPlansProvider.cs

@ -68,7 +68,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
{ {
Guard.NotNull(app, nameof(app)); Guard.NotNull(app, nameof(app));
return GetPlanUpgrade(app.Plan?.PlanId); return GetPlanUpgrade(app.Plan?.PlanId);
} }

2
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetExtensions.cs

@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
using (var stream = DefaultPools.MemoryStream.GetStream()) using (var stream = DefaultPools.MemoryStream.GetStream())
{ {
await assetFileStore.DownloadAsync(appId, id, fileVersion, stream); await assetFileStore.DownloadAsync(appId, id, fileVersion, null, stream);
stream.Position = 0; stream.Position = 0;

2
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetPermanentDeleter.cs

@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
try try
{ {
await assetFileStore.DeleteAsync(assetDeleted.AppId.Id, assetDeleted.AssetId, version); await assetFileStore.DeleteAsync(assetDeleted.AppId.Id, assetDeleted.AssetId, version, null);
} }
catch (AssetNotFoundException) catch (AssetNotFoundException)
{ {

4
backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs

@ -127,7 +127,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
await writer.WriteBlobAsync(GetName(assetId, fileVersion), stream => await writer.WriteBlobAsync(GetName(assetId, fileVersion), stream =>
{ {
return assetFileStore.DownloadAsync(appId, assetId, fileVersion, stream); return assetFileStore.DownloadAsync(appId, assetId, fileVersion, null, stream);
}); });
} }
catch (AssetNotFoundException) catch (AssetNotFoundException)
@ -142,7 +142,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
await reader.ReadBlobAsync(GetName(assetId, fileVersion), stream => await reader.ReadBlobAsync(GetName(assetId, fileVersion), stream =>
{ {
return assetFileStore.UploadAsync(appId, assetId, fileVersion, stream); return assetFileStore.UploadAsync(appId, assetId, fileVersion, null, stream);
}); });
} }
catch (FileNotFoundException) catch (FileNotFoundException)

80
backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs

@ -27,53 +27,53 @@ namespace Squidex.Domain.Apps.Entities.Assets
this.options = options.Value; this.options = options.Value;
} }
public string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion) public string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion, string? suffix)
{ {
var fileName = GetFileName(appId, id, fileVersion); var fileName = GetFileName(appId, id, fileVersion, suffix);
return assetStore.GeneratePublicUrl(fileName); return assetStore.GeneratePublicUrl(fileName);
} }
public async Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, public async Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, string? suffix,
CancellationToken ct = default) CancellationToken ct = default)
{ {
try try
{ {
var fileNameNew = GetFileName(appId, id, fileVersion); var fileNameNew = GetFileName(appId, id, fileVersion, suffix);
return await assetStore.GetSizeAsync(fileNameNew, ct); return await assetStore.GetSizeAsync(fileNameNew, ct);
} }
catch (AssetNotFoundException) catch (AssetNotFoundException) when (!options.FolderPerApp)
{ {
var fileNameOld = GetFileName(id, fileVersion); var fileNameOld = GetFileName(id, fileVersion, suffix);
return await assetStore.GetSizeAsync(fileNameOld, ct); return await assetStore.GetSizeAsync(fileNameOld, ct);
} }
} }
public async Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default, public async Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, string? suffix, Stream stream, BytesRange range = default,
CancellationToken ct = default) CancellationToken ct = default)
{ {
try try
{ {
var fileNameNew = GetFileName(appId, id, fileVersion); var fileNameNew = GetFileName(appId, id, fileVersion, suffix);
await assetStore.DownloadAsync(fileNameNew, stream, range, ct); await assetStore.DownloadAsync(fileNameNew, stream, range, ct);
} }
catch (AssetNotFoundException) catch (AssetNotFoundException) when (!options.FolderPerApp)
{ {
var fileNameOld = GetFileName(id, fileVersion); var fileNameOld = GetFileName(id, fileVersion, suffix);
await assetStore.DownloadAsync(fileNameOld, stream, range, ct); await assetStore.DownloadAsync(fileNameOld, stream, range, ct);
} }
} }
public Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, public Task UploadAsync(DomainId appId, DomainId id, long fileVersion, string? suffix, Stream stream, bool overwrite = true,
CancellationToken ct = default) CancellationToken ct = default)
{ {
var fileName = GetFileName(appId, id, fileVersion); var fileName = GetFileName(appId, id, fileVersion, suffix);
return assetStore.UploadAsync(fileName, stream, true, ct); return assetStore.UploadAsync(fileName, stream, overwrite, ct);
} }
public Task UploadAsync(string tempFile, Stream stream, public Task UploadAsync(string tempFile, Stream stream,
@ -82,22 +82,29 @@ namespace Squidex.Domain.Apps.Entities.Assets
return assetStore.UploadAsync(tempFile, stream, false, ct); return assetStore.UploadAsync(tempFile, stream, false, ct);
} }
public Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, public Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, string? suffix,
CancellationToken ct = default) CancellationToken ct = default)
{ {
var fileName = GetFileName(appId, id, fileVersion); var fileName = GetFileName(appId, id, fileVersion, suffix);
return assetStore.CopyAsync(tempFile, fileName, ct); return assetStore.CopyAsync(tempFile, fileName, ct);
} }
public async Task DeleteAsync(DomainId appId, DomainId id, long fileVersion) public Task DeleteAsync(DomainId appId, DomainId id, long fileVersion, string? suffix)
{ {
var fileNameOld = GetFileName(id, fileVersion); var fileNameOld = GetFileName(id, fileVersion, suffix);
var fileNameNew = GetFileName(appId, id, fileVersion); var fileNameNew = GetFileName(appId, id, fileVersion, suffix);
await Task.WhenAll( if (options.FolderPerApp)
assetStore.DeleteAsync(fileNameOld), {
assetStore.DeleteAsync(fileNameNew)); return assetStore.DeleteAsync(fileNameNew);
}
else
{
return Task.WhenAll(
assetStore.DeleteAsync(fileNameOld),
assetStore.DeleteAsync(fileNameNew));
}
} }
public Task DeleteAsync(string tempFile) public Task DeleteAsync(string tempFile)
@ -105,20 +112,41 @@ namespace Squidex.Domain.Apps.Entities.Assets
return assetStore.DeleteAsync(tempFile); return assetStore.DeleteAsync(tempFile);
} }
private static string GetFileName(DomainId id, long fileVersion) private static string GetFileName(DomainId id, long fileVersion, string? suffix)
{ {
return $"{id}_{fileVersion}"; if (!string.IsNullOrWhiteSpace(suffix))
{
return $"{id}_{fileVersion}_{suffix}";
}
else
{
return $"{id}_{fileVersion}";
}
} }
private string GetFileName(DomainId appId, DomainId id, long fileVersion) private string GetFileName(DomainId appId, DomainId id, long fileVersion, string? suffix)
{ {
if (options.FolderPerApp) if (options.FolderPerApp)
{ {
return $"{appId}/{id}_{fileVersion}"; if (!string.IsNullOrWhiteSpace(suffix))
{
return $"derived/{appId}/{id}_{fileVersion}_{suffix}";
}
else
{
return $"{appId}/{id}_{fileVersion}";
}
} }
else else
{ {
return $"{appId}_{id}_{fileVersion}"; if (!string.IsNullOrWhiteSpace(suffix))
{
return $"{appId}_{id}_{fileVersion}_{suffix}";
}
else
{
return $"{appId}_{id}_{fileVersion}";
}
} }
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs

@ -142,7 +142,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
try try
{ {
await assetFileStore.CopyAsync(tempFile, asset.AppId.Id, asset.AssetId, asset.FileVersion); await assetFileStore.CopyAsync(tempFile, asset.AppId.Id, asset.AssetId, asset.FileVersion, null);
} }
catch (AssetAlreadyExistsException) when (context.Command is not UpsertAsset) catch (AssetAlreadyExistsException) when (context.Command is not UpsertAsset)
{ {

12
backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs

@ -15,20 +15,20 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
public interface IAssetFileStore public interface IAssetFileStore
{ {
string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion); string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion, string? suffix);
Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default); Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, string? suffix, CancellationToken ct = default);
Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default); Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, string? suffix, CancellationToken ct = default);
Task UploadAsync(string tempFile, Stream stream, CancellationToken ct = default); Task UploadAsync(string tempFile, Stream stream, CancellationToken ct = default);
Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, CancellationToken ct = default); Task UploadAsync(DomainId appId, DomainId id, long fileVersion, string? suffix, Stream stream, bool overwrite = true, CancellationToken ct = default);
Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default); Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, string? suffix, Stream stream, BytesRange range = default, CancellationToken ct = default);
Task DeleteAsync(string tempFile); Task DeleteAsync(string tempFile);
Task DeleteAsync(DomainId appId, DomainId id, long fileVersion); Task DeleteAsync(DomainId appId, DomainId id, long fileVersion, string? suffix);
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Assets/RebuildFiles.cs

@ -58,13 +58,13 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
try try
{ {
await assetFileStore.GetFileSizeAsync(appId.Id, id, fileVersion, ct); await assetFileStore.GetFileSizeAsync(appId.Id, id, fileVersion, null, ct);
} }
catch (AssetNotFoundException) catch (AssetNotFoundException)
{ {
DummyStream.Position = 0; DummyStream.Position = 0;
await assetFileStore.UploadAsync(appId.Id, id, fileVersion, DummyStream, ct); await assetFileStore.UploadAsync(appId.Id, id, fileVersion, null, DummyStream, ct: ct);
} }
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj

@ -17,7 +17,7 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" /> <ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="27.1.0" /> <PackageReference Include="CsvHelper" Version="27.1.1" />
<PackageReference Include="Elasticsearch.Net" Version="7.13.1" /> <PackageReference Include="Elasticsearch.Net" Version="7.13.1" />
<PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" /> <PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Fody" Version="6.5.1"> <PackageReference Include="Fody" Version="6.5.1">

2
backend/src/Squidex.Infrastructure.RabbitMq/Squidex.Infrastructure.RabbitMq.csproj

@ -10,7 +10,7 @@
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" /> <PackageReference Include="RabbitMQ.Client" Version="6.2.2" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />

2
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -25,7 +25,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NJsonSchema" Version="10.4.4" /> <PackageReference Include="NJsonSchema" Version="10.4.4" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="1.5.0" /> <PackageReference Include="Squidex.Assets" Version="1.8.0" />
<PackageReference Include="Squidex.Caching" Version="1.8.0" /> <PackageReference Include="Squidex.Caching" Version="1.8.0" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="1.9.0" /> <PackageReference Include="Squidex.Hosting.Abstractions" Version="1.9.0" />
<PackageReference Include="Squidex.Log" Version="1.4.0" /> <PackageReference Include="Squidex.Log" Version="1.4.0" />

2
backend/src/Squidex.Web/Services/UrlGenerator.cs

@ -61,7 +61,7 @@ namespace Squidex.Web.Services
public string? AssetSource(NamedId<DomainId> appId, DomainId assetId, long fileVersion) public string? AssetSource(NamedId<DomainId> appId, DomainId assetId, long fileVersion)
{ {
return assetFileStore.GeneratePublicUrl(appId.Id, assetId, fileVersion); return assetFileStore.GeneratePublicUrl(appId.Id, assetId, fileVersion, null);
} }
public string AssetsUI(NamedId<DomainId> appId, string? query = null) public string AssetsUI(NamedId<DomainId> appId, string? query = null)

23
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -36,7 +36,6 @@ namespace Squidex.Areas.Api.Controllers.Assets
private readonly IAssetFileStore assetFileStore; private readonly IAssetFileStore assetFileStore;
private readonly IAssetQueryService assetQuery; private readonly IAssetQueryService assetQuery;
private readonly IAssetLoader assetLoader; private readonly IAssetLoader assetLoader;
private readonly IAssetStore assetStore;
private readonly IAssetThumbnailGenerator assetThumbnailGenerator; private readonly IAssetThumbnailGenerator assetThumbnailGenerator;
public AssetContentController( public AssetContentController(
@ -44,14 +43,12 @@ namespace Squidex.Areas.Api.Controllers.Assets
IAssetFileStore assetFileStore, IAssetFileStore assetFileStore,
IAssetQueryService assetQuery, IAssetQueryService assetQuery,
IAssetLoader assetLoader, IAssetLoader assetLoader,
IAssetStore assetStore,
IAssetThumbnailGenerator assetThumbnailGenerator) IAssetThumbnailGenerator assetThumbnailGenerator)
: base(commandBus) : base(commandBus)
{ {
this.assetFileStore = assetFileStore; this.assetFileStore = assetFileStore;
this.assetQuery = assetQuery; this.assetQuery = assetQuery;
this.assetLoader = assetLoader; this.assetLoader = assetLoader;
this.assetStore = assetStore;
this.assetThumbnailGenerator = assetThumbnailGenerator; this.assetThumbnailGenerator = assetThumbnailGenerator;
} }
@ -162,21 +159,21 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
callback = async (bodyStream, range, ct) => callback = async (bodyStream, range, ct) =>
{ {
var resizedAsset = $"{asset.AppId.Id}_{asset.Id}_{asset.FileVersion}_{resizeOptions}";
if (request.ForceResize) if (request.ForceResize)
{ {
await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, true, ct); await ResizeAsync(asset, bodyStream, resizeOptions, true, ct);
} }
else else
{ {
try try
{ {
await assetStore.DownloadAsync(resizedAsset, bodyStream, ct: ct); var suffix = resizeOptions.ToString();
await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, bodyStream, ct: ct);
} }
catch (AssetNotFoundException) catch (AssetNotFoundException)
{ {
await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, false, ct); await ResizeAsync(asset, bodyStream, resizeOptions, false, ct);
} }
} }
}; };
@ -187,7 +184,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
callback = async (bodyStream, range, ct) => callback = async (bodyStream, range, ct) =>
{ {
await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, bodyStream, range, ct); await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, null, bodyStream, range, ct);
}; };
} }
@ -202,8 +199,10 @@ namespace Squidex.Areas.Api.Controllers.Assets
}; };
} }
private async Task ResizeAsync(IAssetEntity asset, Stream bodyStream, string fileName, ResizeOptions resizeOptions, bool overwrite, CancellationToken ct) private async Task ResizeAsync(IAssetEntity asset, Stream bodyStream, ResizeOptions resizeOptions, bool overwrite, CancellationToken ct)
{ {
var suffix = resizeOptions.ToString();
using (Profiler.Trace("Resize")) using (Profiler.Trace("Resize"))
{ {
using (var sourceStream = GetTempStream()) using (var sourceStream = GetTempStream())
@ -212,7 +211,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
using (Profiler.Trace("ResizeDownload")) using (Profiler.Trace("ResizeDownload"))
{ {
await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, sourceStream); await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, null, sourceStream);
sourceStream.Position = 0; sourceStream.Position = 0;
} }
@ -234,7 +233,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
using (Profiler.Trace("ResizeUpload")) using (Profiler.Trace("ResizeUpload"))
{ {
await assetStore.UploadAsync(fileName, destinationStream, overwrite); await assetFileStore.UploadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, destinationStream, overwrite);
destinationStream.Position = 0; destinationStream.Position = 0;
} }
} }

12
backend/src/Squidex/Squidex.csproj

@ -59,12 +59,12 @@
<PackageReference Include="Orleans.Providers.MongoDB" Version="3.3.1" /> <PackageReference Include="Orleans.Providers.MongoDB" Version="3.3.1" />
<PackageReference Include="OrleansDashboard" Version="3.1.0" /> <PackageReference Include="OrleansDashboard" Version="3.1.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="4.8.10" PrivateAssets="all" /> <PackageReference Include="ReportGenerator" Version="4.8.11" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="1.5.0" /> <PackageReference Include="Squidex.Assets.Azure" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="1.5.0" /> <PackageReference Include="Squidex.Assets.GoogleCloud" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.FTP" Version="1.5.0" /> <PackageReference Include="Squidex.Assets.FTP" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.Mongo" Version="1.5.0" /> <PackageReference Include="Squidex.Assets.Mongo" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.S3" Version="1.5.0" /> <PackageReference Include="Squidex.Assets.S3" Version="1.8.0" />
<PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" /> <PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="7.4.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="7.4.0" />
<PackageReference Include="Squidex.Hosting" Version="1.9.0" /> <PackageReference Include="Squidex.Hosting" Version="1.9.0" />

14
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs

@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.On(Envelope.Create(@event).SetRestored()); await sut.On(Envelope.Create(@event).SetRestored());
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, A<long>._)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, A<long>._, null))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -72,10 +72,10 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.On(Envelope.Create(@event).SetEventStreamNumber(2)); await sut.On(Envelope.Create(@event).SetEventStreamNumber(2));
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0, null))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1, null))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -84,12 +84,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() };
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0, null))
.Throws(new AssetNotFoundException("fileName")); .Throws(new AssetNotFoundException("fileName"));
await sut.On(Envelope.Create(@event).SetEventStreamNumber(2)); await sut.On(Envelope.Create(@event).SetEventStreamNumber(2));
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1, null))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -98,12 +98,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() };
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0, null))
.Throws(new InvalidOperationException()); .Throws(new InvalidOperationException());
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.On(Envelope.Create(@event).SetEventStreamNumber(2))); await Assert.ThrowsAsync<InvalidOperationException>(() => sut.On(Envelope.Create(@event).SetEventStreamNumber(2)));
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1, null))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
} }

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs

@ -217,7 +217,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
Assert.Equal(Cleanup(expected), Cleanup(result)); Assert.Equal(Cleanup(expected), Cleanup(result));
A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -280,16 +280,16 @@ namespace Squidex.Domain.Apps.Entities.Assets
Assert.Equal(Cleanup(expected), Cleanup(result)); Assert.Equal(Cleanup(expected), Cleanup(result));
A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
private void SetupText(DomainId id, byte[] bytes) private void SetupText(DomainId id, byte[] bytes)
{ {
A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, id, 0, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, id, 0, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.Invokes(x => .Invokes(x =>
{ {
var stream = x.GetArgument<Stream>(3)!; var stream = x.GetArgument<Stream>(4)!;
stream.Write(bytes); stream.Write(bytes);
}); });

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs

@ -250,7 +250,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
Assert.Equal(Cleanup(expected), Cleanup(result)); Assert.Equal(Cleanup(expected), Cleanup(result));
A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -319,16 +319,16 @@ namespace Squidex.Domain.Apps.Entities.Assets
Assert.Equal(Cleanup(expected), Cleanup(result)); Assert.Equal(Cleanup(expected), Cleanup(result));
A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
private void SetupText(DomainId id, byte[] bytes) private void SetupText(DomainId id, byte[] bytes)
{ {
A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, id, 0, A<Stream>._, A<BytesRange>._, A<CancellationToken>._)) A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, id, 0, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
.Invokes(x => .Invokes(x =>
{ {
var stream = x.GetArgument<Stream>(3)!; var stream = x.GetArgument<Stream>(4)!;
stream.Write(bytes); stream.Write(bytes);
}); });

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs

@ -119,7 +119,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.BackupEventAsync(AppEvent(@event), context); await sut.BackupEventAsync(AppEvent(@event), context);
A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, assetStream, default, default)) A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
A.CallTo(() => context.Writer.WriteBlobAsync($"{assetId}_{version}.asset", A<Func<Stream, Task>>._)) A.CallTo(() => context.Writer.WriteBlobAsync($"{assetId}_{version}.asset", A<Func<Stream, Task>>._))
.Invokes((string _, Func<Stream, Task> handler) => handler(assetStream)); .Invokes((string _, Func<Stream, Task> handler) => handler(assetStream));
A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, assetStream, default, default)) A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, default))
.Throws(new AssetNotFoundException(assetId.ToString())); .Throws(new AssetNotFoundException(assetId.ToString()));
await sut.BackupEventAsync(AppEvent(@event), context); await sut.BackupEventAsync(AppEvent(@event), context);
@ -183,7 +183,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.RestoreEventAsync(AppEvent(@event), context); await sut.RestoreEventAsync(AppEvent(@event), context);
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, assetStream, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, null, assetStream, true, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -199,7 +199,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.RestoreEventAsync(AppEvent(@event), context); await sut.RestoreEventAsync(AppEvent(@event), context);
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, assetStream, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, null, assetStream, true, default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }

158
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,59 +23,79 @@ namespace Squidex.Domain.Apps.Entities.Assets
private readonly DomainId appId = DomainId.NewGuid(); private readonly DomainId appId = DomainId.NewGuid();
private readonly DomainId assetId = DomainId.NewGuid(); private readonly DomainId assetId = DomainId.NewGuid();
private readonly long assetFileVersion = 21; private readonly long assetFileVersion = 21;
private readonly string fileNameOld;
private readonly string fileNameNew;
private readonly string fileNameFolder;
private readonly AssetOptions options = new AssetOptions(); private readonly AssetOptions options = new AssetOptions();
private readonly DefaultAssetFileStore sut; private readonly DefaultAssetFileStore sut;
public DefaultAssetFileStoreTests() public DefaultAssetFileStoreTests()
{ {
fileNameOld = $"{assetId}_{assetFileVersion}";
fileNameNew = $"{appId}_{assetId}_{assetFileVersion}";
fileNameFolder = $"{appId}/{assetId}_{assetFileVersion}";
sut = new DefaultAssetFileStore(assetStore, Options.Create(options)); sut = new DefaultAssetFileStore(assetStore, Options.Create(options));
} }
[Fact] public static IEnumerable<object[]> PathCases()
public void Should_get_public_url_from_store() {
yield return new object[] { true, "resize=100", "derived/{appId}/{assetId}_{assetFileVersion}_resize=100" };
yield return new object[] { true, string.Empty, "{appId}/{assetId}_{assetFileVersion}" };
yield return new object[] { false, "resize=100", "{appId}_{assetId}_{assetFileVersion}_resize=100" };
yield return new object[] { false, string.Empty, "{appId}_{assetId}_{assetFileVersion}" };
}
public static IEnumerable<object?[]> PathCasesOld()
{ {
yield return new object?[] { "resize=100", "{assetId}_{assetFileVersion}_resize=100" };
yield return new object?[] { string.Empty, "{assetId}_{assetFileVersion}" };
}
[Theory]
[MemberData(nameof(PathCases))]
public void Should_get_public_url_from_store(bool folderPerApp, string? suffix, string fileName)
{
var fullName = GetFullName(fileName);
options.FolderPerApp = folderPerApp;
var url = "http_//squidex.io/assets"; var url = "http_//squidex.io/assets";
A.CallTo(() => assetStore.GeneratePublicUrl(fileNameNew)) A.CallTo(() => assetStore.GeneratePublicUrl(fullName))
.Returns(url); .Returns(url);
var result = sut.GeneratePublicUrl(appId, assetId, assetFileVersion); var result = sut.GeneratePublicUrl(appId, assetId, assetFileVersion, suffix);
Assert.Equal(url, result); Assert.Equal(url, result);
} }
[Fact] [Theory]
public async Task Should_get_file_size_from_store() [MemberData(nameof(PathCases))]
public async Task Should_get_file_size_from_store(bool folderPerApp, string? suffix, string fileName)
{ {
var fullName = GetFullName(fileName);
options.FolderPerApp = folderPerApp;
var size = 1024L; var size = 1024L;
A.CallTo(() => assetStore.GetSizeAsync(fileNameNew, default)) A.CallTo(() => assetStore.GetSizeAsync(fullName, default))
.Returns(size); .Returns(size);
var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion); var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion, suffix);
Assert.Equal(size, result); Assert.Equal(size, result);
} }
[Fact] [Theory]
public async Task Should_get_file_size_from_store_with_old_file_name_if_new_name_not_found() [MemberData(nameof(PathCasesOld))]
public async Task Should_get_file_size_from_store_with_old_file_name_if_new_name_not_found(string? suffix, string fileName)
{ {
var fullName = GetFullName(fileName);
var size = 1024L; var size = 1024L;
A.CallTo(() => assetStore.GetSizeAsync(fileNameOld, default)) A.CallTo(() => assetStore.GetSizeAsync(A<string>._, default))
.Throws(new AssetNotFoundException(fileNameOld)); .Throws(new AssetNotFoundException(assetId.ToString()));
A.CallTo(() => assetStore.GetSizeAsync(fileNameNew, default)) A.CallTo(() => assetStore.GetSizeAsync(fullName, default))
.Returns(size); .Returns(size);
var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion); var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion, suffix);
Assert.Equal(size, result); Assert.Equal(size, result);
} }
@ -90,66 +111,82 @@ namespace Squidex.Domain.Apps.Entities.Assets
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact] [Theory]
public async Task Should_upload_file_to_store() [MemberData(nameof(PathCases))]
public async Task Should_upload_file_to_store(bool folderPerApp, string? suffix, string fileName)
{ {
options.FolderPerApp = false; var fullName = GetFullName(fileName);
options.FolderPerApp = folderPerApp;
var stream = new MemoryStream(); var stream = new MemoryStream();
await sut.UploadAsync(appId, assetId, assetFileVersion, stream); await sut.UploadAsync(appId, assetId, assetFileVersion, suffix, stream);
A.CallTo(() => assetStore.UploadAsync(fileNameNew, stream, true, CancellationToken.None)) A.CallTo(() => assetStore.UploadAsync(fullName, stream, true, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact] [Theory]
public async Task Should_upload_file_to_store_with_folder() [MemberData(nameof(PathCases))]
public async Task Should_download_file_from_store(bool folderPerApp, string? suffix, string fileName)
{ {
options.FolderPerApp = true; var fullName = GetFullName(fileName);
options.FolderPerApp = folderPerApp;
var stream = new MemoryStream(); var stream = new MemoryStream();
await sut.UploadAsync(appId, assetId, assetFileVersion, stream); await sut.DownloadAsync(appId, assetId, assetFileVersion, suffix, stream);
A.CallTo(() => assetStore.UploadAsync(fileNameFolder, stream, true, CancellationToken.None)) A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact] [Fact]
public async Task Should_download_file_from_store() public async Task Should_download_file_from_store_with_folder_only_if_configured()
{ {
options.FolderPerApp = true;
var stream = new MemoryStream(); var stream = new MemoryStream();
await sut.DownloadAsync(appId, assetId, assetFileVersion, stream); A.CallTo(() => assetStore.DownloadAsync(A<string>._, stream, default, CancellationToken.None))
.Throws(new AssetNotFoundException(assetId.ToString())).Once();
A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None)) await Assert.ThrowsAsync<AssetNotFoundException>(() => sut.DownloadAsync(appId, assetId, assetFileVersion, null, stream));
.MustHaveHappened();
A.CallTo(() => assetStore.DownloadAsync(A<string>._, stream, default, CancellationToken.None))
.MustHaveHappenedOnceExactly();
} }
[Fact] [Theory]
public async Task Should_download_file_from_store_with_old_file_name_if_new_name_not_found() [MemberData(nameof(PathCasesOld))]
public async Task Should_download_file_from_store_with_old_file_name_if_new_name_not_found(string suffix, string fileName)
{ {
var fullName = GetFullName(fileName);
var stream = new MemoryStream(); var stream = new MemoryStream();
A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None)) A.CallTo(() => assetStore.DownloadAsync(A<string>.That.Matches(x => x != fileName), stream, default, CancellationToken.None))
.Throws(new AssetNotFoundException(fileNameNew)); .Throws(new AssetNotFoundException(assetId.ToString())).Once();
await sut.DownloadAsync(appId, assetId, assetFileVersion, stream); await sut.DownloadAsync(appId, assetId, assetFileVersion, suffix, stream);
A.CallTo(() => assetStore.DownloadAsync(fileNameOld, stream, default, CancellationToken.None)) A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, CancellationToken.None))
.MustHaveHappened();
A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact] [Theory]
public async Task Should_copy_file_to_store() [MemberData(nameof(PathCases))]
public async Task Should_copy_file_to_store(bool folderPerApp, string? suffix, string fileName)
{ {
await sut.CopyAsync("Temp", appId, assetId, assetFileVersion); var fullName = GetFullName(fileName);
A.CallTo(() => assetStore.CopyAsync("Temp", fileNameNew, CancellationToken.None)) options.FolderPerApp = folderPerApp;
await sut.CopyAsync("Temp", appId, assetId, assetFileVersion, suffix);
A.CallTo(() => assetStore.CopyAsync("Temp", fullName, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -162,16 +199,29 @@ namespace Squidex.Domain.Apps.Entities.Assets
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact] [Theory]
public async Task Should_delete_file_from_store() [MemberData(nameof(PathCases))]
public async Task Should_delete_file_from_store(bool folderPerApp, string? suffix, string fileName)
{ {
await sut.DeleteAsync(appId, assetId, assetFileVersion); var fullName = GetFullName(fileName);
A.CallTo(() => assetStore.DeleteAsync(fileNameNew)) options.FolderPerApp = folderPerApp;
.MustHaveHappened();
await sut.DeleteAsync(appId, assetId, assetFileVersion, suffix);
A.CallTo(() => assetStore.DeleteAsync(fileNameOld)) A.CallTo(() => assetStore.DeleteAsync(fullName))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => assetStore.DeleteAsync(A<string>._))
.MustHaveHappenedANumberOfTimesMatching(x => x == (folderPerApp ? 1 : 2));
}
private string GetFullName(string fileName)
{
return fileName
.Replace("{appId}", appId.ToString())
.Replace("{assetId}", assetId.ToString())
.Replace("{assetFileVersion}", assetFileVersion.ToString());
} }
} }
} }

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs

@ -192,7 +192,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
A.CallTo(() => assetFileStore.UploadAsync(A<string>._, A<HasherStream>._, CancellationToken.None)) A.CallTo(() => assetFileStore.UploadAsync(A<string>._, A<HasherStream>._, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => assetFileStore.CopyAsync(A<string>._, AppId, assetId, fileVersion, CancellationToken.None)) A.CallTo(() => assetFileStore.CopyAsync(A<string>._, AppId, assetId, fileVersion, null, CancellationToken.None))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => assetFileStore.DeleteAsync(A<string>._)) A.CallTo(() => assetFileStore.DeleteAsync(A<string>._))
.MustHaveHappened(); .MustHaveHappened();

18
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs

@ -38,12 +38,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
SetupEvent(@event); SetupEvent(@event);
A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, default)) A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, null, default))
.Throws(new AssetNotFoundException("file")); .Throws(new AssetNotFoundException("file"));
await sut.RepairAsync(); await sut.RepairAsync();
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, A<Stream>._, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, null, A<Stream>._, true, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -54,12 +54,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
SetupEvent(@event); SetupEvent(@event);
A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, default)) A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, null, default))
.Returns(100); .Returns(100);
await sut.RepairAsync(); await sut.RepairAsync();
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, A<Stream>._, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, null, A<Stream>._, true, default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -70,12 +70,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
SetupEvent(@event); SetupEvent(@event);
A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, default)) A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, null, default))
.Throws(new AssetNotFoundException("file")); .Throws(new AssetNotFoundException("file"));
await sut.RepairAsync(); await sut.RepairAsync();
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, A<Stream>._, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, null, A<Stream>._, true, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -86,12 +86,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
SetupEvent(@event); SetupEvent(@event);
A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, default)) A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, null, default))
.Returns(100); .Returns(100);
await sut.RepairAsync(); await sut.RepairAsync();
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, A<Stream>._, default)) A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, null, A<Stream>._, true, default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.RepairAsync(); await sut.RepairAsync();
A.CallTo(() => assetFileStore.GetFileSizeAsync(A<DomainId>._, A<DomainId>._, A<long>._, default)) A.CallTo(() => assetFileStore.GetFileSizeAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }

Loading…
Cancel
Save