From 8336da4f270879b82e9fec9f2d7071c099b18c77 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Mon, 7 Aug 2023 14:00:44 +0300 Subject: [PATCH] Fixed duplicate event handling on start in ProcessManager (#261) * Fixed duplicate event handling on start in ProcessManager * Fixed test --- .../Builder/AbstractDefinition.cs | 2 +- .../IDefinition.cs | 2 +- .../NBB.ProcessManager.Runtime/Instance.cs | 3 +- .../NBB.ProcessManager.Tests/Events/Events.cs | 4 +- .../ProcessManagerInstanceUnitTests.cs | 11 ++- .../RegistrationTests.cs | 96 +++++++++++++++++++ 6 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 test/UnitTests/Orchestration/NBB.ProcessManager.Tests/RegistrationTests.cs diff --git a/src/Orchestration/NBB.ProcessManager.Definition/Builder/AbstractDefinition.cs b/src/Orchestration/NBB.ProcessManager.Definition/Builder/AbstractDefinition.cs index 0ce03c3b..01bcf3de 100644 --- a/src/Orchestration/NBB.ProcessManager.Definition/Builder/AbstractDefinition.cs +++ b/src/Orchestration/NBB.ProcessManager.Definition/Builder/AbstractDefinition.cs @@ -49,7 +49,7 @@ Func IDefinition.GetCorrelationFilter() return null; } - IEnumerable IDefinition.GetEventTypes() => _eventActivities.Select(x => new EventType(x.EventType, x.StartsProcess)).Distinct(); + IEnumerable IDefinition.GetEventTypes() => _eventActivities.Select(x => new EventType(x.EventType, _eventActivities.Count(e => e.GetType() == x.GetType() && e.StartsProcess) == 1)).Distinct(); EffectFunc IDefinition.GetEffectFunc() { diff --git a/src/Orchestration/NBB.ProcessManager.Definition/IDefinition.cs b/src/Orchestration/NBB.ProcessManager.Definition/IDefinition.cs index dfeb4e99..0ef7f3ed 100644 --- a/src/Orchestration/NBB.ProcessManager.Definition/IDefinition.cs +++ b/src/Orchestration/NBB.ProcessManager.Definition/IDefinition.cs @@ -35,5 +35,5 @@ public sealed class ObsoleteProcessAttribute : Attribute { } - public record struct EventType(Type Type, bool StartsProcess); + public record struct EventType(Type Type, bool OnlyStartsProcess); } diff --git a/src/Orchestration/NBB.ProcessManager.Runtime/Instance.cs b/src/Orchestration/NBB.ProcessManager.Runtime/Instance.cs index d622ccc5..006592c5 100644 --- a/src/Orchestration/NBB.ProcessManager.Runtime/Instance.cs +++ b/src/Orchestration/NBB.ProcessManager.Runtime/Instance.cs @@ -64,7 +64,8 @@ public void ProcessEvent(TEvent @event) { if (_definition.IsObsolete()) { - throw new Exception($"Definition {_definition.GetType().GetLongPrettyName()} is obsolete and new process instances cannot be started."); + _logger.LogWarning($"Definition {_definition.GetType().GetLongPrettyName()} is obsolete and new process instances cannot be started."); + return; } StartProcess(@event); diff --git a/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/Events/Events.cs b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/Events/Events.cs index f34868df..7c475c39 100644 --- a/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/Events/Events.cs +++ b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/Events/Events.cs @@ -16,5 +16,5 @@ public record OrderPaymentExpired (Guid OrderId, int DocumentId, int SiteId) : I public record OrderPaymentReceived(Guid OrderId, int DocumentId, int SiteId) : INotification; - public record OrderShipped(Guid OrderId, DateTime ShippingDate); -} \ No newline at end of file + public record OrderShipped(Guid OrderId, DateTime ShippingDate) : INotification; +} diff --git a/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/ProcessManagerInstanceUnitTests.cs b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/ProcessManagerInstanceUnitTests.cs index 7399a8f6..f19d7835 100644 --- a/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/ProcessManagerInstanceUnitTests.cs +++ b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/ProcessManagerInstanceUnitTests.cs @@ -294,15 +294,20 @@ public OrderProcessManager7() } [Fact] - public void Should_throw_when_starting_obsolete_processes() + public void Should_not_start_when_obsolete_processes() { var @event = new OrderCreated(Guid.NewGuid(), 100, 0, 0); var definition = new ObsoleteProcessManager(); var logger = Mock.Of>>(); var instance = new Instance(definition, logger); - Action act = () => instance.ProcessEvent(@event); - act.Should().Throw(); + instance.ProcessEvent(@event); + + instance.State.Should().Be(InstanceStates.NotStarted); + + Mock.Get(logger).Verify(x => x.Log(LogLevel.Warning, It.IsAny(), + It.Is((v, _) => v.ToString().Contains("obsolete")), + It.IsAny(), It.IsAny>())); } [Fact] diff --git a/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/RegistrationTests.cs b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/RegistrationTests.cs new file mode 100644 index 00000000..ffdf420c --- /dev/null +++ b/test/UnitTests/Orchestration/NBB.ProcessManager.Tests/RegistrationTests.cs @@ -0,0 +1,96 @@ +// Copyright (c) TotalSoft. +// This source code is licensed under the MIT license. + +using FluentAssertions; +using NBB.ProcessManager.Definition.Builder; +using NBB.ProcessManager.Runtime; +using NBB.ProcessManager.Tests.Commands; +using NBB.ProcessManager.Tests.Events; +using System; +using System.Threading; +using System.Threading.Tasks; +using NBB.Messaging.Effects; +using NBB.ProcessManager.Definition; +using Xunit; +using Moq; +using Microsoft.Extensions.Logging; +using NBB.ProcessManager.Runtime.Events; +using Microsoft.Extensions.DependencyInjection; +using NBB.Core.Effects; +using NBB.EventStore.InMemory; +using NBB.EventStore.Internal; +using NBB.ProcessManager.Runtime.Persistence; +using static NBB.ProcessManager.Tests.RegistrationTests.RegistrationProcessManager; +using System.Collections.Generic; +using System.Linq; +using MediatR; +using FluentAssertions.Common; + + +namespace NBB.ProcessManager.Tests +{ + public class RegistrationTests + { + + [Fact] + public void HandlersShouldBeRegisteredOnce() + { + var sp = BuildServiceProvider(); + var orderCreatedHandlers = sp.GetServices>().OfType>(); + var orderPayemntCreatedHandlers = sp.GetServices>().OfType>(); + + orderCreatedHandlers.Count().Should().Be(1); + orderPayemntCreatedHandlers.Count().Should().Be(1); + } + + public IServiceProvider BuildServiceProvider() + { + var services = new ServiceCollection(); + services.AddProcessManager(typeof(RegistrationProcessManager).Assembly); + services.AddEventStore(es => + { + es.UseNewtownsoftJson(); + es.UseInMemoryEventRepository(); + }); + services.AddLogging(builder => builder.AddConsole()); + + return services.BuildServiceProvider(); + } + + public class RegistrationProcessManager : AbstractDefinition + { + public record struct RegistrationProcessManagerData + { + public Guid OrderId { get; init; } + public int CreateCount { get; init; } + public int PaidCount { get; set;} + + } + public RegistrationProcessManager() + { + Event(configurator => configurator.CorrelateById(orderCreated => orderCreated.OrderId)); + Event(configurator => + configurator.CorrelateById(paymentReceived => paymentReceived.OrderId)); + + StartWith(); + + When() + .SetState((orderCreated, state) => + state.Data with + { + OrderId = orderCreated.OrderId, + CreateCount = state.Data.CreateCount + 1 + }) + .PublishEvent((orderCreated, state) => new OrderCompleted(orderCreated.OrderId, 100, 0, 0)); + + When() + .SetState((@event, state) => state.Data with { PaidCount = state.Data.PaidCount + 1 }) + .Then((ev, state) => + { + var effect = MessageBus.Publish(new DoPayment()); + return effect; + }); + } + } + } +}