public async Task Should_pass_message_and_headers_to_partition_key_extractor()
        {
            object capturedMessageInstanceFromPartionKeyExtractor = null;
            IReadOnlyDictionary <string, string> capturedHeadersFromPartionKeyExtractor = null;
            var partitionKeyExtractor = new PartitionKeyExtractor(
                (object msg, IReadOnlyDictionary <string, string> headers, out PartitionKey? partitionKey) =>
            {
                partitionKey = null;
                capturedMessageInstanceFromPartionKeyExtractor = msg;
                capturedHeadersFromPartionKeyExtractor         = headers;
                return(true);
            });

            var behavior = new TransactionInformationBeforeTheLogicalOutboxBehavior(partitionKeyExtractor, new ContainerInformationExtractor());

            var messageHeaders = new Dictionary <string, string> {
                { "HeaderKey", "HeaderValue" }
            };
            var messageInstance = new object();
            var context         = new TestableIncomingLogicalMessageContext
            {
                MessageHeaders = messageHeaders,
                Message        = new LogicalMessage(new MessageMetadata(typeof(object)), messageInstance)
            };

            await behavior.Invoke(context, _ => Task.CompletedTask);

            Assert.That(capturedMessageInstanceFromPartionKeyExtractor, Is.Not.Null.And.EqualTo(messageInstance));
            Assert.That(capturedHeadersFromPartionKeyExtractor, Is.Not.Null.And.EqualTo(messageHeaders));
        }
        public UnitOfWorkBehaviorTestsFixture()
        {
            UnitsOfWork = new List <Mock <IUnitOfWork> >
            {
                new Mock <IUnitOfWork>(),
                new Mock <IUnitOfWork>(),
                new Mock <IUnitOfWork>()
            };

            UnitOfWorkBehavior = new UnitOfWorkBehavior();
            Builder            = new FakeBuilder();
            Context            = new TestableIncomingLogicalMessageContext {
                Builder = Builder
            };
            NextTask = new Mock <Func <Task> >();

            Builder.Register(UnitsOfWork.Select(u => u.Object).Concat(new[] { new NServiceBus.Features.ClientOutbox.Pipeline.UnitOfWork(null, null, null, null) }).ToArray());

            NextTask.Setup(n => n()).Returns(Task.CompletedTask).Callback(() =>
            {
                if (CommittedUnitsOfWork > 0)
                {
                    throw new Exception("Next invoked too late");
                }
            });

            UnitsOfWork.ForEach(u => u.Setup(u2 => u2.CommitAsync(It.IsAny <Func <Task> >())).Returns <Func <Task> >(t => { CommittedUnitsOfWork++; return(t()); }));
        }
예제 #3
0
            public override Task Invoke(IIncomingPhysicalMessageContext context, Func <IIncomingLogicalMessageContext, Task> stage)
            {
                context.PrintInstanceWithRunSpecificIfPossible(instance, writer);

                var logicalMessageContext = new TestableIncomingLogicalMessageContext();

                logicalMessageContext.Extensions.Merge(context.Extensions);

                return(stage(logicalMessageContext));
            }
        public void Should_throw_when_there_are_no_registered_message_handlers()
        {
            var behavior = new LoadHandlersConnector(new MessageHandlerRegistry(new Conventions()), new InMemorySynchronizedStorage(), new InMemoryTransactionalSynchronizedStorageAdapter());

            var context = new TestableIncomingLogicalMessageContext();

            context.Extensions.Set<OutboxTransaction>(new InMemoryOutboxTransaction());
            context.Extensions.Set(new TransportTransaction());

            Assert.That(async () => await behavior.Invoke(context, c => TaskEx.CompletedTask), Throws.InvalidOperationException);
        }
예제 #5
0
        public async Task ShouldProcessMessage()
        {
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <Messages.IEvent>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened();
        }
        public void Should_throw_when_there_are_no_registered_message_handlers()
        {
            var behavior = new LoadHandlersConnector(new MessageHandlerRegistry(), new InMemorySynchronizedStorage(), new InMemoryTransactionalSynchronizedStorageAdapter());

            var context = new TestableIncomingLogicalMessageContext();

            context.Extensions.Set <OutboxTransaction>(new InMemoryOutboxTransaction());
            context.Extensions.Set(new TransportTransaction());

            Assert.That(async() => await behavior.Invoke(context, c => Task.CompletedTask), Throws.InvalidOperationException);
        }
