Browse Source

Another migration fix.

pull/596/head
Sebastian 5 years ago
parent
commit
83d823a29a
  1. 9
      backend/src/Migrations/Migrations/MongoDb/AddAppIdToEventStream.cs
  2. 24
      backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs
  3. 2
      backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs
  4. 71
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs
  5. 24
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs

9
backend/src/Migrations/Migrations/MongoDb/AddAppIdToEventStream.cs

@ -67,6 +67,8 @@ namespace Migrations.Migrations.MongoDb
var domainType = eventStream.Substring(0, indexOfType);
var domainId = eventStream.Substring(indexOfId);
if (!eventStream.StartsWith("app-", StringComparison.OrdinalIgnoreCase))
{
var newDomainId = DomainId.Combine(DomainId.Create(appId), DomainId.Create(domainId)).ToString();
var newStreamName = $"{domainType}-{newDomainId}";
@ -77,6 +79,13 @@ namespace Migrations.Migrations.MongoDb
var metadata = @event["Metadata"].AsBsonDocument;
metadata["AggregateId"] = newDomainId;
}
}
foreach (var @event in document["Events"].AsBsonArray)
{
var metadata = @event["Metadata"].AsBsonDocument;
metadata.Remove("AppId");
}
}

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

@ -6,12 +6,14 @@
// ==========================================================================
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Assets.State;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
@ -122,21 +124,35 @@ namespace Squidex.Domain.Apps.Entities.Assets
await context.Writer.WriteJsonAsync(TagsFile, tags);
}
private Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer)
private async Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer)
{
return writer.WriteBlobAsync(GetName(assetId, fileVersion), stream =>
try
{
await writer.WriteBlobAsync(GetName(assetId, fileVersion), stream =>
{
return assetFileStore.DownloadAsync(appId, assetId, fileVersion, stream);
});
}
catch (AssetNotFoundException)
{
return;
}
}
private Task ReadAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupReader reader)
private async Task ReadAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupReader reader)
{
return reader.ReadBlobAsync(GetName(assetId, fileVersion), stream =>
try
{
await reader.ReadBlobAsync(GetName(assetId, fileVersion), stream =>
{
return assetFileStore.UploadAsync(appId, assetId, fileVersion, stream);
});
}
catch (FileNotFoundException)
{
return;
}
}
private static string GetName(DomainId assetId, long fileVersion)
{

2
backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs

@ -83,7 +83,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
var attachmentEntry = archive.GetEntry(ArchiveHelper.GetAttachmentPath(name));
if (attachmentEntry == null)
if (attachmentEntry == null || attachmentEntry.Length == 0)
{
throw new FileNotFoundException("Cannot find attachment.", name);
}

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

@ -16,6 +16,7 @@ using Squidex.Domain.Apps.Entities.Assets.State;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Xunit;
@ -81,7 +82,15 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
var @event = new AssetCreated { AssetId = DomainId.NewGuid() };
await TestBackupEventAsync(@event, 0);
await TestBackupAsync(@event, 0);
}
[Fact]
public async Task Should_backup_created_asset_with_missing_file()
{
var @event = new AssetCreated { AssetId = DomainId.NewGuid() };
await TestBackupFailedAsync(@event, 0);
}
[Fact]
@ -89,10 +98,18 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
var @event = new AssetUpdated { AssetId = DomainId.NewGuid(), FileVersion = 3 };
await TestBackupEventAsync(@event, @event.FileVersion);
await TestBackupAsync(@event, @event.FileVersion);
}
private async Task TestBackupEventAsync(AssetEvent @event, long version)
[Fact]
public async Task Should_backup_updated_asset_with_missing_file()
{
var @event = new AssetUpdated { AssetId = DomainId.NewGuid(), FileVersion = 3 };
await TestBackupFailedAsync(@event, @event.FileVersion);
}
private async Task TestBackupAsync(AssetEvent @event, long version)
{
var assetStream = new MemoryStream();
var assetId = @event.AssetId;
@ -108,6 +125,22 @@ namespace Squidex.Domain.Apps.Entities.Assets
.MustHaveHappened();
}
private async Task TestBackupFailedAsync(AssetEvent @event, long version)
{
var assetStream = new MemoryStream();
var assetId = @event.AssetId;
var context = CreateBackupContext();
A.CallTo(() => context.Writer.WriteBlobAsync($"{assetId}_{version}.asset", A<Func<Stream, Task>>._))
.Invokes((string _, Func<Stream, Task> handler) => handler(assetStream));
A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, assetStream, default, default))
.Throws(new AssetNotFoundException(assetId.ToString()));
await sut.BackupEventAsync(AppEvent(@event), context);
}
[Fact]
public async Task Should_restore_created_asset()
{
@ -116,6 +149,14 @@ namespace Squidex.Domain.Apps.Entities.Assets
await TestRestoreAsync(@event, 0);
}
[Fact]
public async Task Should_restore_created_asset_with_missing_file()
{
var @event = new AssetCreated { AssetId = DomainId.NewGuid() };
await TestRestoreFailedAsync(@event, 0);
}
[Fact]
public async Task Should_restore_updated_asset()
{
@ -124,6 +165,14 @@ namespace Squidex.Domain.Apps.Entities.Assets
await TestRestoreAsync(@event, @event.FileVersion);
}
[Fact]
public async Task Should_restore_updated_asset_with_missing_file()
{
var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 };
await TestRestoreFailedAsync(@event, @event.FileVersion);
}
private async Task TestRestoreAsync(AssetEvent @event, long version)
{
var assetStream = new MemoryStream();
@ -140,6 +189,22 @@ namespace Squidex.Domain.Apps.Entities.Assets
.MustHaveHappened();
}
private async Task TestRestoreFailedAsync(AssetEvent @event, long version)
{
var assetStream = new MemoryStream();
var assetId = @event.AssetId;
var context = CreateRestoreContext();
A.CallTo(() => context.Reader.ReadBlobAsync($"{assetId}_{version}.asset", A<Func<Stream, Task>>._))
.Throws(new FileNotFoundException());
await sut.RestoreEventAsync(AppEvent(@event), context);
A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, assetStream, default))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_restore_states_for_all_assets()
{

24
backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs

@ -40,6 +40,30 @@ namespace Squidex.Domain.Apps.Entities.Backup
formatter = new DefaultEventDataFormatter(typeNameRegistry, serializer);
}
[Fact]
public async Task Should_not_write_blob_if_handler_failed()
{
var file = "File.json";
await TestReaderWriterAsync(BackupVersion.V1, async writer =>
{
try
{
await writer.WriteBlobAsync(file, _ =>
{
throw new InvalidOperationException();
});
}
catch
{
return;
}
}, async reader =>
{
await Assert.ThrowsAsync<FileNotFoundException>(() => ReadGuidAsync(reader, file));
});
}
[Fact]
public async Task Should_read_and_write_json_async()
{

Loading…
Cancel
Save