public async Task When_new_resolved_event_then_should_dispatch()
        {
            await _nodeStarted;

            var dispatchedEvents = new List<EventMessage<TestEvent>>();
            var handlerModule = new TestHandlerModule(dispatchedEvents);

            var serializer = new DefaultGetEventStoreJsonSerializer();

            using(var host = new ResolvedEventDispatcher(
                _connection, serializer,
                new InMemoryCheckpointRepository(),
                new HandlerResolver(handlerModule)))
            {
                var projectedEvents = host
                    .ProjectedEvents.Replay();

                using(projectedEvents.Connect())
                {
                    await host.Start();

                    Task<ResolvedEvent> commitProjected = projectedEvents
                        .Take(1)
                        .ToTask()
                        .WithTimeout(TimeSpan.FromSeconds(5));

                    var @event = new TestEvent();

                    var streamId = "events".FormatStreamIdWithBucket();
                    var eventId = DeterministicEventIdGenerator.Generate(@event, 1, streamId, Guid.NewGuid());
                    var eventData = serializer.SerializeEventData(@event, eventId);

                    await _connection.AppendToStreamAsync(streamId, ExpectedVersion.Any, eventData);

                    await commitProjected;

                    dispatchedEvents.Count.Should().Be(1);
                    dispatchedEvents[0].Headers.Should().NotBeNull();
                    dispatchedEvents[0].Version.Should().Be(0);
                    dispatchedEvents[0].DomainEvent.Should().BeOfType<TestEvent>();
                }
            }
        }
        public ProcessManagerHandlerTests()
        {
            TestLogger.Configure();

            var source = new TaskCompletionSource<bool>();
            _nodeStarted = source.Task;

            var notListening = new IPEndPoint(IPAddress.None, 0);

            _node = EmbeddedVNodeBuilder.AsSingleNode()
                .WithInternalTcpOn(notListening)
                .WithExternalTcpOn(notListening)
                .WithInternalHttpOn(notListening)
                .WithExternalHttpOn(notListening);

            _node.NodeStatusChanged += (_, e) =>
            {
                if(e.NewVNodeState != VNodeState.Master)
                {
                    return;
                }

                source.SetResult(true);
            };

            _node.Start();

            _connection = EmbeddedEventStoreConnection.Create(_node);

            _commands = new List<object>();

            _serializer = new DefaultGetEventStoreJsonSerializer();

            var commandHandlerModule = new CommandHandlerModule();
            commandHandlerModule.For<ShipOrder>()
                .Handle((message, _) =>
                {
                    _commands.Add(message.Command);
                    return Task.FromResult(0);
                });
            commandHandlerModule.For<BillCustomer>()
                .Handle((message, _) =>
                {
                    _commands.Add(message.Command);
                    return Task.FromResult(0);
                });

            var resolver = new CommandHandlerResolver(commandHandlerModule);
            var commandHandlingMiddleware =
                CommandHandlingMiddleware.HandleCommands(new CommandHandlingSettings(resolver));
            var embeddedClient = commandHandlingMiddleware.CreateEmbeddedClient();

            var processHandler = ProcessHandler.For<OrderFulfillment, CompareablePosition>(
                (command, token) => embeddedClient.PutCommand(command, Guid.NewGuid()),
                new EventStoreClientProcessManagerCheckpointRepository(_connection, _serializer))
                .CorrelateBy<OrderPlaced>(e => e.DomainEvent.OrderId.ToString())
                .CorrelateBy<OrderShipped>(e => e.DomainEvent.OrderId.ToString())
                .CorrelateBy<BillingSucceeded>(e => e.DomainEvent.OrderId.ToString())
                .CorrelateBy<BillingFailed>(e => e.DomainEvent.OrderId.ToString());


            _dispatcher = new ResolvedEventDispatcher(_connection,
                new DefaultGetEventStoreJsonSerializer(),
                new InMemoryCheckpointRepository(),
                processHandler.BuildHandlerResolver(),
                () => { });

            _orderId = Guid.NewGuid();
            _streamId = ("orders-" + _orderId.ToString("n")).FormatStreamIdWithBucket();
            _correlationId = _orderId.ToString();
        }
        public async Task When_handler_throws_Then_invoke_exception_callback()
        {
            await _nodeStarted;

            var serializer = new DefaultGetEventStoreJsonSerializer();
            var handlerModule = new TestHandlerModule(new List<EventMessage<TestEvent>>());

            using(var host = new ResolvedEventDispatcher(
                _connection, serializer,
                new InMemoryCheckpointRepository(),
                new HandlerResolver(handlerModule)))
            {
                var projectedEvents = host
                    .ProjectedEvents.Replay();

                using(projectedEvents.Connect())
                {
                    await host.Start();

                    Task<ResolvedEvent> commitProjected = projectedEvents
                        .Take(1)
                        .ToTask()
                        .WithTimeout(TimeSpan.FromSeconds(5));

                    var @event = new TestEventThatThrows();
                    var streamId = "events";
                    var eventId = DeterministicEventIdGenerator.Generate(@event, 1, streamId, Guid.NewGuid());
                    var eventData = serializer.SerializeEventData(@event, eventId);

                    await _connection.AppendToStreamAsync(streamId, ExpectedVersion.Any,eventData);

                    Func<Task> act = async () => await commitProjected;

                    act.ShouldThrow<Exception>();
                }
            }
        }