예제 #7
0
        public async Task When_processing_message_without_enclosed_message_type_header_it_is_addedAsync()
        {
            var behavior = new InferredMessageTypeEnricherBehavior();
            var context  = new TestableIncomingLogicalMessageContext();

            Assert.IsFalse(context.Headers.ContainsKey(Headers.EnclosedMessageTypes));

            await behavior.Invoke(context, messageContext => Task.CompletedTask);

            Assert.IsTrue(context.Headers.ContainsKey(Headers.EnclosedMessageTypes));
            Assert.AreEqual(context.Headers[Headers.EnclosedMessageTypes], typeof(object).FullName);
        }
예제 #8
0
    public Task IncomingLogicalMessageContext()
    {
        var context = new TestableIncomingLogicalMessageContext
        {
            Message = BuildLogicalMessage(),
            Headers = new Dictionary <string, string> {
                { "Key", "Value" }
            }
        };

        return(Verify(context));
    }
예제 #9
0
        public async Task When_processing_message_with_enclosed_message_type_header_it_is_not_changedAsync()
        {
            var mutator = new InferredMessageTypeEnricherBehavior();
            var context = new TestableIncomingLogicalMessageContext();

            context.Headers.Add(Headers.EnclosedMessageTypes, typeof(string).FullName);

            await mutator.Invoke(context, messageContext => Task.CompletedTask);

            Assert.IsTrue(context.Headers.ContainsKey(Headers.EnclosedMessageTypes));
            Assert.AreEqual(context.Headers[Headers.EnclosedMessageTypes], typeof(string).FullName);
        }
        public async Task ShouldUnpackLocalDelivery()
        {
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.Extensions.Set(Defaults.LocalHeader, Fake <IFullMessage>());
            context.UpdateMessageInstance(Fake <IFullMessage>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened();
        }
        public void Below_v4_3_0_should_return_value_for_all_intents(string nsbVersion, MessageIntentEnum intent)
        {
            var correlationId = new Guid().ToString();
            var lookup = new RequestResponseStateLookup();
            lookup.RegisterState(correlationId, new RequestResponseStateLookup.State());
            var message = new IncomingMessageFromLegacyEndpoint(nsbVersion, intent);
            var incomingContext = new TestableIncomingLogicalMessageContext();
            incomingContext.MessageHeaders.Add(Headers.CorrelationId, correlationId);

            var result = incomingContext.TryRemoveResponseStateBasedOnCorrelationId(message, lookup);

            Assert.IsTrue(result.HasValue);
        }
예제 #12
0
        public async Task ShouldNotAcceptIfNoResponseRequested()
        {
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <ICommand>());
            context.MessageHeaders[Defaults.RequestResponse] = "0";

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened();
            context.RepliedMessages.Should().BeEmpty();
        }
        public async Task Should_not_call_MutateIncoming_when_hasIncomingMessageMutators_is_false()
        {
            var behavior = new MutateIncomingMessageBehavior(hasIncomingMessageMutators: false);

            var context = new TestableIncomingLogicalMessageContext();

            var mutator = new MutatorThatIndicatesIfItWasCalled();
            context.Builder.Register<IMutateIncomingMessages>(() => mutator);

            await behavior.Invoke(context, ctx => TaskEx.CompletedTask);

            Assert.IsFalse(mutator.MutateIncomingCalled);
        }
        public async Task Should_not_call_MutateIncoming_when_hasIncomingMessageMutators_is_false()
        {
            var behavior = new MutateIncomingMessageBehavior(hasIncomingMessageMutators: false);

            var context = new TestableIncomingLogicalMessageContext();

            var mutator = new MutatorThatIndicatesIfItWasCalled();

            context.Builder.Register <IMutateIncomingMessages>(() => mutator);

            await behavior.Invoke(context, ctx => TaskEx.CompletedTask);

            Assert.IsFalse(mutator.MutateIncomingCalled);
        }
