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 WhenCachedBlocksHitTripLevel_ThenStallsUntilWriteOperationSucceeds() { var blocks = new List <IList <BlockData> >(); Action <IReadOnlyCollection <BlockData>, CancellationToken> saveBlocks = (d, ct) => blocks.Add(d.ToList()); var failWrite = true; _writerMock .Setup(w => w.WriteAsync(It.IsAny <IReadOnlyCollection <BlockData> >(), It.IsAny <CancellationToken>())) .Returns(() => TaskHelpers.CreateCompletedTask(!Volatile.Read(ref failWrite))) .Callback(saveBlocks); var context = MockPartitionContext.CreateWithNoopCheckpoint("0"); await _processor.OpenAsync(context); // first N requests fail but go through (the first batch will not fill a frame so it won't result in a write operation) for (int i = 0; i < CircuitBreakerStallLevel + 1; i++) { var batch = new[] { CreateEventData((byte)('a' + i), MaxBlockSize - 200 - i), }; Task processTask = _processor.ProcessEventsAsync(context, batch); await AssertExt.CompletesBeforeTimeoutAsync(processTask, TimeoutInterval); } // N+1th stalls and waits for cached frames to be flushed { var batch = new[] { CreateEventData((byte)('a' + CircuitBreakerStallLevel + 2), 10), }; Task processTask = _processor.ProcessEventsAsync(context, batch); await AssertExt.DoesNotCompleteBeforeTimeoutAsync(processTask, TimeoutInterval); // let the write operation through Volatile.Write(ref failWrite, false); await AssertExt.CompletesBeforeTimeoutAsync(processTask, TimeoutInterval); // check the stalled entries were written var bufferedBlocks = blocks.Last(); Assert.Equal(CircuitBreakerStallLevel, bufferedBlocks.Count); for (int i = 0; i < CircuitBreakerStallLevel; i++) { var lines = GetPayloadsFromBlock(bufferedBlocks[i]); Assert.Equal(1, lines.Length); Assert.Equal( new string((char)('a' + i), MaxBlockSize - 200 - i), lines[0]); } } }
public async Task WhenIncomingMessagesFailToFillABlock_ThenDoesNotWrite() { var context = MockPartitionContext.CreateWithNoopCheckpoint("0"); await _processor.OpenAsync(context); await _processor.ProcessEventsAsync( context, new[] { CreateEventData((byte)'a', 100), CreateEventData((byte)'b', 200), CreateEventData((byte)'c', 300), }); _writerMock.Verify( w => w.WriteAsync(It.IsAny <IReadOnlyCollection <BlockData> >(), It.IsAny <CancellationToken>()), Times.Never()); }
public async Task ProcessEventsAsyncSendsEventDataToWriter() { var context = MockPartitionContext.CreateWithNoopCheckpoint("0"); await _processor.OpenAsync(context); var eventData = new EventData(Encoding.UTF8.GetBytes("{ \"property1\": \"value1\"}")); var eventDataArray = new[] { eventData }; await _processor.ProcessEventsAsync(context, eventDataArray); _writerMock.Verify( w => w.WriteAsync(It.Is <List <EventData> >(p => p.Contains(eventData)), It.IsAny <CancellationToken>()), Times.Once); }
public async Task BuildingIdPropertyPopulatedFromLookupService() { _lookupServiceMock.Setup(service => service.GetBuildingId("123")).Returns(() => "456"); var context = MockPartitionContext.CreateWithNoopCheckpoint("0"); await _processor.OpenAsync(context); var eventData = new EventData(Encoding.UTF8.GetBytes("{ \"DeviceId\": \"123\"}")); var eventDataArray = new[] { eventData }; await _processor.ProcessEventsAsync(context, eventDataArray); _writerMock.Verify( w => w.WriteAsync(It.Is <List <EventData> >(p => p.First().Properties["BuildingId"] as string == "456"), It.IsAny <CancellationToken>()), Times.Once); }
public async Task WhenCachedBlocksRemainBelowTripLevel_ThenDoesNotStall() { var blocks = new List <IList <BlockData> >(); Action <IReadOnlyCollection <BlockData>, CancellationToken> saveBlocks = (d, ct) => blocks.Add(d.ToList()); _writerMock .Setup(w => w.WriteAsync(It.IsAny <IReadOnlyCollection <BlockData> >(), It.IsAny <CancellationToken>())) .Returns(() => TaskHelpers.CreateCompletedTask(false)) .Callback(saveBlocks); var context = MockPartitionContext.CreateWithNoopCheckpoint("0"); await _processor.OpenAsync(context); for (int i = 0; i < CircuitBreakerStallLevel; i++) { var batch = new[] { CreateEventData((byte)('a' + i), MaxBlockSize - 200 - i), }; Task processTask = _processor.ProcessEventsAsync(context, batch); await AssertExt.CompletesBeforeTimeoutAsync(processTask, TimeoutInterval); } }