public async Task When_Reader_Completes_When_All_Readers_Completed()
        {
            // Arrange
            using var multiplexer = new MergingMultiplexer(10, _outputHelper.ToLogger <MergingMultiplexer>());

            var cts = new CancellationTokenSource();

            var channel1 = Channel.CreateBounded <IQueueMessageContext>(10);
            var channel2 = Channel.CreateBounded <IQueueMessageContext>(10);

            multiplexer.ReadFrom(channel1);
            multiplexer.ReadFrom(channel2);

            // Act
            await multiplexer.RunAsync(cts.Token);

            var multiplexerRunTask = ReadAllMessages(multiplexer);

            channel1.Writer.Complete();
            channel2.Writer.Complete();

            // Assert
            await Patiently.AssertThatAsync(_outputHelper, () => multiplexerRunTask.IsCompletedSuccessfully);

            cts.Cancel();
        }
Example #2
0
        // Quick fix for user entity manipulation outside of this db context
        // TODO: Fix properly
        static public async Task <User> GetUserEntityAsync(this BotDatabaseContext context, IUser user)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            // Update cached displayname
            var displayName = user.Username;

            var result = await Patiently.HandleDbConcurrency(async() => {
                var userEntity = await context.Users.AsQueryable().FirstOrDefaultAsync(o => o.Id == user.Id);

                if (userEntity != null && userEntity.Name != displayName)
                {
                    userEntity.Name = displayName;
                    await context.SaveChangesAsync();
                }

                return(userEntity);
            });

            return(result);
        }
        public async Task ThenExceptionIsRecordedInMonitoring()
        {
            _handler.WaitUntilCompletion(15.Seconds()).ShouldBe(true);

            await Patiently.VerifyExpectationAsync(
                () => Monitoring.Received().HandleException(Arg.Any <string>()));
        }
Example #4
0
 public async Task FailedMessageIsNotRemovedFromQueue()
 {
     // The un-handled one is however.
     await Patiently.VerifyExpectationAsync(
         () => Sqs.DidNotReceiveWithAnyArgs().DeleteMessage(
             Arg.Any <DeleteMessageRequest>()));
 }
Example #5
0
    public async Task Then_Both_Handlers_Receive_Messages()
    {
        // Arrange
        var genericHandler    = new InspectableHandler <GenericMessage <SimpleMessage> >();
        var nonGenericHandler = new InspectableHandler <SimpleMessage>();

        var services = GivenJustSaying()
                       .ConfigureJustSaying((builder) => builder.WithLoopbackTopic <GenericMessage <SimpleMessage> >($"{UniqueName}-generic"))
                       .ConfigureJustSaying((builder) => builder.WithLoopbackTopic <SimpleMessage>($"{UniqueName}-nongeneric"))
                       .AddSingleton <IHandlerAsync <GenericMessage <SimpleMessage> > >(genericHandler)
                       .AddSingleton <IHandlerAsync <SimpleMessage> >(nonGenericHandler);

        await WhenAsync(
            services,
            async (publisher, listener, serviceProvider, cancellationToken) =>
        {
            await listener.StartAsync(cancellationToken);
            await publisher.StartAsync(cancellationToken);

            // Act
            await publisher.PublishAsync(new GenericMessage <SimpleMessage>(), cancellationToken);
            await publisher.PublishAsync(new SimpleMessage(), cancellationToken);

            await Patiently.AssertThatAsync(OutputHelper,
                                            () =>
            {
                genericHandler.ReceivedMessages.ShouldHaveSingleItem();
                nonGenericHandler.ReceivedMessages.ShouldHaveSingleItem();
            });
        });
    }
 public async Task EventPublicationWasAttemptedTheConfiguredNumberOfTimes()
 {
     await Patiently.VerifyExpectationAsync(() =>
                                            _publisher
                                            .Received(PublishAttempts)
                                            .Publish(Arg.Any <GenericMessage>()));
 }