예제 #15
0
        public async Task ShouldReplyToCommand()
        {
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <ICommand>());
            context.MessageHeaders[Defaults.RequestResponse] = "1";
            context.Builder.Register <Action <Accept> >(A.Fake <Action <Accept> >());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened();
            context.RepliedMessages.Should().NotBeEmpty();
            context.RepliedMessages[0].Message.Should().BeAssignableTo <Accept>();
        }
        public void Below_v5_0_0_should_return_value_for_all_intents(string nsbVersion, MessageIntentEnum intent)
        {
            var correlationId = new Guid().ToString();
            var lookup        = new RequestResponseStateLookup();

            lookup.RegisterState(correlationId, new RequestResponseStateLookup.State());
            var message         = new IncomingMessageFromLegacyEndpoint(nsbVersion, intent);
            var incomingContext = new TestableIncomingLogicalMessageContext();

            incomingContext.MessageHeaders.Add(Headers.CorrelationId, correlationId);

            var result = incomingContext.TryRemoveResponseStateBasedOnCorrelationId(message, lookup);

            Assert.IsTrue(result.HasValue);
        }
        public async Task ShouldUnpackBulkMessage()
        {
            var message = new Internal.BulkMessage
            {
                Messages = Many <IFullMessage>()
            };
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(message);

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened(3, Times.Exactly);
        }
        public void Should_throw_friendly_exception_when_IMutateIncomingMessages_MutateIncoming_returns_null()
        {
            var behavior = new MutateIncomingMessageBehavior(hasIncomingMessageMutators: true);

            var logicalMessage = new LogicalMessage(new MessageMetadata(typeof(TestMessage)), new TestMessage());

            var context = new TestableIncomingLogicalMessageContext
            {
                Message = logicalMessage
            };

            context.Builder.Register<IMutateIncomingMessages>(() => new MutateIncomingMessagesReturnsNull());

            Assert.That(async () => await behavior.Invoke(context, ctx => TaskEx.CompletedTask), Throws.Exception.With.Message.EqualTo("Return a Task or mark the method as async."));
        }
        public async Task Shares_state_with_pipeline_context()
        {
            var pipelineContext = new TestableIncomingLogicalMessageContext();
            var uniformSession  = new TestableUniformSession(pipelineContext);
            var behavior        = new SendingBehavior(uniformSession);

            await behavior.Invoke(pipelineContext, () => Task.CompletedTask);

            Assert.AreEqual(2, uniformSession.PublishedMessages.Length);
            Assert.AreEqual(2, uniformSession.SentMessages.Length);
            Assert.AreEqual(2, pipelineContext.PublishedMessages.Length);
            Assert.AreEqual(2, pipelineContext.SentMessages.Length);

            Assert.AreEqual("testValue", pipelineContext.Headers["testHeader"]);
        }
        public void Should_throw_friendly_exception_when_IMutateIncomingMessages_MutateIncoming_returns_null()
        {
            var behavior = new MutateIncomingMessageBehavior();

            var logicalMessage = new LogicalMessage(new MessageMetadata(typeof(TestMessage)), new TestMessage());

            var context = new TestableIncomingLogicalMessageContext
            {
                Message = logicalMessage
            };

            context.Builder.Register <IMutateIncomingMessages>(() => new MutateIncomingMessagesReturnsNull());

            Assert.That(async() => await behavior.Invoke(context, ctx => TaskEx.CompletedTask), Throws.Exception.With.Message.EqualTo("Return a Task or mark the method as async."));
        }
