From a29c97adb9b85706066ec0c0a7d45271b78e36e4 Mon Sep 17 00:00:00 2001 From: Mauro Servienti Date: Tue, 2 Jun 2020 15:07:04 +0200 Subject: [PATCH 1/2] SagaInstance creation infrastructure --- .../EndpointTemplate.cs | 13 +++++-- .../IntegrationScenarioContext.cs | 11 ++++++ .../MessageSessionExtensions.cs | 20 +++++++++++ .../Messages/CreateSagaInstance.cs | 9 +++++ .../Handlers/CreateSagaInstanceHandler.cs | 35 +++++++++++++++++++ .../MarkSagaInstanceAsCreatedHandler.cs | 24 +++++++++++++ .../Messages/MarkSagaInstanceAsCreated.cs | 10 ++++++ 7 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/NServiceBus.IntegrationTesting/MessageSessionExtensions.cs create mode 100644 src/NServiceBus.IntegrationTesting/Messages/CreateSagaInstance.cs create mode 100644 src/NServiceBus.IntegrationTesting/Messages/Handlers/CreateSagaInstanceHandler.cs create mode 100644 src/NServiceBus.IntegrationTesting/Messages/Handlers/MarkSagaInstanceAsCreatedHandler.cs create mode 100644 src/NServiceBus.IntegrationTesting/Messages/MarkSagaInstanceAsCreated.cs diff --git a/src/NServiceBus.IntegrationTesting/EndpointTemplate.cs b/src/NServiceBus.IntegrationTesting/EndpointTemplate.cs index ebc36e88..523c9e76 100644 --- a/src/NServiceBus.IntegrationTesting/EndpointTemplate.cs +++ b/src/NServiceBus.IntegrationTesting/EndpointTemplate.cs @@ -1,7 +1,9 @@ using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Configuration.AdvancedExtensibility; +using NServiceBus.IntegrationTesting.Messages.Handlers; using System; using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting.Customization; namespace NServiceBus.IntegrationTesting { @@ -13,11 +15,16 @@ public async Task GetConfiguration(RunDescriptor runDescr var settings = configuration.GetSettings(); endpointCustomizationConfiguration.EndpointName = settings.EndpointName(); + configurationBuilderCustomization(configuration); - configuration.RegisterRequiredPipelineBehaviors(endpointCustomizationConfiguration.EndpointName, (IntegrationScenarioContext)runDescriptor.ScenarioContext); - configuration.RegisterScenarioContext(runDescriptor.ScenarioContext); + configuration.TypesToIncludeInScan(new[] + { + typeof(CreateSagaInstanceHandler), + typeof(MarkSagaInstanceAsCreatedHandler) + }); - configurationBuilderCustomization(configuration); + configuration.RegisterScenarioContext(runDescriptor.ScenarioContext); + configuration.RegisterRequiredPipelineBehaviors(endpointCustomizationConfiguration.EndpointName, (IntegrationScenarioContext)runDescriptor.ScenarioContext); return configuration; } diff --git a/src/NServiceBus.IntegrationTesting/IntegrationScenarioContext.cs b/src/NServiceBus.IntegrationTesting/IntegrationScenarioContext.cs index e6c74e12..e3c4762d 100644 --- a/src/NServiceBus.IntegrationTesting/IntegrationScenarioContext.cs +++ b/src/NServiceBus.IntegrationTesting/IntegrationScenarioContext.cs @@ -14,6 +14,7 @@ public class IntegrationScenarioContext : ScenarioContext readonly ConcurrentBag invokedSagas = new ConcurrentBag(); readonly ConcurrentBag outgoingMessageOperations = new ConcurrentBag(); readonly Dictionary> timeoutRescheduleRules = new Dictionary>(); + readonly ConcurrentDictionary createdSagaInstances = new ConcurrentDictionary(); public IEnumerable InvokedHandlers { get { return invokedHandlers; } } public IEnumerable InvokedSagas { get { return invokedSagas; } } @@ -53,6 +54,16 @@ internal SagaInvocation CaptureInvokedSaga(SagaInvocation invocation) return invocation; } + internal void RegisterSagaInstanceAsCreated(Guid sagaId, Type sagaDataType) + { + createdSagaInstances.AddOrUpdate(sagaId, sagaDataType, (id, type) => type); + } + + public bool IsSagaInstanceAvailable(Guid sagaId) + { + return createdSagaInstances.ContainsKey(sagaId); + } + public bool HandlerWasInvoked() { return InvokedHandlers.Any(invocation => invocation.HandlerType == typeof(THandler)); diff --git a/src/NServiceBus.IntegrationTesting/MessageSessionExtensions.cs b/src/NServiceBus.IntegrationTesting/MessageSessionExtensions.cs new file mode 100644 index 00000000..ddd616f5 --- /dev/null +++ b/src/NServiceBus.IntegrationTesting/MessageSessionExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; + +namespace NServiceBus.IntegrationTesting +{ + public static class MessageSessionExtensions + { + public static Task CreateSagaInstance(this IMessageSession messageSession, string sagaOwnerEndpoint, Guid sagaId, TSagaData sagaData, string originator = null, string originatingMessageId = null) where TSagaData : IContainSagaData + { + sagaData.Id = sagaId; + sagaData.Originator = originator; + sagaData.OriginalMessageId = originatingMessageId; + + return messageSession.Send(sagaOwnerEndpoint, new Messages.CreateSagaInstance() + { + SagaData = sagaData + }); + } + } +} diff --git a/src/NServiceBus.IntegrationTesting/Messages/CreateSagaInstance.cs b/src/NServiceBus.IntegrationTesting/Messages/CreateSagaInstance.cs new file mode 100644 index 00000000..d94e854b --- /dev/null +++ b/src/NServiceBus.IntegrationTesting/Messages/CreateSagaInstance.cs @@ -0,0 +1,9 @@ +namespace NServiceBus.IntegrationTesting.Messages +{ + class CreateSagaInstance + { + public string CorrelationPropertyName { get; set; } + public object CorrelationPropertyValue { get; set; } + public IContainSagaData SagaData { get; set; } + } +} diff --git a/src/NServiceBus.IntegrationTesting/Messages/Handlers/CreateSagaInstanceHandler.cs b/src/NServiceBus.IntegrationTesting/Messages/Handlers/CreateSagaInstanceHandler.cs new file mode 100644 index 00000000..a1b044bf --- /dev/null +++ b/src/NServiceBus.IntegrationTesting/Messages/Handlers/CreateSagaInstanceHandler.cs @@ -0,0 +1,35 @@ +using NServiceBus.AcceptanceTesting; +using NServiceBus.Sagas; +using System.Threading.Tasks; + +namespace NServiceBus.IntegrationTesting.Messages.Handlers +{ + class CreateSagaInstanceHandler : IHandleMessages + { + readonly ISagaPersister sagaPersister; + + public CreateSagaInstanceHandler(ISagaPersister sagaPersister) + { + this.sagaPersister = sagaPersister; + } + + public async Task Handle(CreateSagaInstance message, IMessageHandlerContext context) + { + var correlationProperty = new SagaCorrelationProperty( + message.CorrelationPropertyName, + message.CorrelationPropertyValue); + + await sagaPersister.Save(message.SagaData, + correlationProperty, + context.SynchronizedStorageSession, + new Extensibility.ContextBag()) + .ConfigureAwait(false); + + await context.SendLocal(new MarkSagaInstanceAsCreated() + { + SagaId = message.SagaData.Id, + SagaDataType = message.SagaData.GetType() + }).ConfigureAwait(false); + } + } +} diff --git a/src/NServiceBus.IntegrationTesting/Messages/Handlers/MarkSagaInstanceAsCreatedHandler.cs b/src/NServiceBus.IntegrationTesting/Messages/Handlers/MarkSagaInstanceAsCreatedHandler.cs new file mode 100644 index 00000000..817196f6 --- /dev/null +++ b/src/NServiceBus.IntegrationTesting/Messages/Handlers/MarkSagaInstanceAsCreatedHandler.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace NServiceBus.IntegrationTesting.Messages.Handlers +{ + class MarkSagaInstanceAsCreatedHandler : IHandleMessages + { + readonly IntegrationScenarioContext integrationScenarioContext; + + public MarkSagaInstanceAsCreatedHandler(IntegrationScenarioContext integrationScenarioContext) + { + this.integrationScenarioContext = integrationScenarioContext; + } + + public Task Handle(MarkSagaInstanceAsCreated message, IMessageHandlerContext context) + { + integrationScenarioContext.RegisterSagaInstanceAsCreated(message.SagaId, message.SagaDataType); + + return Task.CompletedTask; + } + } +} diff --git a/src/NServiceBus.IntegrationTesting/Messages/MarkSagaInstanceAsCreated.cs b/src/NServiceBus.IntegrationTesting/Messages/MarkSagaInstanceAsCreated.cs new file mode 100644 index 00000000..e9251c2b --- /dev/null +++ b/src/NServiceBus.IntegrationTesting/Messages/MarkSagaInstanceAsCreated.cs @@ -0,0 +1,10 @@ +using System; + +namespace NServiceBus.IntegrationTesting.Messages +{ + class MarkSagaInstanceAsCreated + { + public Guid SagaId { get; set; } + public Type SagaDataType { get; set; } + } +} From b899c1d136aec58f532c8233c9faf16ed50b30b4 Mon Sep 17 00:00:00 2001 From: mauroservienti Date: Fri, 23 Oct 2020 10:31:32 +0200 Subject: [PATCH 2/2] Add assertion messages --- src/MySystem.AcceptanceTests/When_requesting_a_timeout.cs | 6 +++--- src/MySystem.AcceptanceTests/When_sending_AMessage.cs | 4 ++-- src/MySystem.AcceptanceTests/When_sending_CompleteASaga.cs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/MySystem.AcceptanceTests/When_requesting_a_timeout.cs b/src/MySystem.AcceptanceTests/When_requesting_a_timeout.cs index cd013f1e..c0671c75 100644 --- a/src/MySystem.AcceptanceTests/When_requesting_a_timeout.cs +++ b/src/MySystem.AcceptanceTests/When_requesting_a_timeout.cs @@ -38,9 +38,9 @@ public async Task It_should_be_rescheduled_and_handled() .Done(ctx => ctx.MessageWasProcessedBySaga() || ctx.HasFailedMessages()) .Run(); - Assert.True(context.MessageWasProcessedBySaga()); - Assert.False(context.HasFailedMessages()); - Assert.False(context.HasHandlingErrors()); + Assert.False(context.HasFailedMessages(), "There are failed messages"); + Assert.False(context.HasHandlingErrors(), "There were handling errors"); + Assert.True(context.MessageWasProcessedBySaga(), "MyTimeout was not processed by ASaga"); } class MyServiceEndpoint : EndpointConfigurationBuilder diff --git a/src/MySystem.AcceptanceTests/When_sending_AMessage.cs b/src/MySystem.AcceptanceTests/When_sending_AMessage.cs index a28bdf8b..00aac3ad 100644 --- a/src/MySystem.AcceptanceTests/When_sending_AMessage.cs +++ b/src/MySystem.AcceptanceTests/When_sending_AMessage.cs @@ -40,11 +40,11 @@ public async Task AReplyMessage_is_received_and_ASaga_is_started() var invokedSaga = context.InvokedSagas.Single(s => s.SagaType == typeof(ASaga)); + Assert.False(context.HasFailedMessages(), "There are failed messages"); + Assert.False(context.HasHandlingErrors(), "There were handling errors"); Assert.True(invokedSaga.IsNew); Assert.AreEqual("MyService", invokedSaga.EndpointName); Assert.True(((ASagaData)invokedSaga.SagaData).AnIdentifier == theExpectedIdentifier); - Assert.False(context.HasFailedMessages()); - Assert.False(context.HasHandlingErrors()); } class MyServiceEndpoint : EndpointConfigurationBuilder diff --git a/src/MySystem.AcceptanceTests/When_sending_CompleteASaga.cs b/src/MySystem.AcceptanceTests/When_sending_CompleteASaga.cs index dc09365d..43f9ed38 100644 --- a/src/MySystem.AcceptanceTests/When_sending_CompleteASaga.cs +++ b/src/MySystem.AcceptanceTests/When_sending_CompleteASaga.cs @@ -38,7 +38,7 @@ public async Task ASaga_is_completed() behavior.When(condition: ctx => { return ctx.SagaWasInvoked() && ctx.InvokedSagas.Any(s=> s.SagaType == typeof(ASaga) && s.IsNew); - }, + }, action: session => { return session.Send("MyService", new CompleteASaga {AnIdentifier = theExpectedIdentifier}); @@ -54,10 +54,10 @@ public async Task ASaga_is_completed() var newSaga = invokedSagas.SingleOrDefault(s => s.IsNew); var completedSaga = invokedSagas.SingleOrDefault(s => s.IsCompleted); + Assert.False(context.HasFailedMessages(), "There are failed messages"); + Assert.False(context.HasHandlingErrors(), "There were handling errors"); Assert.IsNotNull(newSaga); Assert.IsNotNull(completedSaga); - Assert.False(context.HasFailedMessages()); - Assert.False(context.HasHandlingErrors()); } class MyServiceEndpoint : EndpointConfigurationBuilder