Example #7
0
        public async Task Then_The_Message_Is_Handled()
        {
            // Arrange
            var handler    = new ThrowingHandler();
            var monitoring = Substitute.For <IMessageMonitor>();

            var services = GivenJustSaying()
                           .ConfigureJustSaying((builder) => builder.WithLoopbackQueue <SimpleMessage>(UniqueName))
                           .ConfigureJustSaying((builder) => builder.Services((options) =>
                                                                              options.WithMessageMonitoring(() => monitoring)))
                           .AddSingleton <IHandlerAsync <SimpleMessage> >(handler);

            var message = new SimpleMessage();

            await WhenAsync(
                services,
                async (publisher, listener, cancellationToken) =>
            {
                await listener.StartAsync(cancellationToken);
                await publisher.StartAsync(cancellationToken);

                // Act
                await publisher.PublishAsync(message, cancellationToken);

                await Patiently.AssertThatAsync(OutputHelper, () =>
                {
                    handler.MessageReceived.ShouldNotBeNull();
                    monitoring.Received().HandleException(Arg.Any <Type>());
                });
            });
        }
Example #8
0
 public async Task CorrectQueueIsPolled()
 {
     await Patiently.VerifyExpectationAsync(() =>
                                            Sqs.Received().ReceiveMessageAsync(
                                                Arg.Is <ReceiveMessageRequest>(x => x.QueueUrl == QueueUrl),
                                                Arg.Any <CancellationToken>()));
 }
Example #9
0
 public async Task TheMaxMessageAllowanceIsGrabbed()
 {
     await Patiently.VerifyExpectationAsync(() =>
                                            Sqs.Received().ReceiveMessageAsync(
                                                Arg.Is <ReceiveMessageRequest>(x => x.MaxNumberOfMessages == 10),
                                                Arg.Any <CancellationToken>()));
 }
Example #10
0
    public async Task Then_The_Error_Queue_Is_Not_Created()
    {
        // Arrange
        ILoggerFactory    loggerFactory = OutputHelper.ToLoggerFactory();
        IAwsClientFactory clientFactory = CreateClientFactory();

        var client = clientFactory.GetSqsClient(Region);

        var queue = new SqsQueueByName(
            Region,
            UniqueName,
            client,
            1,
            loggerFactory);

        // Act
        await queue.CreateAsync(new SqsBasicConfiguration()
        {
            ErrorQueueOptOut = true
        });

        // Assert
        await Patiently.AssertThatAsync(
            OutputHelper, async() => !await queue.ErrorQueue.ExistsAsync(CancellationToken.None));
    }
Example #11
0
        public async Task QueueIsCreated()
        {
            async Task QueueIsCreatedInner()
            {
                var queue = new SqsQueueByName(
                    TestFixture.Region,
                    QueueName,
                    Client,
                    0,
                    TestFixture.LoggerFactory);

                await Patiently.AssertThatAsync(
                    () => queue.ExistsAsync(), TimeSpan.FromSeconds(65));
            }

            var task = QueueIsCreatedInner();

            if (task == await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(70))))
            {
                await task;
            }
            else
            {
                throw new TimeoutException();
            }
        }
 public async Task MessageIsLocked()
 {
     await Patiently.VerifyExpectationAsync(
         () => MessageLock.Received().TryAquireLock(
             Arg.Is <string>(a => a.Contains(DeserialisedMessage.Id.ToString())),
             TimeSpan.FromSeconds(_expectedtimeout)));
 }
        public async Task Sqs_Policy_Is_Applied_With_Wildcard()
        {
            // Arrange
            var handler = new ExactlyOnceHandlerWithTimeout();

            var services = GivenJustSaying()
                           .ConfigureJustSaying((builder) => builder.WithLoopbackTopic <TopicA>(UniqueName))
                           .ConfigureJustSaying((builder) => builder.WithLoopbackTopic <TopicB>(UniqueName))
                           .AddJustSayingHandler <TopicA, HandlerA>()
                           .AddJustSayingHandler <TopicB, HandlerB>();

            await WhenAsync(
                services,
                async (publisher, listener, serviceProvider, cancellationToken) =>
            {
                listener.Start(cancellationToken);

                var clientFactory = serviceProvider.GetRequiredService <MessagingBusBuilder>().BuildClientFactory();
                var loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();
                var client        = clientFactory.GetSqsClient(Region);

                var queue = new SqsQueueByName(Region, UniqueName, client, 0, loggerFactory);

                await Patiently.AssertThatAsync(() => queue.ExistsAsync(), 60.Seconds());

                dynamic policyJson = JObject.Parse(queue.Policy);

                policyJson.Statement.Count.ShouldBe(1, $"Expecting 1 statement in Sqs policy but found {policyJson.Statement.Count}.");
            });
        }