예제 #21
0
        public void SetUp()
        {
            logicalContext = new TestableIncomingLogicalMessageContext();
            scheduler      = new DefaultScheduler();
            behavior       = new ScheduledTaskHandlingBehavior(scheduler);

            var task = new TaskDefinition
            {
                Every = TimeSpan.FromSeconds(5),
                Task  = c => Task.CompletedTask
            };

            taskId = task.Id;
            scheduler.Schedule(task);
        }
        public async Task Should_clear_added_pending_operations_and_restore_ones_from_outbox_record()
        {
            var messageId = Guid.NewGuid().ToString();

            var transportOperations = new[]
            {
                new TransportOperation(
                    messageId: "42",
                    properties: new DispatchProperties {
                    { "Destination", "somewhere" }
                },
                    body: Array.Empty <byte>(),
                    headers: new Dictionary <string, string>()),
            };

            var fakeCosmosClient = new FakeCosmosClient(new FakeContainer
            {
                ReadItemStreamOutboxRecord = (id, key) => new OutboxRecord
                {
                    Dispatched          = false,
                    Id                  = messageId,
                    TransportOperations = transportOperations.Select(op => new StorageTransportOperation(op))
                                          .ToArray()
                }
            });

            var containerHolderHolderResolver = new ContainerHolderResolver(new FakeProvider(fakeCosmosClient),
                                                                            new ContainerInformation("fakeContainer", new PartitionKeyPath("")), "fakeDatabase");

            var behavior = new OutboxBehavior(containerHolderHolderResolver, new JsonSerializer());

            var testableContext = new TestableIncomingLogicalMessageContext();

            testableContext.Extensions.Set(new PartitionKey(""));
            testableContext.Extensions.Set(new SetAsDispatchedHolder());

            testableContext.Extensions.Set <IOutboxTransaction>(new CosmosOutboxTransaction(containerHolderHolderResolver, testableContext.Extensions));

            var pendingTransportOperations = new PendingTransportOperations();

            pendingTransportOperations.Add(new Transport.TransportOperation(new OutgoingMessage(null, null, null), null));
            testableContext.Extensions.Set(pendingTransportOperations);

            await behavior.Invoke(testableContext, c => Task.CompletedTask);

            Assert.IsTrue(pendingTransportOperations.HasOperations, "Should have exactly one operation added found on the outbox record");
            Assert.AreEqual("42", pendingTransportOperations.Operations.ElementAt(0).Message.MessageId, "Should have exactly one operation added found on the outbox record");
        }
        public async Task Should_invoke_all_explicit_mutators()
        {
            var mutator      = new MutatorThatIndicatesIfItWasCalled();
            var otherMutator = new MutatorThatIndicatesIfItWasCalled();

            var behavior = new MutateIncomingMessageBehavior(new HashSet <IMutateIncomingMessages> {
                mutator, otherMutator
            });

            var context = new TestableIncomingLogicalMessageContext();

            await behavior.Invoke(context, ctx => TaskEx.CompletedTask);

            Assert.True(mutator.MutateIncomingCalled);
            Assert.True(otherMutator.MutateIncomingCalled);
        }
예제 #24
0
        public async Task Should_not_call_MutateIncoming_when_hasIncomingMessageMutators_is_false()
        {
            var behavior = new MutateIncomingMessageBehavior(new HashSet <IMutateIncomingMessages>());

            var context = new TestableIncomingLogicalMessageContext();

            await behavior.Invoke(context, ctx => Task.CompletedTask);

            var mutator = new MutatorThatIndicatesIfItWasCalled();

            context.Services.AddTransient <IMutateIncomingMessages>(sp => mutator);

            await behavior.Invoke(context, ctx => Task.CompletedTask);

            Assert.IsFalse(mutator.MutateIncomingCalled);
        }
예제 #25
0
        public async Task ShouldRejectCommand()
        {
            var next = A.Fake <Func <Task> >();

            A.CallTo(() => next()).Throws <BusinessException>();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <ICommand>());
            context.MessageHeaders[Defaults.RequestResponse] = "1";
            context.Builder.Register <Action <BusinessException, Reject> >(A.Fake <Action <BusinessException, Reject> >());

            var e = await Record.ExceptionAsync(() => Sut.Invoke(context, next)).ConfigureAwait(false);

            e.Should().BeOfType <BusinessException>();
            context.RepliedMessages.Should().NotBeEmpty();
            context.RepliedMessages[0].Message.Should().BeAssignableTo <Reject>();
        }
예제 #26
0
        public async Task ShouldMutateMessage()
        {
            var mutator = new FakeMutator();

            A.CallTo(() => Configuration.Settings.Container.Resolve(A <Type> .Ignored)).Returns(mutator);
            MutationManager.RegisterMutator("test", typeof(FakeMutator));

            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <Messages.IEvent>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened();
            mutator.MutatedIncoming.Should().BeTrue();
        }
        public async Task Should_not_set_container_information_when_container_information_extractor_returns_false()
        {
            var extractor = new ContainerInformationExtractor(
                (object msg, IReadOnlyDictionary <string, string> headers, out ContainerInformation? container) =>
            {
                container = null;
                return(false);
            });

            var behavior = new TransactionInformationBeforeTheLogicalOutboxBehavior(new CosmosDB.PartitionKeyExtractor(), extractor);

            var context = new TestableIncomingLogicalMessageContext();

            await behavior.Invoke(context, _ => Task.CompletedTask);

            Assert.That(context.Extensions.TryGet <ContainerInformation>(out _), Is.False);
        }
예제 #28
0
        public async Task ShouldNotQueueRetryOnBusinessException()
        {
            var retrier = A.Fake <Internal.DelayedRetry>();

            Inject(retrier);
            var next = A.Fake <Func <Task> >();

            A.CallTo(() => next()).Throws <BusinessException>();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <Messages.IEvent>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => retrier.QueueRetry(A <IFullMessage> .Ignored, A <TimeSpan> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => next()).MustHaveHappened();
        }
