Example #1
0
        public void ConsumeShouldExecuteActionToEachConsumedMessage()
        {
            // Arrange
            var topic = "my-topic";

            var consumeResultMock = new ConsumeResult <string, string>
            {
                Message = new Message <string, string>()
            };

            var actionMock   = new Mock <Action <AgnosticMessage <string> > >();
            var producerMock = new Mock <IProducer <string, string> >();
            var loggerMock   = new Mock <ILogger <KafkaConsumerWrapper <string> > >();

            // Simulates a consumer with 3 messages to be read before being terminated.
            var consumerMock = new Mock <IConsumer <string, string> >();

            consumerMock.SetupSequence(consumer => consumer.Consume(It.IsAny <CancellationToken>()))
            .Returns(consumeResultMock)
            .Returns(consumeResultMock)
            .Returns(consumeResultMock)
            .Throws <OperationCanceledException>();

            // Act
            using (var kafkaConsumerWrapper = new KafkaConsumerWrapper <string>(consumerMock.Object, producerMock.Object, loggerMock.Object))
            {
                kafkaConsumerWrapper.Consume(topic, actionMock.Object);
            }

            // Assert
            actionMock.Verify(action => action(It.IsAny <AgnosticMessage <string> >()), Times.Exactly(3));
        }
Example #2
0
        public void ConsumeShouldStopConsumingAndLeaveGroupWhenCanceled()
        {
            // Arrange
            var topic = "my-topic";

            var consumeResultMock = new ConsumeResult <string, string>
            {
                Message = new Message <string, string>()
            };

            var actionMock   = new Mock <Action <AgnosticMessage <string> > >();
            var producerMock = new Mock <IProducer <string, string> >();
            var loggerMock   = new Mock <ILogger <KafkaConsumerWrapper <string> > >();

            // Simulates a consumer being terminated immediately.
            var consumerMock = new Mock <IConsumer <string, string> >();

            consumerMock.SetupSequence(consumer => consumer.Consume(It.IsAny <CancellationToken>()))
            .Throws <OperationCanceledException>();

            // Act
            using (var kafkaConsumerWrapper = new KafkaConsumerWrapper <string>(consumerMock.Object, producerMock.Object, loggerMock.Object))
            {
                kafkaConsumerWrapper.Consume(topic, actionMock.Object);
            }

            // Assert
            actionMock.Verify(action => action(It.IsAny <AgnosticMessage <string> >()), Times.Never);
            consumerMock.Verify(consumer => consumer.Close(), Times.Once);
        }
Example #3
0
        public void ConsumeShouldSubscribeToTopic()
        {
            // Arrange
            var topic = "my-topic";

            var consumeResultMock = new ConsumeResult <string, string>
            {
                Message = new Message <string, string>()
            };

            // Simulates a consumer being terminated immediately.
            var consumerMock = new Mock <IConsumer <string, string> >();

            consumerMock.SetupSequence(consumer => consumer.Consume(It.IsAny <CancellationToken>()))
            .Returns(consumeResultMock)
            .Throws <OperationCanceledException>();

            var producerMock = new Mock <IProducer <string, string> >();
            var loggerMock   = new Mock <ILogger <KafkaConsumerWrapper <string> > >();

            // Act
            using (var kafkaConsumerWrapper = new KafkaConsumerWrapper <string>(consumerMock.Object, producerMock.Object, loggerMock.Object))
            {
                kafkaConsumerWrapper.Consume(topic, (AgnosticMessage <string> message) => {});
            }

            // Assert
            consumerMock.Verify(consumer => consumer.Subscribe(topic), Times.Once);
        }
Example #4
0
        public async Task OneTopic()
        {
            var config = new TestMessageConfiguration();

            config.Subscription.Add("TestTopic");
            config.IsValid().ShouldBe(true);
            var stringPropertyValue = "string";
            var message             = new TestMessage
            {
                String = stringPropertyValue
            };

            config.MessagePublishing += async(sender, e) =>
            {
                e.ShouldBe(config.LatestMessagePublishingEventArgs);
                e.Topic.ShouldBe("TestTopic");
                var strongTyped = JsonConvert.DeserializeObject <TestMessage>(e.Message);
                strongTyped.String.ShouldBe(stringPropertyValue);
            };
            config.MessageReceiving += async(sender, e) =>
            {
                e.Topic.ShouldBe("TestTopic");
                var strongTyped = JsonConvert.DeserializeObject <TestMessage>(e.Message);
                strongTyped.String.ShouldBe(stringPropertyValue);
            };
            var publisherWrapper = new KafkaProducerWrapper(config);
            var receiverWrapper  = new KafkaConsumerWrapper(config);
            var publisher        = new MessagePublisher(config, publisherWrapper);

            receiverWrapper.Connect();
            publisherWrapper.Connect();
            receiverWrapper.IsConnected.ShouldBe(true);
            publisherWrapper.IsConnected.ShouldBe(true);
            await publisher.PublishAsync(message);

            publisherWrapper.Disconnect();
            publisherWrapper.IsConnected.ShouldBe(false);
            config.LatestMessagePublishingEventArgs.ShouldNotBeNull();
            await Task.Delay(10000).ConfigureAwait(false);

            config.LatestMessageReceivingEventArgs.ShouldNotBeNull();
            receiverWrapper.Disconnect();
            receiverWrapper.IsConnected.ShouldBe(false);
        }