Example #14
0
        [Then, Timeout(70000)] // ToDo: Sorry about this, but SQS is a little slow to verify against. Can be better I'm sure? ;)
        public async Task QueueIsCreated()
        {
            var queue = new SqsQueueByName(RegionEndpoint.EUWest1,
                                           QueueName, CreateMeABus.DefaultClientFactory().GetSqsClient(RegionEndpoint.EUWest1), 0);

            await Patiently.AssertThatAsync(
                queue.Exists, TimeSpan.FromSeconds(65));
        }
Example #15
0
        [Then, Timeout(70000)] // ToDo: Sorry about this, but SQS is a little slow to verify against. Can be better I'm sure? ;)
        public async Task QueueIsCreated()
        {
            var queue = new SqsQueueByName(RegionEndpoint.EUWest1,
                                           QueueName, Client, 0, Substitute.For <ILoggerFactory>());

            await Patiently.AssertThatAsync(
                queue.Exists, TimeSpan.FromSeconds(65));
        }
        private async Task ThenTheSubscriberReceivesBothMessages()
        {
            await Patiently.AssertThatAsync(
                () => _handler.HasReceived(_message1));

            await Patiently.AssertThatAsync(
                () => _handler.HasReceived(_message2));
        }
Example #17
0
        public async Task SqsPolicyWithAWildcardIsApplied()
        {
            var queue = new SqsQueueByName(RegionEndpoint.EUWest1, QueueName, Client, 0);
            await Patiently.AssertThatAsync(queue.Exists, TimeSpan.FromSeconds(60));

            dynamic policyJson = JObject.Parse(queue.Policy);

            Assert.IsTrue(policyJson.Statement.Count == 1, $"Expecting 1 statement in Sqs policy but found {policyJson.Statement.Count}");
        }
 public async Task SubscribersStartedUp()
 {
     await Patiently.AssertThatAsync(OutputHelper,
                                     () =>
     {
         _queue1.ReceiveMessageRequests.Count.ShouldBeGreaterThan(0);
         _queue2.ReceiveMessageRequests.Count.ShouldBeGreaterThan(0);
     });
 }
Example #19
0
    public async Task Buffer_Is_Filled()
    {
        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
        var _ = _messageReceiveBuffer.RunAsync(cts.Token);

        await Patiently.AssertThatAsync(_outputHelper, () => _callCount > 0);

        _callCount.ShouldBeGreaterThan(0);
    }
Example #20
0
        public async Task SqsPolicyWithAWildcardIsApplied()
        {
            var queue = new SqsQueueByName(RegionEndpoint.EUWest1, QueueName, Client, 0, Substitute.For <ILoggerFactory>());
            await Patiently.AssertThatAsync(queue.Exists, TimeSpan.FromSeconds(60));

            dynamic policyJson = JObject.Parse(queue.Policy);

            policyJson.Statement.Count.ShouldBe(1, $"Expecting 1 statement in Sqs policy but found {policyJson.Statement.Count}");
        }
        public async Task Subscriber_Not_Started_No_Buffer_Filled_Then_No_More_Messages_Requested()
        {
            // Arrange
            int messagesFromQueue   = 0;
            int messagesDispatched  = 0;
            int receivebufferSize   = 2;
            int multiplexerCapacity = 2;

            // plus one "in flight" between buffer and multiplexer
            int expectedReceiveFromQueueCount = receivebufferSize + multiplexerCapacity + 1;

            var sqsQueue = TestQueue(() => Interlocked.Increment(ref messagesFromQueue));
            IMessageReceiveBuffer buffer     = CreateMessageReceiveBuffer(sqsQueue, receivebufferSize);
            IMessageDispatcher    dispatcher =
                new FakeDispatcher(() => Interlocked.Increment(ref messagesDispatched));
            IMultiplexerSubscriber consumer1   = CreateSubscriber(dispatcher);
            IMultiplexer           multiplexer = CreateMultiplexer(multiplexerCapacity);

            multiplexer.ReadFrom(buffer.Reader);
            consumer1.Subscribe(multiplexer.GetMessagesAsync());

            // need to start the multiplexer before calling Messages

            using var cts = new CancellationTokenSource();

            // Act and Assert
            var multiplexerCompletion = multiplexer.RunAsync(cts.Token);
            var bufferCompletion      = buffer.RunAsync(cts.Token);

            cts.CancelAfter(TimeSpan.FromSeconds(3));

            await multiplexerCompletion.HandleCancellation();

            await Assert.ThrowsAnyAsync <OperationCanceledException>(() => bufferCompletion);

            await Patiently.AssertThatAsync(OutputHelper,
                                            () =>
            {
                messagesFromQueue.ShouldBe(expectedReceiveFromQueueCount);
                messagesDispatched.ShouldBe(0);

                return(true);
            });

            // Starting the consumer after the token is cancelled will not dispatch messages
            await Assert.ThrowsAnyAsync <OperationCanceledException>(() => consumer1.RunAsync(cts.Token));

            await Patiently.AssertThatAsync(OutputHelper,
                                            () =>
            {
                messagesFromQueue.ShouldBe(expectedReceiveFromQueueCount);
                messagesDispatched.ShouldBe(0);

                return(true);
            });
        }
