public void when_executed_with_few_handlers_it_should_execute_them_in_parallel()
        {
            // TODO: On AppVeyor this test is blinking. I thing because of shared resources. This test shouldn't use time.
            var container = new Container();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
            container.AddLogging(_testOutput);
            var strategy = new ParallelHandlersExecutionStrategy(container.GetInstance <ILogger <ParallelHandlersExecutionStrategy> >());
            var handlers = VentureContextTools.CreateHandlerDescriptors(
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100)),
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100)),
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100)),
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100)),
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100)),
                new DelayedMessageHandler(TimeSpan.FromMilliseconds(value: 100))).ToArray();
            var message = new Message02();
            var context = VentureContextTools.CreateFilledVentureContext(message);

            Func <Task> sut = () => strategy.ExecuteHandlers(
                handlers,
                message,
                context);
            var singleHandlerExecutionTime = TimeSpan.FromMilliseconds(value: 100);

            sut.ExecutionTime().Should()
            .BeCloseTo(
                singleHandlerExecutionTime,
                TimeSpan.FromMilliseconds(value: 50),
                "should run simultaneously");
        }
        public void when_executed_with_failing_handler_it_should_throw()
        {
            var handlers = VentureContextTools.CreateHandlerDescriptors(
                new MessageHandler(),
                new ThrowingHandler(),
                new ThrowingHandler()).ToArray();
            var message  = new Message02();
            var context  = VentureContextTools.CreateFilledVentureContext(message);
            var strategy = new ParallelHandlersExecutionStrategy(NullLogger <ParallelHandlersExecutionStrategy> .Instance);

            Func <Task> sut = () => strategy.ExecuteHandlers(
                handlers,
                message,
                context);

            sut.Should().ThrowExactly <AggregateException>()
            .Where(exception => exception.InnerExceptions.Count == 2, "two handlers did throw an exception");
        }
        public void when_executed_without_context_it_should_throw()
        {
            var container = new Container();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
            container.AddLogging(_testOutput);
            var strategy = new ParallelHandlersExecutionStrategy(container.GetInstance <ILogger <ParallelHandlersExecutionStrategy> >());
            var handlers = VentureContextTools.CreateHandlerDescriptors(new MessageHandler()).ToArray();
            var message  = new Message02();

            // ReSharper disable once AssignNullToNotNullAttribute - it's a test against null.
            Func <Task> sut = () => strategy.ExecuteHandlers(
                handlers,
                message,
                context: null);

            sut.Should().Throw <ArgumentNullException>().Where(exception => exception.ParamName.Equals("context"));
        }
        public async Task when_executed_with_filled_context_it_should_execute_all_handlers()
        {
            var sut = new ExecuteMessageHandlersStep(new ExecutionStrategy());

            var handler1 = new MessageHandler();
            var handler2 = new MessageHandler();
            var handler3 = new MessageHandler();
            var handlers = VentureContextTools.CreateHandlerDescriptors(
                handler1,
                handler2,
                handler3);
            var context = VentureContextTools.CreateFilledPoezdContext(new Message02(), handlers);

            await sut.Execute(context);

            handler1.IsExecuted.Should().BeTrue("handler #1 should be called");
            handler2.IsExecuted.Should().BeTrue("handler #2 should be called");
            handler3.IsExecuted.Should().BeTrue("handler #3 should be called");
        }
        public async Task when_executed_with_few_handlers_it_should_execute_all_of_them()
        {
            var handler1 = new MessageHandler();
            var handler2 = new MessageHandler();
            var handler3 = new MessageHandler();
            var handlers = VentureContextTools.CreateHandlerDescriptors(
                handler1,
                handler2,
                handler3).ToArray();
            var message = new Message02();
            var context = VentureContextTools.CreateFilledVentureContext(message);
            var sut     = new ParallelHandlersExecutionStrategy(NullLogger <ParallelHandlersExecutionStrategy> .Instance);

            await sut.ExecuteHandlers(
                handlers,
                message,
                context);

            handler1.IsExecuted.Should().BeTrue("handler #1 should be called");
            handler2.IsExecuted.Should().BeTrue("handler #2 should be called");
            handler3.IsExecuted.Should().BeTrue("handler #3 should be called");
        }
        public void when_executed_without_required_context_items_it_should_throw()
        {
            var step = new ExecuteMessageHandlersStep(new ExecutionStrategy());

            MessageHandlingContext context = null;
            // ReSharper disable once AssignNullToNotNullAttribute - it's a test against null.
            // ReSharper disable once AccessToModifiedClosure - it's a way to test.
            Func <Task> sut = () => step.Execute(context !);

            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.MessageType = null);
            sut.Should().Throw <PoezdOperationException>("message type is required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.QueueName = null);
            sut.Should().Throw <PoezdOperationException>("queue name is required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.Handlers = null);
            sut.Should().Throw <PoezdOperationException>("handlers are required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.ReceivedOnUtc = DateTimeOffset.MinValue);
            sut.Should().Throw <PoezdOperationException>("received on moment is required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.CorrelationId = null);
            sut.Should().NotThrow <PoezdOperationException>("correlation ID is not required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.CausationId = null);
            sut.Should().NotThrow <PoezdOperationException>("causation ID is not required");
            context = VentureContextTools.CreateContextWithout(handlingContext => handlingContext.MessageId = null);
            sut.Should().NotThrow <PoezdOperationException>("message ID is not required");
        }
        public void when_executed_with_handlers_it_should_log_execution_progress()
        {
            var container = new Container();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
            container.AddLogging(_testOutput);
            var handlers = VentureContextTools.CreateHandlerDescriptors(
                new MessageHandler(),
                new ThrowingHandler(),
                new ThrowingHandler()).ToArray();
            var message  = new Message02();
            var context  = VentureContextTools.CreateFilledVentureContext(message);
            var strategy = new ParallelHandlersExecutionStrategy(container.GetInstance <ILogger <ParallelHandlersExecutionStrategy> >());

            Func <Task> sut = () => strategy.ExecuteHandlers(
                handlers,
                message,
                context);

            sut.Should().ThrowExactly <AggregateException>();
            InMemorySink.Instance.LogEvents
            .Where(log => log.Level == LogEventLevel.Debug)
            .Select(log => log.RenderMessage())
            .Count(log => log.StartsWith("Executing a message handler of type"))
            .Should().Be(handlers.Length, "for each handler should be logged its start");
            InMemorySink.Instance.LogEvents
            .Where(log => log.Level == LogEventLevel.Debug)
            .Select(log => log.RenderMessage())
            .Count(log => log.StartsWith("Executed a message handler of type"))
            .Should().Be(handlers.Length, "for each handler should be logged its finish");
            InMemorySink.Instance.LogEvents
            .Where(log => log.Level == LogEventLevel.Error)
            .Select(log => log.RenderMessage())
            .Count(log => log.StartsWith("An error occurred during a message handler execution of type"))
            .Should().Be(expected: 2, "for each failed handler should be logged an error");
        }