// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using Squidex.Assets; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; public class RepairFilesTests : GivenContext { private readonly IEventStore eventStore = A.Fake(); private readonly IEventFormatter eventFormatter = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly RebuildFiles sut; public RepairFilesTests() { sut = new RebuildFiles(assetFileStore, eventFormatter, eventStore); } [Fact] public async Task Should_repair_created_asset_if_not_found() { var @event = new AssetCreated { AppId = AppId, AssetId = DomainId.NewGuid() }; SetupEvent(@event); A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 0, null, CancellationToken)) .Throws(new AssetNotFoundException("file")); await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 0, null, A._, true, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_not_repair_created_asset_if_found() { var @event = new AssetCreated { AppId = AppId, AssetId = DomainId.NewGuid() }; SetupEvent(@event); A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 0, null, CancellationToken)) .Returns(100); await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 0, null, A._, true, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_repair_updated_asset_if_not_found() { var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; SetupEvent(@event); A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 3, null, CancellationToken)) .Throws(new AssetNotFoundException("file")); await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 3, null, A._, true, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_not_repair_updated_asset_if_found() { var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; SetupEvent(@event); A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 3, null, CancellationToken)) .Returns(100); await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 3, null, A._, true, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_ignore_old_events() { SetupEvent(null); await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.GetFileSizeAsync(A._, A._, A._, null, A._)) .MustNotHaveHappened(); } private void SetupEvent(IEvent? @event) { var storedEvent = new StoredEvent("stream", "0", -1, new EventData("type", [], "payload")); var storedEvents = new List { storedEvent }; if (@event != null) { A.CallTo(() => eventFormatter.ParseIfKnown(storedEvent)) .Returns(Envelope.Create(@event)); } else { A.CallTo(() => eventFormatter.ParseIfKnown(storedEvent)) .Returns(null); } var streamFilter = StreamFilter.Prefix("asset-"); A.CallTo(() => eventStore.QueryAllAsync(streamFilter, null, int.MaxValue, CancellationToken)) .Returns(storedEvents.ToAsyncEnumerable()); } }