Example #22
0
        public async Task HandleMessageFromQueueLogs_ShouldHaveContext(bool handlerShouldSucceed, LogLevel level, string status, string exceptionMessage)
        {
            var handler = new InspectableHandler <SimpleMessage>()
            {
                ShouldSucceed = handlerShouldSucceed,
            };

            if (exceptionMessage != null)
            {
                handler.OnHandle = msg => throw new Exception(exceptionMessage);
            }

            var services = GivenJustSaying(levelOverride: LogLevel.Information)
                           .ConfigureJustSaying(
                (builder) => builder.WithLoopbackQueue <SimpleMessage>(UniqueName)
                .Subscriptions(sub => sub.WithDefaults(sgb =>
                                                       sgb.WithDefaultConcurrencyLimit(10))))
                           .AddSingleton <IHandlerAsync <SimpleMessage> >(handler);

            var sp = services.BuildServiceProvider();

            var cts = new CancellationTokenSource();

            var publisher = sp.GetRequiredService <IMessagePublisher>();
            await publisher.StartAsync(cts.Token);

            await sp.GetRequiredService <IMessagingBus>().StartAsync(cts.Token);

            var message = new SimpleMessage();
            await publisher.PublishAsync(message, cts.Token);

            await Patiently.AssertThatAsync(() => handler.ReceivedMessages
                                            .ShouldHaveSingleItem()
                                            .Id.ShouldBe(message.Id));

            var testLogger = sp.GetRequiredService <ITestLoggerSink>();

            await Patiently.AssertThatAsync(() =>
            {
                var handleMessage = testLogger.LogEntries
                                    .SingleOrDefault(le => le.OriginalFormat == "{Status} handling message with Id '{MessageId}' of type {MessageType} in {TimeToHandle}ms.");

                handleMessage.ShouldNotBeNull();

                handleMessage.LogLevel.ShouldBe(level);
                handleMessage.Exception?.Message.ShouldBe(exceptionMessage);

                var propertyMap = new Dictionary <string, object>(handleMessage.Properties);
                propertyMap.ShouldContainKeyAndValue("Status", status);
                propertyMap.ShouldContainKeyAndValue("MessageId", message.Id);
                propertyMap.ShouldContainKeyAndValue("MessageType", message.GetType().FullName);
                propertyMap.ShouldContainKey("TimeToHandle");
            });

            cts.Cancel();
        }
        public async Task AllMessagesAreClearedFromQueue()
        {
            await Patiently.VerifyExpectationAsync(
                () => SerialisationRegister.Received(2).DeserializeMessage(
                    Arg.Any<string>()));

            await Patiently.VerifyExpectationAsync(
                () =>Sqs.Received().DeleteMessage(
                    Arg.Any<DeleteMessageRequest>()));
        }
        public async Task SqsPolicyWithAWildcardIsApplied()
        {
            var queue = new SqsQueueByName(Region, QueueName, Client, 0, TestFixture.LoggerFactory);

            await Patiently.AssertThatAsync(() => queue.ExistsAsync(), TimeSpan.FromSeconds(60));

            dynamic policyJson = JObject.Parse(queue.Policy);

            policyJson.Statement.Count.ShouldBe(1, $"Expecting 1 statement in Sqs policy but found {policyJson.Statement.Count}");
        }
