// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System; using System.Threading.Tasks; using FakeItEasy; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Squidex.Infrastructure.EventSourcing; using Xunit; #pragma warning disable RECS0002 // Convert anonymous method to method group namespace Squidex.Infrastructure.States { public class PersistenceSnapshotTests { private readonly string key = Guid.NewGuid().ToString(); private readonly IEventDataFormatter eventDataFormatter = A.Fake(); private readonly IEventStore eventStore = A.Fake(); private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); private readonly IPubSub pubSub = new InMemoryPubSub(true); private readonly IServiceProvider services = A.Fake(); private readonly ISnapshotStore snapshotStore = A.Fake>(); private readonly IStreamNameResolver streamNameResolver = A.Fake(); private readonly IStore sut; public PersistenceSnapshotTests() { A.CallTo(() => services.GetService(typeof(ISnapshotStore))) .Returns(snapshotStore); sut = new Store(eventStore, eventDataFormatter, services, streamNameResolver); } [Fact] public async Task Should_read_from_store() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((20, 10)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await persistence.ReadAsync(); Assert.Equal(10, persistence.Version); Assert.Equal(20, persistedState); } [Fact] public async Task Should_return_empty_version_when_version_negative() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((20, -10)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await persistence.ReadAsync(); Assert.Equal(EtagVersion.Empty, persistence.Version); } [Fact] public async Task Should_set_to_empty_when_store_returns_not_found() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((20, EtagVersion.Empty)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await persistence.ReadAsync(); Assert.Equal(-1, persistence.Version); Assert.Equal( 0, persistedState); } [Fact] public async Task Should_throw_exception_if_not_found_and_version_expected() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((123, EtagVersion.Empty)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await Assert.ThrowsAsync(() => persistence.ReadAsync(1)); } [Fact] public async Task Should_throw_exception_if_other_version_found() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((123, 2)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await Assert.ThrowsAsync(() => persistence.ReadAsync(1)); } [Fact] public async Task Should_write_to_store_with_previous_version() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((20, 10)); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await persistence.ReadAsync(); Assert.Equal(10, persistence.Version); Assert.Equal(20, persistedState); await persistence.WriteSnapshotAsync(100); A.CallTo(() => snapshotStore.WriteAsync(key, 100, 10, 11)) .MustHaveHappened(); } [Fact] public async Task Should_wrap_exception_when_writing_to_store_with_previous_version() { A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((20, 10)); A.CallTo(() => snapshotStore.WriteAsync(key, 100, 10, 11)) .Throws(new InconsistentStateException(1, 1, new InvalidOperationException())); var persistedState = 0; var persistence = sut.WithSnapshots(key, x => persistedState = x); await persistence.ReadAsync(); await Assert.ThrowsAsync(() => persistence.WriteSnapshotAsync(100)); } } }