Example #5
0
        public void ConsumeShouldSendMessageToDeadLetterTopicAfterSuccessiveFailedRetries()
        {
            // Arrange
            var topic           = "my-topic";
            var deadLetterTopic = "_dead-letter_my-topic";

            var consumeResultMock = new ConsumeResult <string, string>
            {
                Topic   = topic,
                Message = new Message <string, string> {
                    Key = "msg-1"
                }
            };

            var loggerMock = new Mock <ILogger <KafkaConsumerWrapper <string> > >();

            // Simulates an action that always fail.
            var actionMock = new Mock <Action <AgnosticMessage <string> > >();

            actionMock.Setup(action => action(It.Is <AgnosticMessage <string> >(message => message.Key == consumeResultMock.Message.Key)))
            .Throws <Exception>();

            // Simulates a consumer with one message to be read before being terminated.
            var consumerMock = new Mock <IConsumer <string, string> >();

            consumerMock.SetupSequence(consumer => consumer.Consume(It.IsAny <CancellationToken>()))
            .Returns(consumeResultMock)
            .Throws <OperationCanceledException>();

            var producerMock = new Mock <IProducer <string, string> >();

            producerMock.Setup(producer => producer.ProduceAsync(deadLetterTopic, consumeResultMock.Message))
            .ReturnsAsync(new DeliveryResult <string, string>());

            // Act
            using (var kafkaConsumerWrapper = new KafkaConsumerWrapper <string>(consumerMock.Object, producerMock.Object, loggerMock.Object))
            {
                kafkaConsumerWrapper.Consume(topic, actionMock.Object);
            }

            // Assert
            actionMock.Verify(action => action(It.IsAny <AgnosticMessage <string> >()), Times.Exactly(4));
            producerMock.Verify(producer => producer.ProduceAsync(deadLetterTopic, consumeResultMock.Message), Times.Once);
        }
Example #6
0
        public void ConsumeShouldRetryExecutingActionUponFailure()
        {
            // Arrange
            var topic = "my-topic";

            var consumeResultMock = new ConsumeResult <string, string>
            {
                Message = new Message <string, string> {
                    Key = "msg-1"
                }
            };

            var producerMock = new Mock <IProducer <string, string> >();
            var loggerMock   = new Mock <ILogger <KafkaConsumerWrapper <string> > >();

            // Simulates an action that fails twice and executes successfully on the third attempt.
            var actionMock = new Mock <Action <AgnosticMessage <string> > >();

            actionMock.SetupSequence(action => action(It.Is <AgnosticMessage <string> >(message => message.Key == consumeResultMock.Message.Key)))
            .Throws <Exception>()
            .Throws <Exception>();

            // Simulates a consumer with one message to be read before being terminated.
            var consumerMock = new Mock <IConsumer <string, string> >();

            consumerMock.SetupSequence(consumer => consumer.Consume(It.IsAny <CancellationToken>()))
            .Returns(consumeResultMock)
            .Throws <OperationCanceledException>();

            // Act
            using (var kafkaConsumerWrapper = new KafkaConsumerWrapper <string>(consumerMock.Object, producerMock.Object, loggerMock.Object))
            {
                kafkaConsumerWrapper.Consume(topic, actionMock.Object);
            }

            // Assert
            actionMock.Verify(action => action(It.IsAny <AgnosticMessage <string> >()), Times.Exactly(3));
        }
Example #7
0
        public async Task SpecifingTopics()
        {
            var config       = new TestMessageConfiguration();
            var pubCount     = 0;
            var subCount     = 0;
            var subTopicList = new List <string>();

            config.IsValid().ShouldBe(true);
            var stringPropertyValue = "string";
            var message1            = new TestMessage
            {
                String = stringPropertyValue
            };
            var message2 = new TestMessage2
            {
                String = stringPropertyValue
            };
            var message3 = new TestMessage3
            {
                String = stringPropertyValue
            };

            config.MessagePublishing += async(sender, e) =>
            {
                pubCount++;
                e.ShouldBe(config.LatestMessagePublishingEventArgs);
                new[] { "TestTopic", "2TestTopic", "3TestTopic" }
                .ShouldContain(e.Topic);
                var strongTyped = JsonConvert.DeserializeObject <TestMessage>(e.Message);
                strongTyped.String.ShouldBe(stringPropertyValue);
            };
            config.Subscription.Add("2TestTopic");
            config.Subscription.Add("3TestTopic");

            config.MessageReceiving += async(sender, e) =>
            {
                subCount++;
                subTopicList.Add(e.Topic);
                config.Subscription.ShouldContain(e.Topic);
                var strongTyped = JsonConvert.DeserializeObject <TestMessage>(e.Message);
                strongTyped.String.ShouldBe(stringPropertyValue);
            };
            var publisherWrapper = new KafkaProducerWrapper(config);
            var receiverWrapper  = new KafkaConsumerWrapper(config);
            var publisher        = new MessagePublisher(config, publisherWrapper);

            receiverWrapper.Connect();
            publisherWrapper.Connect();
            await publisher.PublishAsync(message1);

            await publisher.PublishAsync(message2);

            await publisher.PublishAsync(message3);

            publisherWrapper.Disconnect();
            await Task.Delay(10000).ConfigureAwait(false);

            receiverWrapper.Disconnect();
            config.LatestMessagePublishingEventArgs.ShouldNotBeNull();
            config.LatestMessageReceivingEventArgs.ShouldNotBeNull();
            pubCount.ShouldBe(3);
            subCount.ShouldBe(2);
        }