Example #25
0
        public async Task Sqs_Client_Throwing_Exceptions_Continues_To_Request_Messages()
        {
            // Arrange
            int messagesRequested  = 0;
            int messagesDispatched = 0;

            IEnumerable <Message> GetMessages()
            {
                Interlocked.Increment(ref messagesRequested);
                throw new Exception();
            }

            var queue = new FakeSqsQueue(ct => Task.FromResult(GetMessages()));


            var queues = new List <ISqsQueue> {
                queue
            };
            IMessageDispatcher dispatcher =
                new FakeDispatcher(() =>
            {
                Interlocked.Increment(ref messagesDispatched);
            });

            var defaults = new SubscriptionGroupSettingsBuilder()
                           .WithDefaultConcurrencyLimit(8);
            var settings = new Dictionary <string, SubscriptionGroupConfigBuilder>
            {
                { "test", new SubscriptionGroupConfigBuilder("test").AddQueues(queues) },
            };

            var subscriptionGroupFactory = new SubscriptionGroupFactory(
                dispatcher,
                MessageMonitor,
                LoggerFactory);

            ISubscriptionGroup collection = subscriptionGroupFactory.Create(defaults, settings);

            var cts = new CancellationTokenSource();

            // Act
            var runTask = collection.RunAsync(cts.Token);

            await Patiently.AssertThatAsync(_outputHelper,
                                            () =>
            {
                messagesRequested.ShouldBeGreaterThan(1, $"but was {messagesRequested}");
                messagesDispatched.ShouldBe(0, $"but was {messagesDispatched}");
            });

            cts.Cancel();
            await runTask.HandleCancellation();
        }
Example #26
0
    public async Task CanSubscribeUsingQueueArn()
    {
        IAwsClientFactory clientFactory = CreateClientFactory();
        var sqsClient     = clientFactory.GetSqsClient(Region);
        var snsClient     = clientFactory.GetSnsClient(Region);
        var queueResponse = await sqsClient.CreateQueueAsync(UniqueName);

        var anotherUniqueName = $"{Guid.NewGuid():N}-integration-tests";
        var topicResponse     = await snsClient.CreateTopicAsync(anotherUniqueName);

        var subscriptionArn = await snsClient.SubscribeQueueAsync(topicResponse.TopicArn, sqsClient, queueResponse.QueueUrl);

        var queueArn = (await sqsClient.GetQueueAttributesAsync(queueResponse.QueueUrl, new List <string> {
            SQSConstants.ATTRIBUTE_QUEUE_ARN
        })).Attributes[SQSConstants.ATTRIBUTE_QUEUE_ARN];

        var handler = new InspectableHandler <SimpleMessage>();

        var services = GivenJustSaying()
                       .ConfigureJustSaying(builder =>
                                            builder
                                            .Subscriptions(c =>
                                                           c.ForQueueArn <SimpleMessage>(queueArn))
                                            .Publications(c =>
                                                          c.WithTopicArn <SimpleMessage>(topicResponse.TopicArn)
                                                          )
                                            )
                       .AddJustSayingHandlers(new[] { handler });

        string content = Guid.NewGuid().ToString();

        var message = new SimpleMessage
        {
            Content = content
        };

        await WhenAsync(
            services,
            async (publisher, listener, serviceProvider, cancellationToken) =>
        {
            await listener.StartAsync(cancellationToken);
            await publisher.StartAsync(cancellationToken);

            await publisher.PublishAsync(message, cancellationToken);

            // Assert
            await Patiently.AssertThatAsync(OutputHelper,
                                            () =>
            {
                handler.ReceivedMessages.ShouldHaveSingleItem().Content.ShouldBe(content);
            });
        });
    }
Example #27
0
        public async Task ThenItIsUsed()
        {
            // Arrange
            var handler  = new InspectableHandler <SimpleMessage>();
            var accessor = new RecordingMessageContextAccessor(new MessageContextAccessor());

            var subject         = Guid.NewGuid().ToString();
            var subjectProvider = new ConstantSubjectProvider(subject);

            var services = GivenJustSaying()
                           .ConfigureJustSaying((builder) =>
                                                builder.WithLoopbackTopic <SimpleMessage>(UniqueName))
                           .ConfigureJustSaying(builder =>
                                                builder.Services(s => s.WithMessageContextAccessor(() => accessor)))
                           .ConfigureJustSaying((builder) =>
                                                builder.Messaging(m =>
                                                                  m.WithMessageSubjectProvider(subjectProvider)))
                           .AddSingleton <IHandlerAsync <SimpleMessage> >(handler);

            var id      = Guid.NewGuid();
            var message = new SimpleMessage()
            {
                Id = id
            };

            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));

            await WhenAsync(
                services,
                async (publisher, listener, cancellationToken) =>
            {
                await listener.StartAsync(cancellationToken);
                await publisher.StartAsync(cancellationToken);

                // Let's send an OrderPlaced, but the subject will be a GUID
                // because of the custom subject provider
                await publisher.PublishAsync(message, cancellationToken);

                await Patiently.AssertThatAsync(OutputHelper,
                                                () =>
                {
                    var receivedMessage = handler.ReceivedMessages.ShouldHaveSingleItem();
                    receivedMessage.Id.ShouldBe(id);

                    var context    = accessor.ValuesWritten.ShouldHaveSingleItem();
                    dynamic json   = JsonConvert.DeserializeObject(context.Message.Body);
                    string subject = json.Subject;
                    subject.ShouldBe(subject);
                });
            });
        }
        protected override async Task WhenAsync()
        {
            MiddlewareMap.Add <SimpleMessage>(_queue.QueueName, Middleware);

            var cts = new CancellationTokenSource();

            var completion = SystemUnderTest.RunAsync(cts.Token);

            await Patiently.AssertThatAsync(OutputHelper,
                                            () => Handler.ReceivedMessages.Any());

            cts.Cancel();
            await Assert.ThrowsAnyAsync <OperationCanceledException>(() => completion);
        }
        public async Task Add_Different_Handler_Per_Queue()
        {
            // Arrange
            string group1     = "group1";
            string group2     = "group2";
            string queueName1 = "queue1";
            string queueName2 = "queue2";

            JustSaying.JustSayingBus bus = CreateBus();

            var handler1 = new InspectableHandler <TestJustSayingMessage>();
            var handler2 = new InspectableHandler <TestJustSayingMessage>();

            bus.AddMessageHandler(queueName1, () => handler1);
            bus.AddMessageHandler(queueName2, () => handler2);

            ISqsQueue queue1 = TestQueue(bus.SerializationRegister, queueName1);
            ISqsQueue queue2 = TestQueue(bus.SerializationRegister, queueName2);

            bus.AddQueue(group1, queue1);
            bus.AddQueue(group2, queue2);

            using var cts = new CancellationTokenSource();

            // Act
            await bus.StartAsync(cts.Token);

            await Patiently.AssertThatAsync(_outputHelper,
                                            () =>
            {
                handler1.ReceivedMessages.Count.ShouldBeGreaterThan(0);
                handler2.ReceivedMessages.Count.ShouldBeGreaterThan(0);
            });

            cts.Cancel();
            await bus.Completion;

            foreach (var message in handler1.ReceivedMessages)
            {
                message.QueueName.ShouldBe(queueName1);
            }

            foreach (var message in handler2.ReceivedMessages)
            {
                message.QueueName.ShouldBe(queueName2);
            }

            bus.Dispose();
        }
Example #30
0
    public async Task Then_The_Message_Is_Handled()
    {
        // Arrange
        var handler = new InspectableHandler <SimpleMessage>();

        var services = GivenJustSaying()
                       .ConfigureJustSaying((builder) =>
                                            builder
                                            .Publications((options) =>
                                                          options.WithTopic <SimpleMessage>(configure => { configure.WithName("my-special-topic"); }))
                                            .Subscriptions((options) =>
                                                           options.ForTopic <SimpleMessage>("my-special-topic",
                                                                                            subscriptionBuilder => { subscriptionBuilder.WithName(UniqueName); })))
                       .AddSingleton <IHandlerAsync <SimpleMessage> >(handler);

        string content = Guid.NewGuid().ToString();

        var message = new SimpleMessage()
        {
            Content = content
        };

        string json = "";

        await WhenAsync(
            services,
            async (publisher, listener, cancellationToken) =>
        {
            await listener.StartAsync(cancellationToken);
            await publisher.StartAsync(cancellationToken);

            var listenerJson  = JsonConvert.SerializeObject(listener.Interrogate(), Formatting.Indented);
            var publisherJson = JsonConvert.SerializeObject(publisher.Interrogate(), Formatting.Indented);

            await publisher.PublishAsync(message, cancellationToken);

            json = string.Join($"{Environment.NewLine}{Environment.NewLine}",
                               listenerJson,
                               publisherJson)
                   .Replace(UniqueName, "integrationTestQueueName", StringComparison.Ordinal);

            await Patiently.AssertThatAsync(OutputHelper,
                                            () =>
                                            handler.ReceivedMessages.Any(x => x.Content == content).ShouldBeTrue());
        });

        json.ShouldMatchApproved(opt => opt.SubFolder("Approvals"));
    }