public async Task Given_Existing_Queue_When_New_Message_Queued_Then_Listener_Should_Fire() { var listenerCalledEvent = new ManualResetEvent(false); var tempDir = GetTempDirectory(); var fsQueueingService = new FilesystemMessageQueueingService(tempDir); fsQueueingService.Init(); var mockListener = new Mock<IQueueListener>(); mockListener.Setup( x => x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>())) .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) => { ctx.Acknowledge(); listenerCalledEvent.Set(); }) .Returns(Task.FromResult(true)); var queueName = new QueueName(Guid.NewGuid().ToString()); await fsQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {MaxAttempts = 1}); var message = new Message(new MessageHeaders { {HeaderName.ContentType, "text/plain"}, {HeaderName.MessageId, Guid.NewGuid().ToString()} }, "Hello, world!"); await fsQueueingService.EnqueueMessage(queueName, message, Thread.CurrentPrincipal); await listenerCalledEvent.WaitOneAsync(TimeSpan.FromSeconds(1)); var messageEqualityComparer = new MessageEqualityComparer(); mockListener.Verify( x => x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once()); }
public async Task Given_Queued_Message_When_Acknowledged_Then_Message_Should_Be_Deleted() { var listenerCalledEvent = new ManualResetEvent(false); var tempDir = GetTempDirectory(); var queueName = new QueueName(Guid.NewGuid().ToString()); var queuePath = Path.Combine(tempDir.FullName, queueName); var queueDir = new DirectoryInfo(queuePath); if (!queueDir.Exists) { queueDir.Create(); } var fsQueueingService = new FilesystemMessageQueueingService(tempDir); fsQueueingService.Init(); var mockListener = new Mock<IQueueListener>(); mockListener.Setup( x => x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>())) .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) => { ctx.Acknowledge(); listenerCalledEvent.Set(); }) .Returns(Task.FromResult(true)); await fsQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {MaxAttempts = 1}); var message = new Message(new MessageHeaders { {HeaderName.ContentType, "text/plain"}, {HeaderName.MessageId, Guid.NewGuid().ToString()} }, "Hello, world!"); await fsQueueingService.EnqueueMessage(queueName, message, Thread.CurrentPrincipal); await listenerCalledEvent.WaitOneAsync(TimeSpan.FromSeconds(1)); // The listener is called before the file is deleted, so there is a possible // race condition here. Wait for a second to allow the delete to take place // before enumerating the files to see that they were actually deleted. await Task.Delay(TimeSpan.FromSeconds(1)); var messageEqualityComparer = new MessageEqualityComparer(); mockListener.Verify( x => x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once()); var queuedMessages = queueDir.EnumerateFiles() .Select(f => new MessageFile(f)) .ToList(); Assert.That(queuedMessages, Is.Empty); }
public async Task Given_10_Existing_Messages_10_New_Messages_Then_Listener_Should_Fire_For_All_20_Messages() { var existingMessages = Enumerable.Range(1, 10) .Select(i => new Message(new MessageHeaders { {HeaderName.ContentType, "text/plain"}, {HeaderName.MessageId, Guid.NewGuid().ToString()} }, "Hello, world! (" + i + ")")) .ToList(); var tempDir = GetTempDirectory(); var queueName = new QueueName(Guid.NewGuid().ToString()); var queuePath = Path.Combine(tempDir.FullName, queueName); var queueDir = new DirectoryInfo(queuePath); if (!queueDir.Exists) { queueDir.Create(); } await Task.WhenAll(existingMessages.Select(msg => MessageFile.Create(queueDir, msg, Thread.CurrentPrincipal))); var newMessages = Enumerable.Range(1, 10) .Select(i => new Message(new MessageHeaders { {HeaderName.ContentType, "text/plain"}, {HeaderName.MessageId, Guid.NewGuid().ToString()} }, "Hello, world! (" + i + ")")) .ToList(); var listenerCountdown = new CountdownEvent(existingMessages.Count + newMessages.Count); var fsQueueingService = new FilesystemMessageQueueingService(tempDir); fsQueueingService.Init(); var mockListener = new Mock<IQueueListener>(); mockListener.Setup( x => x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>())) .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) => { ctx.Acknowledge(); listenerCountdown.Signal(); }) .Returns(Task.FromResult(true)); await fsQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {MaxAttempts = 1}); await Task.WhenAll(newMessages.Select(msg => fsQueueingService.EnqueueMessage(queueName, msg, Thread.CurrentPrincipal))); var timedOut = !await listenerCountdown.WaitHandle.WaitOneAsync(TimeSpan.FromSeconds(10)); Assert.That(timedOut, Is.False, "Timed out waiting for listeners to be called"); var messageEqualityComparer = new MessageEqualityComparer(); var allmessages = existingMessages.Union(newMessages); foreach (var message in allmessages) { mockListener.Verify( x => x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once()); } }
public async Task Given_Auto_Acknowledge_Queue_When_Listener_Throws_Then_Message_Should_Not_Be_Deleted() { var listenerCalledEvent = new ManualResetEvent(false); var tempDir = GetTempDirectory(); var queueName = new QueueName(Guid.NewGuid().ToString()); var queuePath = Path.Combine(tempDir.FullName, queueName); var queueDir = new DirectoryInfo(queuePath); if (!queueDir.Exists) { queueDir.Create(); } var fsQueueingService = new FilesystemMessageQueueingService(tempDir); fsQueueingService.Init(); var mockListener = new Mock<IQueueListener>(); mockListener.Setup( x => x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>())) .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) => { listenerCalledEvent.Set(); throw new Exception(); }); await fsQueueingService .CreateQueue(queueName, mockListener.Object, new QueueOptions { AutoAcknowledge = true, MaxAttempts = 2, // So the message doesn't get moved to the DLQ RetryDelay = TimeSpan.FromSeconds(30) }); var message = new Message(new MessageHeaders { {HeaderName.ContentType, "text/plain"}, {HeaderName.MessageId, Guid.NewGuid().ToString()} }, "Hello, world!"); await fsQueueingService.EnqueueMessage(queueName, message, Thread.CurrentPrincipal); var listenerCalled = await listenerCalledEvent .WaitOneAsync(Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(3)); Assert.That(listenerCalled, Is.True); // The listener is called before the file is deleted, so there is a possible // race condition here. Wait for a second to allow the delete to take place // before enumerating the files to see that they were actually not deleted. await Task.Delay(TimeSpan.FromSeconds(1)); var messageEqualityComparer = new MessageEqualityComparer(); mockListener.Verify( x => x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)), It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once()); var queuedMessages = queueDir.EnumerateFiles() .Select(f => new MessageFile(f)) .ToList(); Assert.That(queuedMessages.Count, Is.EqualTo(1)); Assert.That(await queuedMessages[0].ReadMessage(), Is.EqualTo(message).Using(messageEqualityComparer)); }