// ========================================================================== // AggregateHandlerTests.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group // All rights reserved. // ========================================================================== using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.States; using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.TestHelpers; using Xunit; namespace Squidex.Infrastructure.Commands { public class AggregateHandlerTests { private readonly IServiceProvider serviceProvider = A.Fake(); private readonly IStore store = A.Fake>(); private readonly IStateFactory stateFactory = A.Fake(); private readonly IPersistence persistence = A.Fake>(); private readonly Envelope event1 = new Envelope(new MyEvent()); private readonly Envelope event2 = new Envelope(new MyEvent()); private readonly CommandContext context; private readonly CommandContext invalidContext = new CommandContext(A.Dummy()); private readonly Guid domainObjectId = Guid.NewGuid(); private readonly MyCommand command; private readonly MyDomainObject domainObject = new MyDomainObject(); private readonly AggregateHandler sut; public AggregateHandlerTests() { command = new MyCommand { AggregateId = domainObjectId, ExpectedVersion = EtagVersion.Any }; context = new CommandContext(command); A.CallTo(() => store.WithSnapshotsAndEventSourcing(domainObjectId, A>.Ignored, A, Task>>.Ignored)) .Returns(persistence); A.CallTo(() => stateFactory.CreateAsync(domainObjectId)) .Returns(Task.FromResult(domainObject)); A.CallTo(() => stateFactory.GetSingleAsync(domainObjectId)) .Returns(Task.FromResult(domainObject)); sut = new AggregateHandler(stateFactory, serviceProvider); domainObject.ActivateAsync(domainObjectId, store).Wait(); } [Fact] public Task Create_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.CreateAsync(invalidContext, x => TaskHelper.False)); } [Fact] public Task Create_synced_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.CreateSyncedAsync(invalidContext, x => TaskHelper.False)); } [Fact] public Task Create_with_task_should_should_throw_exception_if_version_is_wrong() { command.ExpectedVersion = 2; return Assert.ThrowsAnyAsync(() => sut.CreateAsync(context, x => TaskHelper.False)); } [Fact] public Task Create_synced_with_task_should_should_throw_exception_if_version_is_wrong() { command.ExpectedVersion = 2; return Assert.ThrowsAnyAsync(() => sut.CreateSyncedAsync(context, x => TaskHelper.False)); } [Fact] public async Task Create_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateAsync(context, async x => { x.RaiseEvent(new MyEvent()); await Task.Yield(); passedDomainObject = x; }); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Create_synced_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateSyncedAsync(context, async x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); await Task.Yield(); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Create_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateAsync(context, x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Create_synced_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateSyncedAsync(context, x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public Task Update_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.UpdateAsync(invalidContext, x => TaskHelper.False)); } [Fact] public Task Update_synced_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.UpdateSyncedAsync(invalidContext, x => TaskHelper.False)); } [Fact] public Task Update_with_task_should_should_throw_exception_if_version_is_wrong() { command.ExpectedVersion = 2; return Assert.ThrowsAnyAsync(() => sut.UpdateAsync(context, x => TaskHelper.False)); } [Fact] public Task Update_synced_with_task_should_should_throw_exception_if_version_is_wrong() { command.ExpectedVersion = 2; return Assert.ThrowsAnyAsync(() => sut.UpdateSyncedAsync(context, x => TaskHelper.False)); } [Fact] public async Task Update_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateAsync(context, async x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); await Task.Yield(); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Update_synced_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateSyncedAsync(context, async x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); await Task.Yield(); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Update_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateAsync(context, x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] public async Task Update_synced_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateSyncedAsync(context, x => { x.RaiseEvent(new MyEvent()); x.RaiseEvent(new MyEvent()); passedDomainObject = x; }); Assert.Equal(2, domainObject.Snapshot.Version); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } } }