예제 #1
0
        public async Task HandleErrorAsync_Whatever_ConsumerRolledBackAndTransactionAborted()
        {
            var policy   = new RetryErrorPolicy().MaxFailedAttempts(3).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var transactionManager = Substitute.For <IConsumerTransactionManager>();

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(
                    envelope,
                    _serviceProvider,
                    transactionManager),
                new InvalidOperationException("test"));

            await transactionManager.Received(1).RollbackAsync(
                Arg.Any <InvalidOperationException>(),
                false,
                true,
                false);
        }
        public async Task HandleAsync_ThrowException_ExceptionIsThrown()
        {
            var message = new TestValidationMessage
            {
                Id = "1", String10 = "123456789abc", IntRange = 5, NumbersOnly = "123"
            };
            var expectedMessage =
                $"The message is not valid:{Environment.NewLine}- The field String10 must be a string with a maximum length of 10.";
            var endpoint = TestConsumerEndpoint.GetDefault();

            endpoint.MessageValidationMode = MessageValidationMode.ThrowException;

            var envelope = new InboundEnvelope(
                message,
                null,
                null,
                new TestOffset(),
                endpoint,
                "source-endpoint");

            IRawInboundEnvelope?result = null;
            Func <Task>         act    = () => new ValidatorConsumerBehavior(_inboundLogger).HandleAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                context =>
            {
                result = context.Envelope;
                return(Task.CompletedTask);
            });

            await act.Should().ThrowAsync <MessageValidationException>().WithMessage(expectedMessage);

            result.Should().BeNull();
        }
        public void CanHandle_Sequence_FalseReturned()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                new TestConsumerEndpoint("test")
            {
                Batch = new BatchSettings
                {
                    Size = 10
                }
            },
                TestConsumerEndpoint.GetDefault().Name);

            var context = ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider);

            context.SetSequence(new BatchSequence("batch", context), false);

            var result = policy.CanHandle(
                context,
                new InvalidOperationException("test"));

            result.Should().BeFalse();
        }
        public async Task HandleAsync_ValidMessage_NoLogAndNoException(MessageValidationMode validationMode)
        {
            var message = new TestValidationMessage
            {
                Id = "1", String10 = "123", IntRange = 5, NumbersOnly = "123"
            };
            var endpoint = TestConsumerEndpoint.GetDefault();

            endpoint.MessageValidationMode = validationMode;

            var envelope = new InboundEnvelope(
                message,
                null,
                null,
                new TestOffset(),
                endpoint,
                "source-endpoint");

            IRawInboundEnvelope?result = null;
            Func <Task>         act    = () => new ValidatorConsumerBehavior(_inboundLogger).HandleAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                context =>
            {
                result = context.Envelope;
                return(Task.CompletedTask);
            });
            await act.Should().NotThrowAsync <ValidationException>();

            result.Should().NotBeNull();
            _loggerSubstitute.DidNotReceive(LogLevel.Warning, null).Should().BeTrue();
        }
        public void CanHandle_Whatever_TrueReturned(int failedAttempts)
        {
            var rawMessage = new MemoryStream();
            var headers    = new[]
            {
                new MessageHeader(
                    DefaultMessageHeaders.FailedAttempts,
                    failedAttempts.ToString(CultureInfo.InvariantCulture))
            };

            var testPolicy = new TestErrorPolicy();

            var chain = new ErrorPolicyChain(
                new RetryErrorPolicy().MaxFailedAttempts(3),
                testPolicy)
                        .Build(_serviceProvider);

            var result = chain.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(
                    new InboundEnvelope(
                        rawMessage,
                        headers,
                        new TestOffset(),
                        TestConsumerEndpoint.GetDefault(),
                        TestConsumerEndpoint.GetDefault().Name)),
                new InvalidOperationException("test"));

            result.Should().BeTrue();
        }
        public async Task HandleAsync_LogWarning_WarningIsLogged(
            IIntegrationMessage message,
            string expectedValidationMessage)
        {
            var endpoint = TestConsumerEndpoint.GetDefault();

            endpoint.MessageValidationMode = MessageValidationMode.LogWarning;

            var envelope = new InboundEnvelope(
                message,
                null,
                null,
                new TestOffset(),
                endpoint,
                "source-endpoint");

            IRawInboundEnvelope?result = null;

            await new ValidatorConsumerBehavior(_inboundLogger).HandleAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                context =>
            {
                result = context.Envelope;
                return(Task.CompletedTask);
            });

            result.Should().NotBeNull();
            _loggerSubstitute.Received(LogLevel.Warning, null, expectedValidationMessage, 1080);
        }
예제 #7
0
        public void CanHandle_WithMaxFailedAttempts_ExpectedResultReturned(
            int failedAttempts,
            bool expectedResult)
        {
            var envelope = new InboundEnvelope(
                new MemoryStream(),
                new[]
                {
                    new MessageHeader(
                        DefaultMessageHeaders.FailedAttempts,
                        failedAttempts.ToString(CultureInfo.InvariantCulture))
                },
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var policy = new TestErrorPolicy()
                .MaxFailedAttempts(3)
                .Build(Substitute.For<IServiceProvider>());

            var canHandle = policy.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope),
                new InvalidOperationException());

            canHandle.Should().Be(expectedResult);
        }
        public async Task Transform_SingleMessage_HeadersProperlyModified()
        {
            var policy = ErrorPolicy
                         .Move(TestProducerEndpoint.GetDefault())
                         .Transform((outboundEnvelope, ex) => { outboundEnvelope.Headers.Add("error", ex.GetType().Name); })
                         .Build(_serviceProvider);

            var envelope = new InboundEnvelope(
                new MemoryStream(Encoding.UTF8.GetBytes("hey oh!")),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            envelope.Headers.Add("key", "value");

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            var producer   = (TestProducer)_broker.GetProducer(TestProducerEndpoint.GetDefault());
            var newHeaders = producer.ProducedMessages[0].Headers;

            newHeaders.Should().HaveCount(6); // message-id, message-type, key, traceid, error, source-endpoint
        }
예제 #9
0
        public void CanHandle_WithDifferentFailedAttemptsCount_ReturnReflectsMaxFailedAttempts(
            int failedAttempts,
            bool expectedResult)
        {
            var policy = ErrorPolicy.Retry().MaxFailedAttempts(3).Build(_serviceProvider);

            var rawMessage = new MemoryStream();
            var headers    = new[]
            {
                new MessageHeader(DefaultMessageHeaders.FailedAttempts, failedAttempts)
            };

            var envelope = new InboundEnvelope(
                rawMessage,
                headers,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var canHandle = policy.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            canHandle.Should().Be(expectedResult);
        }
예제 #10
0
        public async Task HandleError_WithPublish_MessagePublished()
        {
            var publisher       = Substitute.For <IPublisher>();
            var serviceProvider = new ServiceCollection().AddScoped(_ => publisher)
                                  .BuildServiceProvider(new ServiceProviderOptions {
                ValidateScopes = true
            });

            var policy = new TestErrorPolicy()
                         .Publish(_ => new TestEventTwo {
                Content = "aaa"
            })
                         .Build(serviceProvider);

            var envelope = new InboundEnvelope(
                new MemoryStream(),
                new[] { new MessageHeader(DefaultMessageHeaders.FailedAttempts, "3") },
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, serviceProvider),
                new ArgumentNullException());

            await publisher.Received().PublishAsync(Arg.Any <TestEventTwo>());
        }
        public async Task HandleErrorAsync_WithTransform_MessageTranslated()
        {
            var policy = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault())
                         .Transform((originalEnvelope, _) => { originalEnvelope.Message = new TestEventTwo(); })
                         .Build(_serviceProvider);

            var rawMessage = new MemoryStream(Encoding.UTF8.GetBytes("hey oh!"));

            var headers = new[]
            {
                new MessageHeader(DefaultMessageHeaders.MessageType, typeof(string).AssemblyQualifiedName)
            };

            var envelope = new InboundEnvelope(
                rawMessage,
                headers,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            var producer = (TestProducer)_broker.GetProducer(TestProducerEndpoint.GetDefault());

            var(producedMessage, _) = await producer.Endpoint.Serializer.DeserializeAsync(
                new MemoryStream(producer.ProducedMessages[0].Message !),
                producer.ProducedMessages[0].Headers,
                MessageSerializationContext.Empty);

            producedMessage.Should().BeOfType <TestEventTwo>();
        }
예제 #12
0
        public async Task HandleErrorAsync_RetryWithMaxFailedAttempts_AppliedAccordingToMaxFailedAttempts(int failedAttempts)
        {
            var rawMessage = new MemoryStream();
            var headers    = new[]
            {
                new MessageHeader(
                    DefaultMessageHeaders.FailedAttempts,
                    failedAttempts.ToString(CultureInfo.InvariantCulture))
            };

            var testPolicy = new TestErrorPolicy();

            var chain = new ErrorPolicyChain(
                new[]
            {
                new RetryErrorPolicy().MaxFailedAttempts(3),
                testPolicy
            })
                        .Build(_serviceProvider);

            await chain.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(
                    new InboundEnvelope(
                        rawMessage,
                        headers,
                        new TestOffset(),
                        TestConsumerEndpoint.GetDefault(),
                        TestConsumerEndpoint.GetDefault().Name)),
                new InvalidOperationException("test"));

            testPolicy.Applied.Should().Be(failedAttempts > 3);
        }
예제 #13
0
        public void LogSkippingIncompleteSequence_Logged()
        {
            var expectedMessage = "Skipping the incomplete sequence 'fake1'. The first message is missing.";

            _silverbackLogger.LogSkippingIncompleteSequence(
                new IncompleteSequence("fake1", ConsumerPipelineContextHelper.CreateSubstitute()));

            _loggerSubstitute.Received(LogLevel.Warning, null, expectedMessage, 1009);
        }
        public async Task AddAsync_NewSequence_SequenceAddedAndReturned()
        {
            var store   = new DefaultSequenceStore(new IntegrationLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            var newSequence = new ChunkSequence("abc", 10, context);
            var result      = await store.AddAsync(newSequence);

            result.Should().BeSameAs(newSequence);
            (await store.GetAsync <ChunkSequence>("abc")).Should().BeSameAs(newSequence);
        }
            public FakeSequence(string sequenceId, bool isComplete, bool isAborted, ISequenceStore store)
                : base(sequenceId, ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store))
            {
                if (isComplete)
                {
                    CompleteAsync().Wait();
                }

                if (isAborted)
                {
                    AbortAsync(SequenceAbortReason.EnumerationAborted).Wait();
                }
            }
        public async Task AddAsyncAndGetAsync_Sequence_IsNewFlagAutomaticallyHandled()
        {
            var store   = new DefaultSequenceStore(new IntegrationLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            var sequence = await store.AddAsync(new ChunkSequence("abc", 10, context));

            sequence.IsNew.Should().BeTrue();

            sequence = (await store.GetAsync <ChunkSequence>("abc")) !;

            sequence !.IsNew.Should().BeFalse();
        }
        public async Task AddAsync_ExistingSequence_SequenceAbortedAndReplaced()
        {
            var store   = new DefaultSequenceStore(new IntegrationLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            var originalSequence = new ChunkSequence("abc", 10, context);
            await store.AddAsync(originalSequence);

            var newSequence = new ChunkSequence("abc", 10, context);
            await store.AddAsync(newSequence);

            originalSequence.IsAborted.Should().BeTrue();

            (await store.GetAsync <ChunkSequence>("abc")).Should().BeSameAs(newSequence);
        }
        public async Task GetAsync_NotExistingSequence_NullReturned()
        {
            var store   = new DefaultSequenceStore(new IntegrationLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            await store.AddAsync(new ChunkSequence("aaa", 10, context));

            await store.AddAsync(new ChunkSequence("bbb", 10, context));

            await store.AddAsync(new ChunkSequence("ccc", 10, context));

            var result = await store.GetAsync <ChunkSequence>("123");

            result.Should().BeNull();
        }
        public async Task GetSequence_ChunkForExistingSequence_SequenceReturned()
        {
            var envelope1 = new RawInboundEnvelope(
                new byte[] { 0x01, 0x02, 0x03 },
                new MessageHeaderCollection
            {
                { DefaultMessageHeaders.MessageId, "123" },
                { DefaultMessageHeaders.ChunkIndex, "0" },
                { DefaultMessageHeaders.ChunksCount, "4" }
            },
                new TestConsumerEndpoint("test"),
                "test",
                new TestOffset());
            var envelope2 = new RawInboundEnvelope(
                new byte[] { 0x04, 0x05, 0x06 },
                new MessageHeaderCollection
            {
                { DefaultMessageHeaders.MessageId, "123" },
                { DefaultMessageHeaders.ChunkIndex, "1" },
                { DefaultMessageHeaders.ChunksCount, "4" }
            },
                new TestConsumerEndpoint("test"),
                "test",
                new TestOffset());

            var reader = new ChunkSequenceReader();

            var context1 = ConsumerPipelineContextHelper.CreateSubstitute(
                envelope1,
                sequenceStore: _defaultSequenceStore);

            var sequence1 = await reader.GetSequenceAsync(context1);

            sequence1.Should().NotBeNull();
            sequence1.Should().BeOfType <ChunkSequence>();
            sequence1 !.TotalLength.Should().Be(4);
            sequence1.IsNew.Should().BeTrue();

            var context2 = ConsumerPipelineContextHelper.CreateSubstitute(
                envelope2,
                sequenceStore: _defaultSequenceStore);

            var sequence2 = await reader.GetSequenceAsync(context2);

            sequence2.Should().NotBeNull();
            sequence2.Should().BeSameAs(sequence1);
            sequence2 !.IsNew.Should().BeFalse();
        }
예제 #20
0
        public SilverbackIntegrationLoggerBenchmark()
        {
            _integrationLogger = new SilverbackIntegrationLogger(
                new FakeLogger(),
                new LogTemplates().ConfigureAdditionalData <TestConsumerEndpoint>("offset"));

            _singleMessageContext = ConsumerPipelineContextHelper.CreateSubstitute(
                new RawInboundEnvelope(
                    Array.Empty <byte>(),
                    new MessageHeaderCollection
            {
                new MessageHeader("Test", "Test"),
                new MessageHeader(DefaultMessageHeaders.FailedAttempts, 1),
                new MessageHeader(DefaultMessageHeaders.MessageType, "Something.Xy"),
                new MessageHeader(DefaultMessageHeaders.MessageId, "1234"),
            },
                    new TestConsumerEndpoint("Test"),
                    "Test",
                    new TestOffset("abc", "1"),
                    new Dictionary <string, string>
            {
                ["offset"] = "1@42"
            }));

            _sequenceContext = ConsumerPipelineContextHelper.CreateSubstitute(
                new RawInboundEnvelope(
                    Array.Empty <byte>(),
                    new MessageHeaderCollection
            {
                new MessageHeader("Test", "Test"),
                new MessageHeader(DefaultMessageHeaders.FailedAttempts, 1),
                new MessageHeader(DefaultMessageHeaders.MessageType, "Something.Xy"),
                new MessageHeader(DefaultMessageHeaders.MessageId, "5678"),
                new MessageHeader(DefaultMessageHeaders.BatchId, "1234"),
                new MessageHeader(DefaultMessageHeaders.BatchSize, "11"),
            },
                    new TestConsumerEndpoint("Test"),
                    "Test",
                    new TestOffset("abc", "2"),
                    new Dictionary <string, string>
            {
                ["offset"] = "1@43"
            }));
            var sequence = new BatchSequence("123", _sequenceContext);

            sequence.AddAsync(_sequenceContext.Envelope, null, false);
            _sequenceContext.SetSequence(sequence, true);
        }
        public async Task Remove_NotExistingSequence_NoExceptionThrown()
        {
            var store   = new DefaultSequenceStore(new IntegrationLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            await store.AddAsync(new ChunkSequence("aaa", 10, context));

            await store.AddAsync(new ChunkSequence("bbb", 10, context));

            await store.AddAsync(new ChunkSequence("ccc", 10, context));

            await store.RemoveAsync("123");

            (await store.GetAsync <ChunkSequence>("aaa")).Should().NotBeNull();
            (await store.GetAsync <ChunkSequence>("bbb")).Should().NotBeNull();
            (await store.GetAsync <ChunkSequence>("ccc")).Should().NotBeNull();
        }
예제 #22
0
        public async Task Remove_ExistingSequence_SequenceRemoved()
        {
            var store   = new DefaultSequenceStore(new SilverbackLoggerSubstitute <DefaultSequenceStore>());
            var context = ConsumerPipelineContextHelper.CreateSubstitute(sequenceStore: store);

            await store.AddAsync(new ChunkSequence("aaa", 10, context));

            await store.AddAsync(new ChunkSequence("bbb", 10, context));

            await store.AddAsync(new ChunkSequence("ccc", 10, context));

            await store.RemoveAsync("bbb");

            (await store.GetAsync <ChunkSequence>("bbb")).Should().BeNull();
            (await store.GetAsync <ChunkSequence>("aaa")).Should().NotBeNull();
            (await store.GetAsync <ChunkSequence>("ccc")).Should().NotBeNull();
        }
        public void CanHandle_SingleMessage_TrueReturned()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var result = policy.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            result.Should().BeTrue();
        }
        public async Task HandleErrorAsync_SingleMessage_TrueReturned()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(Encoding.UTF8.GetBytes("hey oh!")),
                null,
                new TestOffset(),
                new TestConsumerEndpoint("source-endpoint"),
                "source-endpoint");

            var result = await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            result.Should().BeTrue();
        }
        public void CanHandle_Whatever_TrueReturned()
        {
            var policy   = new StopConsumerErrorPolicy().Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var canHandle = policy.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            canHandle.Should().BeTrue();
        }
        public async Task HandleErrorAsync_Whatever_FalseReturned()
        {
            var policy   = new StopConsumerErrorPolicy().Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            var result = await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            result.Should().BeFalse();
        }
예제 #27
0
        public void CanHandle_WithApplyWhen_ExpectedResultReturned(
            IInboundEnvelope envelope,
            Exception exception,
            bool mustApply)
        {
            var policy = new TestErrorPolicy()
                         .ApplyWhen(
                (msg, ex) =>
                msg.Headers.GetValue <int>(DefaultMessageHeaders.FailedAttempts) <= 5 && ex.Message != "no")
                         .Build(Substitute.For <IServiceProvider>());

            var canHandle = policy.CanHandle(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope),
                exception);

            canHandle.Should().Be(mustApply);
        }
        public async Task HandleErrorAsync_Whatever_ConsumerCommittedButTransactionAborted()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(Encoding.UTF8.GetBytes("hey oh!")),
                null,
                new TestOffset(),
                new TestConsumerEndpoint("source-endpoint"),
                "source-endpoint");

            var transactionManager = Substitute.For <IConsumerTransactionManager>();

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider, transactionManager),
                new InvalidOperationException("test"));

            await transactionManager.Received(1).RollbackAsync(Arg.Any <InvalidOperationException>(), true);
        }
        public async Task HandleErrorAsync_NotDeserializedInboundMessage_MessagePreserved()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                new MemoryStream(Encoding.UTF8.GetBytes("hey oh!")),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            var producer        = (TestProducer)_broker.GetProducer(TestProducerEndpoint.GetDefault());
            var producedMessage = producer.ProducedMessages.Last();

            producedMessage.Message.Should().BeEquivalentTo(producedMessage.Message);
        }
        public async Task HandleErrorAsync_InboundMessage_MessageMoved()
        {
            var policy   = new MoveMessageErrorPolicy(TestProducerEndpoint.GetDefault()).Build(_serviceProvider);
            var envelope = new InboundEnvelope(
                "hey oh!",
                new MemoryStream(),
                null,
                new TestOffset(),
                TestConsumerEndpoint.GetDefault(),
                TestConsumerEndpoint.GetDefault().Name);

            await policy.HandleErrorAsync(
                ConsumerPipelineContextHelper.CreateSubstitute(envelope, _serviceProvider),
                new InvalidOperationException("test"));

            var producer = (TestProducer)_broker.GetProducer(TestProducerEndpoint.GetDefault());

            producer.ProducedMessages.Should().HaveCount(1);
        }