public async Task VeryBasicTransactionThing() { const string destinationQueueName = "another-queue"; var network = new InMemNetwork(); network.CreateQueue(destinationQueueName); var transport = new InMemTransport(network, "test-queue"); transport.Initialize(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() } }; await transport.Send( destinationAddress : destinationQueueName, message : new TransportMessage(headers, new byte[] { 1, 2, 3 }), context : scope.TransactionContext ); Assert.That(network.Count(destinationQueueName), Is.EqualTo(0), $"Expected ZERO messages in queue '{destinationQueueName}' at this point, because the scope was not completed"); await scope.CompleteAsync(); } Assert.That(network.Count(destinationQueueName), Is.EqualTo(1), $"Expected 1 message in queue '{destinationQueueName}' at this point, because the scope is completed now"); }
public async Task UnregisterSubscriber(string topic, string subscriberAddress) { m_log.Debug(c_removingSqsSubscriptionMessage, subscriberAddress, topic); using (var rebusTransactionScope = new RebusTransactionScope()) { var topicArn = await m_AmazonInternalSettings.GetTopicArn(topic, rebusTransactionScope); using (var scope = new RebusTransactionScope()) { var destinationQueueUrlByName = m_amazonSQSQueueContext.GetDestinationQueueUrlByName(subscriberAddress, scope.TransactionContext); var sqsInfo = m_amazonSQSQueueContext.GetSqsInformationFromUri(destinationQueueUrlByName); var snsClient = m_AmazonInternalSettings.CreateSnsClient(rebusTransactionScope.TransactionContext); var listSubscriptionsByTopicResponse = await snsClient.ListSubscriptionsByTopicAsync(topicArn); var subscriptions = listSubscriptionsByTopicResponse?.Subscriptions; var subscription = subscriptions.FirstOrDefault(s => s.SubscriptionArn == sqsInfo.Arn); if (subscription != null) { var unsubscribeResponse = await snsClient.UnsubscribeAsync(subscription.SubscriptionArn); if (unsubscribeResponse.HttpStatusCode != HttpStatusCode.OK) { throw new SnsRebusException($"Error deleting subscription {subscriberAddress} on topic {topic}.", unsubscribeResponse.CreateAmazonExceptionFromResponse()); } } } } m_log.Debug("Removed sqs subscriber {0} to sns topic {1}", subscriberAddress, topic); }
public static async Task <TransportMessage> AwaitReceive(this ITransport transport, double timeoutSeconds = 5) { var stopwatch = Stopwatch.StartNew(); var timeout = TimeSpan.FromSeconds(timeoutSeconds); var source = new CancellationTokenSource(); while (stopwatch.Elapsed < timeout) { TransportMessage receivedTransportMessage; using (var scope = new RebusTransactionScope()) { receivedTransportMessage = await transport.Receive(scope.TransactionContext, source.Token); await scope.CompleteAsync(); } if (receivedTransportMessage != null) { return(receivedTransportMessage); } } throw new AssertionException($"Did not receive transport message from {transport} within {timeout} timeout"); }
public async Task PolymorphicMessageHandling_RemoveDuplicateHandlers() { // Arrange var services = new ServiceCollection(); var testHandler = new Message1Handler(); // Act services .AddSingleton <IHandleMessages <Message1> >(testHandler) .AddSingleton <IHandleMessages <IMessage1> >(testHandler) .AddRebus(config => config .Logging(l => l.None()) .Transport(t => t.UseInMemoryTransport(new InMemNetwork(false), "Messages")) .Routing(r => r.TypeBased().MapAssemblyOf <Message1>("Messages"))); var provider = services .BuildServiceProvider() .UseRebus(); var activator = provider.GetRequiredService <IHandlerActivator>(); // Assert using (var scope = new RebusTransactionScope()) { var handlers = await activator.GetHandlers(new Message1(), scope.TransactionContext); handlers.Should().HaveCount(1); } }
public static void UseRebusOutbox(this IApplicationBuilder app, string connectionString) { app.Use(async(context, next) => { // if you've set up DI resolution to fetch the current connection/transaction from a unit of work, you can do something like this: //var serviceProvider = context.RequestServices; //var connection = serviceProvider.GetRequiredService<SqlConnection>(); //var transaction = serviceProvider.GetRequiredService<SqlTransaction>(); // but in this case we'll work with a simulated unit of work here: await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); // process the web request await next(); // insert outgoing messages await scope.CompleteAsync(); // commit! await transaction.CommitAsync(); }); }
public async Task JustResolveManyTimes(int count) { var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient <IHandleMessages <string> >(p => new StringHandler()); serviceCollection.AddSingleton(p => new DependencyInjectionHandlerActivator(p)); using (var provider = serviceCollection.BuildServiceProvider()) { var handlerActivator = provider.GetRequiredService <DependencyInjectionHandlerActivator>(); var stopwatch = Stopwatch.StartNew(); for (var counter = 0; counter < count; counter++) { using (var scope = new RebusTransactionScope()) { await handlerActivator.GetHandlers("this is my message", scope.TransactionContext); } } var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; Console.WriteLine($"{count} resolutions took {elapsedSeconds:0.0} s - that's {count/elapsedSeconds:0.0} /s"); } }
public async Task CheckIt() { var activator = Using(new BuiltinHandlerActivator()); var network = new InMemNetwork(); var rolledBackMessageReceived = new ManualResetEvent(initialState: false); activator.Handle <ThisMessageShouldNotBeSent>(async _ => rolledBackMessageReceived.Set()); activator.Handle <string>(async(bus, context, message) => { using (var scope = new RebusTransactionScope()) { await scope.CompleteAsync(); } await bus.SendLocal(new ThisMessageShouldNotBeSent()); throw new InvalidOperationException("OH NO!"); }); Configure.With(activator) .Transport(t => t.UseInMemoryTransport(network, "queue-name")) .Options(o => o.FailFastOn <InvalidOperationException>(when: exception => exception.Message.Contains("OH NO!"))) .Start(); await activator.Bus.SendLocal("HEJ MED DIG MIN VEN"); Assert.That(rolledBackMessageReceived.WaitOne(TimeSpan.FromSeconds(3)), Is.False, "Did not expect to receive the ThisMessageShouldNotBeSent, because its Rebus handler transaction was rolled back by an exception"); }
public void SendOperationsEnlistInTheSameTransactionContext(bool commitTransaction) { var receivedMessages = new ConcurrentQueue <string>(); var bus = _activator.Bus.Advanced.SyncBus; _activator.AddHandlerWithBusTemporarilyStopped <string>(async msg => receivedMessages.Enqueue(msg)); using (var context = new RebusTransactionScope()) { bus.SendLocal("hej med dig min ven"); bus.SendLocal("her er endnu en besked"); if (commitTransaction) { context.Complete(); } } Thread.Sleep(500); if (commitTransaction) { Assert.That(receivedMessages, Contains.Item("hej med dig min ven")); Assert.That(receivedMessages, Contains.Item("her er endnu en besked")); } else { Assert.That(receivedMessages.Count, Is.EqualTo(0)); } }
public async Task ItWorks() { var gotMessage = new ManualResetEvent(false); _activator.Handle <string>(async(bus, context, message) => { Console.WriteLine($"Got message with ID {context.Headers.GetValue(Headers.MessageId)} - waiting 2 minutes...."); await Task.Delay(TimeSpan.FromMinutes(2)); Console.WriteLine("done waiting"); gotMessage.Set(); }); _busStarter.Start(); await _bus.SendLocal("hej med dig min ven!"); gotMessage.WaitOrDie(TimeSpan.FromMinutes(2.1)); // shut down bus _bus.Dispose(); // see if queue is empty using var scope = new RebusTransactionScope(); var message = await _transport.Receive(scope.TransactionContext, CancellationToken.None); await scope.CompleteAsync(); if (message != null) { throw new AssertionException( $"Did not expect to receive a message - got one with ID {message.Headers.GetValue(Headers.MessageId)}"); } }
public async Task ReceivesAlmostExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id }, { Headers.TimeToBeReceived, "00:00:20" }, { Headers.SentTime, DateTimeOffset.UtcNow.ToString("O") }//< expires after 10 seconds! }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } await Task.Delay(3000); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Not.Null); } }
public async Task ReceivesNonExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id } }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } await Task.Delay(5000); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Not.Null); var headers = transportMessage.Headers; Assert.That(headers.ContainsKey("recognizzle")); Assert.That(headers["recognizzle"], Is.EqualTo(id)); } }
async Task <List <string> > GetAll(ITransport input) { var transportMessages = new List <string>(); var receivedNulls = 0; while (receivedNulls < 5) { using (var scope = new RebusTransactionScope()) { var msg = await input.Receive(scope.TransactionContext, _cancellationToken); if (msg != null) { transportMessages.Add(GetStringBody(msg)); await scope.CompleteAsync(); continue; } await Task.Delay(100); receivedNulls++; } } return(transportMessages); }
public static async Task <TransportMessage> WaitForNextMessage(this ITransport transport, int timeoutSeconds = 5) { var stopwatch = Stopwatch.StartNew(); while (true) { using (var scope = new RebusTransactionScope()) { var nextMessage = await transport.Receive(scope.TransactionContext, CancellationToken.None); await scope.CompleteAsync(); if (nextMessage != null) { return(nextMessage); } } await Task.Delay(100); if (stopwatch.Elapsed < TimeSpan.FromSeconds(timeoutSeconds)) { continue; } throw new TimeoutException($"Did not receive message from transport with address '{transport.Address}' within {timeoutSeconds} s timeout"); } }
static async Task PutInQueue(ITransport transport, TransportMessage transportMessage) { using var scope = new RebusTransactionScope(); await transport.Send(QueueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); }
public async Task Send_StoresMessagesToOutboxOnCommit() { using var rebusTransactionScope = new RebusTransactionScope(); var transportMessage1 = new TransportMessage(new Dictionary <string, string>(), new byte[0]); const string destinationAddress1 = "TestAddress1"; var transportMessage2 = new TransportMessage(new Dictionary <string, string>(), new byte[0]); const string destinationAddress2 = "TestAddress2"; await _decorator.Send(destinationAddress1, transportMessage1, rebusTransactionScope.TransactionContext); await _decorator.Send(destinationAddress2, transportMessage2, rebusTransactionScope.TransactionContext); Assert.True(rebusTransactionScope.TransactionContext.Items.TryGetValue( OutboxTransportDecorator.OutgoingMessagesItemsKey, out var outgoingMessagesObject)); var outgoingMessages = ((IEnumerable <TransportMessage>)outgoingMessagesObject).ToArray(); Assert.Contains(transportMessage1, outgoingMessages); Assert.Contains(transportMessage2, outgoingMessages); var recipient1 = Assert.Contains(OutboxHeaders.Recipient, transportMessage1.Headers as IDictionary <string, string>); Assert.Equal(destinationAddress1, recipient1); var recipient2 = Assert.Contains(OutboxHeaders.Recipient, transportMessage2.Headers as IDictionary <string, string>); Assert.Equal(destinationAddress2, recipient2); await rebusTransactionScope.CompleteAsync(); await _outboxStorage.Received().Store(transportMessage1); await _outboxStorage.Received().Store(transportMessage2); }
public void TakeTime(int count) { var activator = new BuiltinHandlerActivator(); Using(activator); activator.Handle <string>(async str => { }); activator.Handle <string>(async(bus, str) => { }); activator.Handle <string>(async(bus, context, str) => { }); var stopwatch = Stopwatch.StartNew(); for (var counter = 0; counter < count; counter++) { using (var scope = new RebusTransactionScope()) { // ReSharper disable once UnusedVariable var handlers = _activator.GetHandlers("hej med dig", scope.TransactionContext).Result; } } var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; Console.WriteLine($"{count} resolutions took {elapsedSeconds:0.0} s - that's {count/elapsedSeconds:0.0} /s"); }
public async Task WrapsInvokersSoTheyCanRunInsideAnActivity() { var step = new IncomingDiagnosticsHandlerInvokerWrapper(); var headers = new Dictionary <string, string> { { Headers.Type, "MyType" } }; var transportMessage = new TransportMessage(headers, Array.Empty <byte>()); var message = new Message(headers, Array.Empty <byte>()); var innerInvoker = new TestInvoker(() => { }); var handlerInvokers = new HandlerInvokers(message, new[] { innerInvoker }); var scope = new RebusTransactionScope(); var context = new IncomingStepContext(transportMessage, scope.TransactionContext); context.Save(handlerInvokers); var callbackWasInvoked = false; await step.Process(context, () => { callbackWasInvoked = true; return(Task.CompletedTask); }); Assert.That(callbackWasInvoked); var updatedInvokers = context.Load <HandlerInvokers>(); Assert.That(updatedInvokers, Is.Not.SameAs(handlerInvokers)); Assert.That(updatedInvokers, Has.Exactly(1).Items.And.All.TypeOf <HandlerInvokerWrapper>()); }
public async Task DoesNotReceiveExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id }, { Headers.TimeToBeReceived, "00:00:04" } //< expires after 4 seconds! }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } const int millisecondsDelay = 7000; var stopwatch = Stopwatch.StartNew(); await Task.Delay(millisecondsDelay); Console.WriteLine($"Delay of {millisecondsDelay} ms actually lasted {stopwatch.ElapsedMilliseconds:0} ms"); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Null); } }
public async Task CannotReceiveSameMessageTwiceEvenWhenSnapahotIsolationIsOn() { const string sentText = "HEJ MED DIG MIN VEN!!!!!11"; var transportMessage = new TransportMessage(new Dictionary <string, string>(), Encoding.UTF8.GetBytes(sentText)); var transport1 = GetTransport(";MultipleActiveResultSets=True;" + SqlTestHelper.ConnectionString, IsolationLevel.Snapshot); var transport2 = GetTransport(SqlTestHelper.ConnectionString, IsolationLevel.Snapshot); using (var scope = new RebusTransactionScope()) { await transport1.Send(_queueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); } using (var scope1 = new RebusTransactionScope()) using (var scope2 = new RebusTransactionScope()) { var message1 = await transport1.Receive(scope1.TransactionContext, CancellationToken.None); var message2 = await transport2.Receive(scope2.TransactionContext, CancellationToken.None); Assert.That(message1, Is.Not.Null); Assert.That(Encoding.UTF8.GetString(message1.Body), Is.EqualTo(sentText)); Assert.That(message2, Is.Null, "Expected the second message to be null, because we should NOT be able to accidentally peek at the same message as another ongoing transaction"); await scope2.CompleteAsync(); await scope1.CompleteAsync(); } }
public static IEnumerable <TransportMessage> GetMessages(this SqlServerTransport transport) { var messages = new List <TransportMessage>(); AsyncHelpers.RunSync(async() => { while (true) { using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, CancellationToken.None); if (transportMessage == null) { break; } messages.Add(transportMessage); await scope.CompleteAsync(); } } }); return(messages); }
static List <int> SendMessages(int messageCount) { var transport = new MsmqTransport(QueueName, new ConsoleLoggerFactory(true)); MsmqUtil.EnsureQueueExists(MsmqUtil.GetPath(QueueName)); var sendIds = new List <int>(); Enumerable.Range(0, messageCount) .Select(id => new SomeMessage { Id = id }) .ToList() .ForEach(msg => { using (var scope = new RebusTransactionScope()) { transport.Send(QueueName, TransportMessageHelpers.FromString(JsonConvert.SerializeObject(msg)), scope.TransactionContext).Wait(); scope.Complete(); sendIds.Add(msg.Id); } }); return(sendIds); }
public async Task DoesNotHitTheLimit() { var queueName = TestConfig.GetName("payload-limit"); Using(new QueueDeleter(queueName)); var activator = Using(new BuiltinHandlerActivator()); activator.Handle <MessageWithText>(async _ => { }); var bus = Configure.With(activator) .Logging(l => l.Console(LogLevel.Info)) .Transport(t => t.UseAzureServiceBus(AsbTestConfig.ConnectionString, queueName)) .Start(); using (var scope = new RebusTransactionScope()) { var strings = Enumerable.Range(0, 1000) .Select(n => new MessageWithText($"message {n}")); await Task.WhenAll(strings.Select(str => bus.SendLocal(str))); await scope.CompleteAsync(); } }
public void WorksWithPrefetch(int prefetch, int numberOfMessages, int maxParallelism) { var activator = Using(new BuiltinHandlerActivator()); var counter = new SharedCounter(numberOfMessages); Using(counter); activator.Handle <string>(async str => { counter.Decrement(); }); Console.WriteLine("Sending {0} messages", numberOfMessages); var transport = GetTransport(); var tasks = Enumerable.Range(0, numberOfMessages) .Select(i => $"THIS IS MESSAGE # {i}") .Select(async msg => { using (var scope = new RebusTransactionScope()) { var headers = DefaultHeaders(); var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(msg)); var transportMessage = new TransportMessage(headers, body); await transport.Send(_queueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); } }) .ToArray(); Task.WhenAll(tasks).Wait(); Console.WriteLine("Receiving {0} messages", numberOfMessages); var stopwatch = Stopwatch.StartNew(); Configure.With(activator) .Logging(l => l.Console(LogLevel.Info)) .Transport(t => { t.UseAzureServiceBus(AsbTestConfig.ConnectionString, _queueName) .EnablePrefetching(prefetch); }) .Options(o => { o.SetNumberOfWorkers(1); o.SetMaxParallelism(maxParallelism); }) .Start(); counter.WaitForResetEvent(timeoutSeconds: (int)(numberOfMessages * 0.1 + 3)); var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; Console.WriteLine("Receiving {0} messages took {1:0.0} s - that's {2:0.0} msg/s", numberOfMessages, elapsedSeconds, numberOfMessages / elapsedSeconds); }
public async Task LotsOfAsyncStuffGoingDown(int numberOfMessages) { var receivedMessages = 0L; var messageIds = new ConcurrentDictionary <int, int>(); Console.WriteLine("Sending {0} messages", numberOfMessages); await Task.WhenAll(Enumerable.Range(0, numberOfMessages) .Select(async i => { using (var scope = new RebusTransactionScope()) { await _transport.Send(QueueName, RecognizableMessage(i), scope.TransactionContext); await scope.CompleteAsync(); messageIds[i] = 0; } })); Console.WriteLine("Receiving {0} messages", numberOfMessages); using (new Timer(_ => Console.WriteLine("Received: {0} msgs", receivedMessages), null, 0, 1000)) { var stopwatch = Stopwatch.StartNew(); while (Interlocked.Read(ref receivedMessages) < numberOfMessages && stopwatch.Elapsed < TimeSpan.FromMinutes(2)) { await Task.WhenAll(Enumerable.Range(0, 10).Select(async __ => { using (var scope = new RebusTransactionScope()) { var msg = await _transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); if (msg != null) { Interlocked.Increment(ref receivedMessages); var id = int.Parse(msg.Headers["id"]); messageIds.AddOrUpdate(id, 1, (_, existing) => existing + 1); } } })); } await Task.Delay(3000); } Assert.That(messageIds.Keys.OrderBy(k => k).ToArray(), Is.EqualTo(Enumerable.Range(0, numberOfMessages).ToArray())); var kvpsDifferentThanOne = messageIds.Where(kvp => kvp.Value != 1).ToList(); if (kvpsDifferentThanOne.Any()) { Assert.Fail(@"Oh no! the following IDs were not received exactly once: {0}", string.Join(Environment.NewLine, kvpsDifferentThanOne.Select(kvp => $" {kvp.Key}: {kvp.Value}"))); } }
private async Task ProcessOutboxMessages() { _log.Debug("Starting outbox messages processor"); while (!_busDisposalCancellationToken.IsCancellationRequested) { try { bool waitForMessages; using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var messages = await _outboxStorage.Retrieve(_busDisposalCancellationToken, _topMessagesToRetrieve); if (messages.Length > 0) { using (var rebusTransactionScope = new RebusTransactionScope()) { foreach (var message in messages) { var destinationAddress = message.Headers[OutboxHeaders.Recipient]; message.Headers.Remove(OutboxHeaders.Recipient); await _transport.Send(destinationAddress, message, rebusTransactionScope.TransactionContext); } await rebusTransactionScope.CompleteAsync(); } waitForMessages = false; } else { waitForMessages = true; } transactionScope.Complete(); } if (waitForMessages) { await _backoffStrategy.WaitNoMessageAsync(_busDisposalCancellationToken); } else { _backoffStrategy.Reset(); } } catch (OperationCanceledException) when(_busDisposalCancellationToken.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in outbox messages processor"); await _backoffStrategy.WaitErrorAsync(_busDisposalCancellationToken); } } _log.Debug("Outbox messages processor stopped"); }
public async Task RespectsSerializedAccessToUnderlyingConnectionEvenWhenCalledInParallel() { using (var scope = new RebusTransactionScope()) { await Task.WhenAll( _transport.Send(QueueName, RecognizableMessage(), scope.TransactionContext), _transport.Send(QueueName, RecognizableMessage(), scope.TransactionContext)); } }
void Send(string destinationAddress, string message) { Console.WriteLine("Sending to {0}", destinationAddress); using (var scope = new RebusTransactionScope()) { _transport.Send(destinationAddress, NewMessage(message), scope.TransactionContext).Wait(); scope.Complete(); } }
public async Task Handlers_ShouldHandleSameCovariantType() { var activator = Setup(new CovariantGenericParentMessageHandler(), typeof(IHandleMessages <ICovariantGeneric <Parent> >)); using (var scope = new RebusTransactionScope()) { var handlers = await activator.GetHandlers(new ConcreteCovariantGeneric <Parent>(), scope.TransactionContext); handlers.Should().HaveCount(1); } }
public async Task Handlers_ShouldNotHandleSupertype() { var activator = Setup(new ChildMessageHandler(), typeof(IHandleMessages <Child>)); using (var scope = new RebusTransactionScope()) { var handlers = await activator.GetHandlers(new Parent(), scope.TransactionContext); handlers.Should().HaveCount(0); } }
public async Task Handlers_ShouldHandleIFailedMessages() { var activator = Setup(new FailedMessageHandler(), typeof(IHandleMessages <IFailed <object> >)); using (var scope = new RebusTransactionScope()) { var handlers = await activator.GetHandlers(new FailedMessage <Child>(), scope.TransactionContext); handlers.Should().HaveCount(1); } }