예제 #29
0
        public async Task ShouldAddRetryHeader()
        {
            var next = A.Fake <Func <Task> >();

            A.CallTo(() => next()).Throws <Exception>();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <Messages.IEvent>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            context.Extensions.Get <int>(Defaults.Retries).Should().Be(0);

            await Sut.Invoke(context, next).ConfigureAwait(false);

            context.Extensions.Get <int>(Defaults.Retries).Should().Be(1);
        }
        public async Task ShouldUnpackBulkHeader()
        {
            var message = Fake <IFullMessage>();

            A.CallTo(() => message.Headers).Returns(new Dictionary <string, string> {
                [Defaults.ChannelKey] = "test"
            });
            Inject(message);
            var next    = A.Fake <Func <Task> >();
            var context = new TestableIncomingLogicalMessageContext();

            context.UpdateMessageInstance(Fake <int>());
            context.Extensions.Set(Defaults.BulkHeader, Many <IFullMessage>());

            await Sut.Invoke(context, next).ConfigureAwait(false);

            A.CallTo(() => next()).MustHaveHappened(3, Times.Exactly);
        }
        public async Task Should_set_partition_key_when_partition_key_extractor_returns_true()
        {
            var partitionKeyExtractor = new PartitionKeyExtractor(
                (object msg, IReadOnlyDictionary <string, string> headers, out PartitionKey? key) =>
            {
                key = new PartitionKey(true);
                return(true);
            });

            var behavior = new TransactionInformationBeforeTheLogicalOutboxBehavior(partitionKeyExtractor, new ContainerInformationExtractor());

            var context = new TestableIncomingLogicalMessageContext();

            await behavior.Invoke(context, _ => Task.CompletedTask);

            Assert.That(context.Extensions.TryGet <PartitionKey>(out var partitionKey), Is.True);
            Assert.AreEqual(new PartitionKey(true), partitionKey);
        }
        public async Task Should_set_container_when_container_information_extractor_returns_true()
        {
            var extractor = new ContainerInformationExtractor(
                (object msg, IReadOnlyDictionary <string, string> headers, out ContainerInformation? container) =>
            {
                container = new ContainerInformation("containerName", new PartitionKeyPath("/deep/down"));
                return(true);
            });

            var behavior = new TransactionInformationBeforeTheLogicalOutboxBehavior(new PartitionKeyExtractor(), extractor);

            var context = new TestableIncomingLogicalMessageContext();

            await behavior.Invoke(context, _ => Task.CompletedTask);

            Assert.That(context.Extensions.TryGet <ContainerInformation>(out var containerInformation), Is.True);
            Assert.AreEqual(new ContainerInformation("containerName", new PartitionKeyPath("/deep/down")), containerInformation);
        }
        public async Task Should_invoke_both_explicit_and_container_provided_mutators()
        {
            var explicitMutator  = new MutatorThatIndicatesIfItWasCalled();
            var containerMutator = new MutatorThatIndicatesIfItWasCalled();

            var behavior = new MutateIncomingMessageBehavior(new HashSet <IMutateIncomingMessages> {
                explicitMutator
            });

            var context = new TestableIncomingLogicalMessageContext();

            context.Builder.Register <IMutateIncomingMessages>(() => containerMutator);

            await behavior.Invoke(context, ctx => TaskEx.CompletedTask);

            Assert.True(explicitMutator.MutateIncomingCalled);
            Assert.True(containerMutator.MutateIncomingCalled);
        }
예제 #34
0
        public async Task Should_fire_activity_start_stop_when_listener_attached()
        {
            var diagnosticListener = new DiagnosticListener("DummySource");
            var context            = new TestableIncomingLogicalMessageContext();
            var processedFired     = false;

            diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair =>
            {
                if (pair.Key == $"{ActivityNames.IncomingLogicalMessage}.Processed")
                {
                    processedFired = true;
                }
            }));

            var behavior = new IncomingLogicalMessageDiagnostics(diagnosticListener);

            await behavior.Invoke(context, () => Task.CompletedTask);

            processedFired.ShouldBeTrue();
        }
        public void SetupTests()
        {
            behavior = new InvokeSagaNotFoundBehavior();

            incomingContext = new TestableIncomingLogicalMessageContext();
        }