public async Task ShouldNotPublishToPoisonQueueWhenMessageIsHandled()
        {
            var handled = false;

            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var events = new[] { new EventData() };

            var resovler = new MockMessageHandlerResolver(
                (body, headers) =>
            {
                handled = true;
                return(Task.FromResult <object>(null));
            });

            var poisonHandler = (MockPoisonMessageHandler)DependencyResolverFactory
                                .GetResolver()
                                .GetService(typeof(IPoisonMessageHandler));

            var processor = new EventProcessor(resovler, new MockCircuitBreaker(), 1, "test", Mock.Of <IDispatcherInstrumentationPublisher>());

            await processor.ProcessEventsAsync(context, events);

            Assert.True(handled);
            Assert.False(
                poisonHandler.Messages.Any(),
                String.Format("Expected poison handler to have no messages; count = {0}",
                              poisonHandler.Messages.Count()));
        }
        public async Task ShouldProcessMessagesConcurrently()
        {
            const int Concurrency  = 4;
            const int MessageCount = 4;
            const int MsPerMessage = 300;

            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var events = Enumerable
                         .Range(0, MessageCount)
                         .Select(id => new EventData())
                         .ToArray();

            var resovler = new MockMessageHandlerResolver(
                async(body, headers) => { await Task.Delay(TimeSpan.FromMilliseconds(MsPerMessage)); });

            var processor = new EventProcessor(resovler, new MockCircuitBreaker(), Concurrency, "test", Mock.Of <IDispatcherInstrumentationPublisher>());

            var sw = Stopwatch.StartNew();
            await processor.ProcessEventsAsync(context, events);

            sw.Stop();

            Assert.True(sw.Elapsed < TimeSpan.FromMilliseconds(MsPerMessage * MessageCount));
            Assert.True(sw.Elapsed >= TimeSpan.FromMilliseconds(MsPerMessage));
        }
        public async Task ShouldPublishToPoisonQueueWhenHandlerThrows()
        {
            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var attemptedToResolveHandler = false;

            var events = new[] { new EventData() };

            var resolver = new MockMessageHandlerResolver(
                async(body, headers) =>
            {
                attemptedToResolveHandler = true;
                await Task.Yield();
                throw new Exception("This message was bad.");
            });

            var poisonHandler = (MockPoisonMessageHandler)DependencyResolverFactory
                                .GetResolver()
                                .GetService(typeof(IPoisonMessageHandler));

            var processor = new EventProcessor(resolver, new MockCircuitBreaker(), 1, "test", Mock.Of <IDispatcherInstrumentationPublisher>());

            await processor.ProcessEventsAsync(context, events);

            Assert.True(attemptedToResolveHandler);
            Assert.True(
                poisonHandler.Messages.Any(),
                String.Format("Expected poison handler to have messages; count = {0}",
                              poisonHandler.Messages.Count()));
        }
        public async Task ShouldNotPublishToPoisonQueueWhenMessageIsHandled()
        {
            var handled = false;

            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var events = new[] { new EventData() };

            var resovler = new MockMessageHandlerResolver(
                (body, headers) =>
                {
                    handled = true;
                    return Task.FromResult<object>(null);
                });

            var poisonHandler = (MockPoisonMessageHandler)DependencyResolverFactory
                .GetResolver()
                .GetService(typeof(IPoisonMessageHandler));

            var processor = new EventProcessor(resovler, new MockCircuitBreaker(), 1, "test", Mock.Of<IDispatcherInstrumentationPublisher>());

            await processor.ProcessEventsAsync(context, events);

            Assert.True(handled);
            Assert.False(
                poisonHandler.Messages.Any(), 
                String.Format("Expected poison handler to have no messages; count = {0}",
                poisonHandler.Messages.Count()));
        }
        public async Task ShouldPublishToPoisonQueueWhenHandlerThrows()
        {
            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var attemptedToResolveHandler = false;

            var events = new[] { new EventData() };

            var resolver = new MockMessageHandlerResolver(
                async (body, headers) =>
                {
                    attemptedToResolveHandler = true;
                    await Task.Yield();
                    throw new Exception("This message was bad.");
                });

            var poisonHandler = (MockPoisonMessageHandler)DependencyResolverFactory
                .GetResolver()
                .GetService(typeof(IPoisonMessageHandler));

            var processor = new EventProcessor(resolver, new MockCircuitBreaker(), 1, "test", Mock.Of<IDispatcherInstrumentationPublisher>());

            await processor.ProcessEventsAsync(context, events);

            Assert.True(attemptedToResolveHandler);
            Assert.True(
                poisonHandler.Messages.Any(), 
                String.Format("Expected poison handler to have messages; count = {0}",
                poisonHandler.Messages.Count()));
        }
        public void DoesNotThrowWhenCheckpointFailsWithLeaseLostExceptionTypes()
        {
            testDomain.DoCallBack(() =>
            {
                // Arrange
                var mockLogger = new Mock <ILogger>();
                LoggerFactory.Register(Mock.Of <ILogFactory>(f => f.Create(It.IsAny <string>()) == mockLogger.Object));
                var mockCircuitBreaker = new MockCircuitBreaker();
                var mockResolver       = new MockMessageHandlerResolver();

                var processor = new EventProcessor(mockResolver, mockCircuitBreaker, MaxConcurrency, EventHubName, Mock.Of <IDispatcherInstrumentationPublisher>());
                Func <Task> faultedCheckpoint = () =>
                {
                    throw new LeaseLostException();
                };

                var context = MockPartitionContext.Create(PartitionId, faultedCheckpoint);
                var events  = new[] { new EventData() };

                // Act & Assert
                processor.ProcessEventsAsync(context, events).Wait();
                mockLogger.Verify(l => l.Warning(It.IsAny <Exception>(), It.IsAny <string>(), It.IsAny <object[]>()), Times.Once);
            });
        }
        public void DoesNotThrowWhenCheckpointFailsWithStorageExceptionTypes()
        {
            testDomain.DoCallBack(() =>
            {
                // Arrange
                var mockLogger = new Mock<ILogger>();
                LoggerFactory.Register(Mock.Of<ILogFactory>(f => f.Create(It.IsAny<string>()) == mockLogger.Object));
                var mockCircuitBreaker = new MockCircuitBreaker();
                var mockResolver = new MockMessageHandlerResolver();

                var processor = new EventProcessor(mockResolver, mockCircuitBreaker, MaxConcurrency, EventHubName, Mock.Of<IDispatcherInstrumentationPublisher>());
                Func<Task> faultedCheckpoint = () =>
                {
                    throw new StorageException();
                };

                var context = MockPartitionContext.Create(PartitionId, faultedCheckpoint);
                var events = new[] { new EventData() };

                // Act & Assert
                processor.ProcessEventsAsync(context, events).Wait();
                mockLogger.Verify(l => l.Warning(It.IsAny<Exception>(), It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
            });
        }
        public async Task ShouldProcessMessagesConcurrently()
        {
            const int Concurrency = 4;
            const int MessageCount = 4;
            const int MsPerMessage = 300;

            var context = MockPartitionContext.CreateWithNoopCheckpoint("1");

            var events = Enumerable
                .Range(0, MessageCount)
                .Select(id => new EventData())
                .ToArray();

            var resovler = new MockMessageHandlerResolver(
                async (body, headers) => { await Task.Delay(TimeSpan.FromMilliseconds(MsPerMessage)); });

            var processor = new EventProcessor(resovler, new MockCircuitBreaker(), Concurrency, "test", Mock.Of<IDispatcherInstrumentationPublisher>());

            var sw = Stopwatch.StartNew();
            await processor.ProcessEventsAsync(context, events);
            sw.Stop();

            Assert.True(sw.Elapsed < TimeSpan.FromMilliseconds(MsPerMessage * MessageCount));
            Assert.True(sw.Elapsed >= TimeSpan.FromMilliseconds(MsPerMessage));
        }