private async Task TestExecutionException( Operation expected, MessagingContext context, Func <IAgentExceptionHandler, Func <Exception, MessagingContext, Task <MessagingContext> > > getExercise) { // Arrange var inMessage = new InMessage(ebmsMessageId: _expectedId); inMessage.SetStatus(InStatus.Received); GetDataStoreContext.InsertInMessage(inMessage); IAgentExceptionHandler sut = CreateInboundExceptionHandler(); var exercise = getExercise(sut); // Act await exercise(new Exception(), context); // Assert GetDataStoreContext.AssertInMessage(_expectedId, m => Assert.Equal(InStatus.Exception, m.Status.ToEnum <InStatus>())); GetDataStoreContext.AssertInException( _expectedId, ex => { Assert.Equal(expected, ex.Operation); Assert.Null(ex.MessageLocation); }); }
public void Set_Retry_Info_When_ReceivingPMode_Is_Configured_For_Retry( bool enabled, PositiveInt count, TimeSpan interval) { // Arrange ClearInExceptions(); IAgentExceptionHandler sut = CreateInboundExceptionHandler(); var pmode = new ReceivingProcessingMode(); pmode.ExceptionHandling.Reliability = new RetryReliability { IsEnabled = enabled, RetryCount = count.Get, RetryInterval = interval.ToString("G") }; var entity = new InMessage($"entity-{Guid.NewGuid()}"); GetDataStoreContext.InsertInMessage(entity); // Act sut.HandleExecutionException( new Exception(), new MessagingContext( new ReceivedEntityMessage(entity), MessagingContextMode.Deliver) { ReceivingPMode = pmode }) .GetAwaiter() .GetResult(); // Assert GetDataStoreContext.AssertInException(ex => { Assert.Null(ex.MessageLocation); GetDataStoreContext.AssertRetryRelatedInException( ex.Id, rr => { Assert.True( enabled == (0 == rr?.CurrentRetryCount), "CurrentRetryCount != 0 when RetryReliability is enabled"); Assert.True( enabled == (count.Get == rr?.MaxRetryCount), enabled ? $"Max retry count failed on enabled: {count.Get} != {rr?.MaxRetryCount}" : $"Max retry count should be 0 on disabled but is {rr?.MaxRetryCount}"); Assert.True( enabled == (interval == rr?.RetryInterval), enabled ? $"Retry interval failed on enabled: {interval:G} != {rr?.RetryInterval}" : $"Retry interval should be 0:00:00 on disabled but is {rr?.RetryInterval}"); }); }); }
/// <summary> /// Initializes a new instance of the <see cref="SafeExceptionHandler" /> class. /// </summary> /// <param name="handler">The handler.</param> public SafeExceptionHandler(IAgentExceptionHandler handler) { if (handler == null) { throw new ArgumentNullException(nameof(handler)); } _innerHandler = handler; }
private static Agent AgentWithSaboteurTransformer(IAgentExceptionHandler spyHandler) { return(new Agent( new AgentConfig(name: "Agent with Saboteur Transformer"), new SpyReceiver(), Transformer <DummyTransformer>(), spyHandler, new StepConfiguration())); }
/// <summary> /// Initializes a new instance of the <see cref="Agent"/> class. /// </summary> /// <param name="config">The config to add metadata to the agent.</param> /// <param name="receiver">The receiver on which the agent should listen for messages.</param> /// <param name="transformerConfig">The config to create <see cref="ITransformer"/> instances.</param> /// <param name="exceptionHandler">The handler to handle failures during the agent execution.</param> /// <param name="stepConfiguration">The config to create <see cref="IStep"/> normal & error pipelines.</param> internal Agent( AgentConfig config, IReceiver receiver, Transformer transformerConfig, IAgentExceptionHandler exceptionHandler, StepConfiguration stepConfiguration) : this(config, receiver, transformerConfig, exceptionHandler, stepConfiguration, NoopJournalLogger.Instance) { }
private static Agent AgentWithUnhappySaboteurSteps(IAgentExceptionHandler spyHandler) { return(new Agent( new AgentConfig(name: "Agent with Saboteur Steps in Error Pipeline"), new SpyReceiver(), Transformer <StubSubmitTransformer>(), spyHandler, new StepConfiguration { NormalPipeline = Step <UnsuccessfulStep>(), ErrorPipeline = Step <SaboteurStep>() })); }
/// <summary> /// Exercises the transform exception. /// </summary> /// <param name="handler">The handler.</param> /// <param name="createContext">The create context.</param> /// <param name="contents">The contents.</param> /// <param name="exception">The exception.</param> /// <returns></returns> internal static async Task <MessagingContext> ExerciseTransformException( this IAgentExceptionHandler handler, Func <DatastoreContext> createContext, string contents, Exception exception) { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) { stream.Position = 0; var receivedMessage = new ReceivedMessage(stream); return(await handler.HandleTransformationException(exception, receivedMessage)); } }
public async Task InsertInException_IfTransformException() { // Arrange string expectedBody = Guid.NewGuid().ToString(), expectedMessage = Guid.NewGuid().ToString(); IAgentExceptionHandler sut = CreateInboundExceptionHandler(); // Act await sut.ExerciseTransformException(GetDataStoreContext, expectedBody, new Exception(expectedMessage)); // Assert GetDataStoreContext.AssertInException( ex => { Assert.True(ex.Exception.IndexOf(expectedMessage, StringComparison.CurrentCultureIgnoreCase) > -1); }); }
/// <summary> /// Initializes a new instance of the <see cref="Agent"/> class. /// </summary> /// <param name="config">The config to add metadata to the agent.</param> /// <param name="receiver">The receiver on which the agent should listen for messages.</param> /// <param name="transformerConfig">The config to create <see cref="ITransformer"/> instances.</param> /// <param name="exceptionHandler">The handler to handle failures during the agent execution.</param> /// <param name="stepConfiguration">The config to create <see cref="IStep"/> normal & error pipelines.</param> /// <param name="journalLogger">The logging implementation to write journal log entries for handled messages.</param> internal Agent( AgentConfig config, IReceiver receiver, Transformer transformerConfig, IAgentExceptionHandler exceptionHandler, StepConfiguration stepConfiguration, IJournalLogger journalLogger) { if (config == null) { throw new ArgumentNullException(nameof(config)); } if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } if (transformerConfig == null) { throw new ArgumentNullException(nameof(transformerConfig)); } if (exceptionHandler == null) { throw new ArgumentNullException(nameof(exceptionHandler)); } if (stepConfiguration == null) { throw new ArgumentNullException(nameof(stepConfiguration)); } _receiver = receiver; _transformerConfig = transformerConfig; _exceptionHandler = exceptionHandler; _steps = new StepExecutioner(stepConfiguration, exceptionHandler); _journalLogger = journalLogger ?? NoopJournalLogger.Instance; AgentConfig = config; }
/// <summary> /// Initializes a new instance of the <see cref="Agent"/> class. /// </summary> /// <param name="config">The config to add meta data information to the agent.</param> /// <param name="receiver">The receiver on which the agent should listen for messages.</param> /// <param name="transformerConfig">The config to create <see cref="ITransformer"/> instances.</param> /// <param name="exceptionHandler">The handler to handle failures during the agent execution.</param> /// <param name="pipelineConfig">The config to create <see cref="IStep"/> normal & error pipelines.</param> /// <remarks>This should only be used inside a 'Minder' scenario!</remarks> internal Agent( AgentConfig config, IReceiver receiver, Transformer transformerConfig, IAgentExceptionHandler exceptionHandler, (ConditionalStepConfig happyPath, ConditionalStepConfig unhappyPath) pipelineConfig)