From 35064fa8bbec747bb1d862fe67dbf54a8d62c14b Mon Sep 17 00:00:00 2001 From: Szymon Pobiega Date: Thu, 24 Aug 2023 21:49:18 +0200 Subject: [PATCH] Almost working --- .../AcceptanceTesting.csproj | 8 +- .../ConfigureEndpointInMemoryPersistence.cs | 2 +- .../ConfigureEndpointTestTransport.cs | 116 ++--- .../Infrastructure/DeterministicGuid.cs | 2 +- .../EndpointTemplates/ConfigureExtensions.cs | 3 +- .../EndpointConfigurationExtensions.cs | 19 - .../IConfigureEndpointTestExecution.cs | 4 +- .../Infrastructure/SpyComponent.cs | 12 +- .../Infrastructure/SpyComponentExtensions.cs | 9 +- .../Infrastructure/SpyComponentRunner.cs | 21 +- .../SubscriptionBehaviorExtensions.cs | 84 --- src/AcceptanceTesting/SubscriptionHelper.cs | 5 +- .../TestTransport/AsyncFile.cs | 149 ------ .../TestTransport/AsyncTimer.cs | 51 -- .../TestTransport/DelayedMessagePoller.cs | 64 --- .../DeliveryConstraintExtensions.cs | 16 - .../DirectoryBasedTransaction.cs | 153 ------ .../TestTransport/HeaderSerializer.cs | 39 -- .../ITestTransportTransaction.cs | 21 - .../TestTransport/NoTransaction.cs | 41 -- .../TestTransport/PathChecker.cs | 25 - src/AcceptanceTesting/TestTransport/TaskEx.cs | 14 - .../TestTransport/TestTransport.cs | 36 -- .../TestTransportConfigurationExtensions.cs | 45 -- .../TestTransport/TestTransportDispatcher.cs | 244 --------- .../TestTransport/TestTransportHeaders.cs | 7 - .../TestTransportInfrastructure.cs | 137 ----- .../TestTransport/TestTransportMessagePump.cs | 346 ------------- .../TestTransportQueueCreator.cs | 33 -- .../TestTransportSubscriptionManager.cs | 97 ---- src/Billing/Billing.csproj | 1 - src/Client/Client.csproj | 1 - .../LoadTests.Receiver.Router.csproj | 1 - .../LoadTests.Sender.Router.csproj | 1 - ...ing_from_message_driven_pubsub_endpoint.cs | 133 ----- .../When_replying_to_a_message.cs | 105 ---- .../When_publishing_via_two_routers.cs | 184 ------- ...ublishing_via_two_routers_native_pubsub.cs | 188 ------- .../When_sending_via_two_routers.cs | 163 ------ .../Infrastructure/BrokerSettings.cs | 45 ++ .../Infrastructure/ConfigureExtensions.cs | 49 ++ .../Infrastructure/DefaultServer.cs | 42 ++ ...intCustomizationConfigurationExtensions.cs | 54 ++ .../Infrastructure/IPoisonSpyContext.cs | 8 + .../InMemorySubscriptionStorage.cs | 90 ++++ .../NServiceBusAcceptanceTest.cs | 40 ++ .../Infrastructure/RouterComponent.cs | 72 +++ .../RouterComponentExtensions.cs | 32 ++ .../Infrastructure/SpyComponent.cs | 32 ++ .../Infrastructure/SpyComponentExtensions.cs | 42 ++ .../Infrastructure/SpyComponentRunner.cs | 51 ++ .../Infrastructure/SubscriptionHelper.cs | 17 + .../When_connecting_to_two_routers.cs | 133 ----- ...en_publishing_via_double_unicast_bridge.cs | 96 ---- ...ing_via_double_unicast_multicast_bridge.cs | 96 ---- .../When_sender_delegates_routing.cs | 131 ----- .../When_sending_between_sites.cs | 191 ------- .../When_sending_via_three_routers.cs | 119 ----- .../When_sending_via_two_routers.cs | 173 ------- .../NServiceBus.Router.AcceptanceTests.csproj | 23 +- .../When_interface_is_not_configured.cs | 90 ---- ...When_reply_correlation_id_is_overridden.cs | 127 ----- ...n_reply_does_not_contain_correlation_id.cs | 127 ----- .../When_reply_does_not_specify_iface.cs | 128 ----- ...n_routing_configuration_contains_cycles.cs | 97 ---- ...hen_sender_does_not_specify_destination.cs | 89 ---- .../Poison/When_there_is_no_route.cs | 90 ---- ...orwarding_a_message_via_sendonly_router.cs | 12 +- .../When_intentionally_dropping_messages.cs | 10 +- ...ionally_dropping_messages_in_prerouting.cs | 10 +- ...hen_migrating_transport_publisher_first.cs | 349 ------------- .../When_migrating_transport_sends.cs | 279 ---------- ...en_migrating_transport_subscriber_first.cs | 315 ------------ .../SingleRouter/When_mutating_messages.cs | 13 +- ...l_interfaces_are_interested_in_an_event.cs | 18 +- .../When_publisher_is_scaled_out.cs | 15 +- ...n_publishing_from_asb_endpoint_oriented.cs | 145 ------ ...oint_oriented_while_router_is_restarted.cs | 159 ------ ...shing_from_message_driven_endpoint_auto.cs | 294 +++++------ ...ing_from_message_driven_pubsub_endpoint.cs | 19 +- ..._publishing_from_native_pubsub_endpoint.cs | 19 +- ...ishing_from_native_pubsub_endpoint_auto.cs | 24 +- .../When_receiver_is_scaled_out.cs | 16 +- .../When_replying_to_a_message.cs | 14 +- .../When_replying_to_a_message_with_asb.cs | 132 ----- .../SingleRouter/When_replying_to_a_reply.cs | 12 +- ...o_an_event_from_message_driven_endpoint.cs | 15 +- ...to_an_event_from_native_pubsub_endpoint.cs | 13 +- .../SingleRouter/When_routing_metrics.cs | 18 +- .../When_sender_delegates_routing.cs | 12 +- ...ending_a_message_based_on_other_message.cs | 18 +- .../When_sending_from_sendonly_endpoint.cs | 11 +- .../When_subscriber_is_not_aware_of_router.cs | 22 +- .../When_subscriber_is_scaled_out.cs | 18 +- .../SingleRouter/When_subscribing_from_asb.cs | 121 ----- ...rom_native_and_message_driven_endpoints.cs | 21 +- ...subscribing_from_native_pubsub_endpoint.cs | 19 +- ...When_subscribing_locally_and_via_router.cs | 18 +- .../When_using_sql_persistence.cs | 21 +- .../NServiceBus.Router.Connector.csproj | 4 +- .../RouterAutoSubscribeBehavior.cs | 2 +- .../RouterConnectionFeature.cs | 25 +- .../RouterSubscribeBehavior.cs | 55 +- .../RouterUnsubscribeBehavior.cs | 11 +- .../DeduplicationExtensions.cs | 2 +- .../NServiceBus.Router.SqlServer.csproj | 10 +- .../InboxPersisterTests.cs | 275 ---------- .../LinkStateTests.cs | 63 --- .../NServiceBus.Router.Tests.csproj | 5 +- .../OutboxPersisterTests.cs | 479 ------------------ src/NServiceBus.Router.sln | 67 +-- .../IRuleCreationContext.cs | 2 +- src/NServiceBus.Router/Interface.cs | 25 +- .../InterfaceConfiguration.cs | 34 +- src/NServiceBus.Router/MessageDrivenPubSub.cs | 4 +- .../MessageDrivenPubSubFeature.cs | 5 +- .../MessageDrivenSubscriptionExtensions.cs | 14 +- .../NServiceBus.Router.csproj | 8 +- src/NServiceBus.Router/NativePubSubFeature.cs | 5 +- .../NativeSubscriptionExtensions.cs | 4 +- .../Forwarding/1_ForwardPublishContext.cs | 2 +- .../Forwarding/1_ForwardReplyContext.cs | 4 +- .../Forwarding/1_ForwardSendContext.cs | 3 +- .../Forwarding/ForwardSubscribeGatewayRule.cs | 2 +- .../ForwardSubscribeMessageDrivenRule.cs | 2 +- .../Forwarding/ForwardSubscribeNativeRule.cs | 7 +- .../ForwardUnsubscribeGatewayRule.cs | 2 +- .../ForwardUnsubscribeMessageDrivenRule.cs | 2 +- .../ForwardUnsubscribeNativeRule.cs | 7 +- .../Pipeline/IRuleContext.cs | 6 + .../Postrouting/PostroutingTerminator.cs | 2 +- .../Pipeline/Prerouting/1_RawContext.cs | 5 +- .../Prerouting/2_PreroutingContext.cs | 8 +- .../Prerouting/3_PublishPreroutingContext.cs | 4 +- .../Prerouting/3_ReplyPreroutingContext.cs | 4 +- .../Prerouting/3_SendPreroutingContext.cs | 3 +- .../PreroutingToPublishPreroutingFork.cs | 2 +- .../PreroutingToReplyPreroutingFork.cs | 2 +- .../PreroutingToSendPreroutingFork.cs | 2 +- .../PreroutingToSubscribePreroutingFork.cs | 6 +- .../Pipeline/RootContext.cs | 10 +- .../Pipeline/RuleContext.cs | 8 + src/NServiceBus.Router/Router.cs | 5 +- src/NServiceBus.Router/RouterConfiguration.cs | 28 +- src/NServiceBus.Router/RouterImpl.cs | 6 +- src/NServiceBus.Router/RuleCreationContext.cs | 4 +- src/NServiceBus.Router/SendOnlyInterface.cs | 22 +- .../SendOnlyInterfaceConfiguration.cs | 22 +- src/NServiceBus.Router/SettingsHolder.cs | 2 +- .../SqlDialect_MsSqlServer.cs | 2 +- .../SqlSubscriptionStorage.cs | 7 +- .../ThrottlingRawEndpointConfig.cs | 115 ++--- src/PaymentGateway/PaymentGateway.csproj | 2 - src/Sales/Sales.csproj | 2 - src/Shipping/Shipping.csproj | 1 - src/ShippingGateway/ShippingGateway.csproj | 2 - 156 files changed, 1284 insertions(+), 7174 deletions(-) delete mode 100644 src/AcceptanceTesting/Infrastructure/EndpointTemplates/EndpointConfigurationExtensions.cs delete mode 100644 src/AcceptanceTesting/Infrastructure/SubscriptionBehaviorExtensions.cs delete mode 100644 src/AcceptanceTesting/TestTransport/AsyncFile.cs delete mode 100644 src/AcceptanceTesting/TestTransport/AsyncTimer.cs delete mode 100644 src/AcceptanceTesting/TestTransport/DelayedMessagePoller.cs delete mode 100644 src/AcceptanceTesting/TestTransport/DeliveryConstraintExtensions.cs delete mode 100644 src/AcceptanceTesting/TestTransport/DirectoryBasedTransaction.cs delete mode 100644 src/AcceptanceTesting/TestTransport/HeaderSerializer.cs delete mode 100644 src/AcceptanceTesting/TestTransport/ITestTransportTransaction.cs delete mode 100644 src/AcceptanceTesting/TestTransport/NoTransaction.cs delete mode 100644 src/AcceptanceTesting/TestTransport/PathChecker.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TaskEx.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransport.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportConfigurationExtensions.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportDispatcher.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportHeaders.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportInfrastructure.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportMessagePump.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportQueueCreator.cs delete mode 100644 src/AcceptanceTesting/TestTransport/TestTransportSubscriptionManager.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_publishing_from_message_driven_pubsub_endpoint.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_replying_to_a_message.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers_native_pubsub.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Deduplication/When_sending_via_two_routers.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/BrokerSettings.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/ConfigureExtensions.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/DefaultServer.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/EndpointCustomizationConfigurationExtensions.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/IPoisonSpyContext.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/InMemorySubscriptionStorage.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/NServiceBusAcceptanceTest.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponent.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponentExtensions.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponent.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentExtensions.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentRunner.cs create mode 100644 src/NServiceBus.Router.AcceptanceTests/Infrastructure/SubscriptionHelper.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_connecting_to_two_routers.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_bridge.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_multicast_bridge.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sender_delegates_routing.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_between_sites.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_three_routers.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_two_routers.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_interface_is_not_configured.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_correlation_id_is_overridden.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_contain_correlation_id.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_specify_iface.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_routing_configuration_contains_cycles.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_sender_does_not_specify_destination.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/Poison/When_there_is_no_route.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_publisher_first.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_sends.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_subscriber_first.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented_while_router_is_restarted.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message_with_asb.cs delete mode 100644 src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_asb.cs delete mode 100644 src/NServiceBus.Router.Tests/InboxPersisterTests.cs delete mode 100644 src/NServiceBus.Router.Tests/LinkStateTests.cs delete mode 100644 src/NServiceBus.Router.Tests/OutboxPersisterTests.cs diff --git a/src/AcceptanceTesting/AcceptanceTesting.csproj b/src/AcceptanceTesting/AcceptanceTesting.csproj index 65fd879..74e9dc9 100644 --- a/src/AcceptanceTesting/AcceptanceTesting.csproj +++ b/src/AcceptanceTesting/AcceptanceTesting.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + net48;net6.0 @@ -13,9 +13,9 @@ - - - + + + diff --git a/src/AcceptanceTesting/Infrastructure/ConfigureEndpointInMemoryPersistence.cs b/src/AcceptanceTesting/Infrastructure/ConfigureEndpointInMemoryPersistence.cs index ab50ff0..b12cf56 100644 --- a/src/AcceptanceTesting/Infrastructure/ConfigureEndpointInMemoryPersistence.cs +++ b/src/AcceptanceTesting/Infrastructure/ConfigureEndpointInMemoryPersistence.cs @@ -6,7 +6,7 @@ public class ConfigureEndpointInMemoryPersistence { public Task Configure(string endpointName, EndpointConfiguration configuration, RunSettings settings, PublisherMetadata publisherMetadata) { - configuration.UsePersistence(); + configuration.UsePersistence(); return Task.FromResult(0); } } \ No newline at end of file diff --git a/src/AcceptanceTesting/Infrastructure/ConfigureEndpointTestTransport.cs b/src/AcceptanceTesting/Infrastructure/ConfigureEndpointTestTransport.cs index f51722e..422c83b 100644 --- a/src/AcceptanceTesting/Infrastructure/ConfigureEndpointTestTransport.cs +++ b/src/AcceptanceTesting/Infrastructure/ConfigureEndpointTestTransport.cs @@ -1,69 +1,69 @@ -using System; -using System.IO; -using NServiceBus; -using NUnit.Framework; +//using System; +//using System.IO; +//using NServiceBus; +//using NUnit.Framework; -public static class ConfigureEndpointTestTransport -{ - public static TransportExtensions BrokerAlpha(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Alpha"); - transportConfig.NoNativePubSub(); - return transportConfig; - } +//public static class ConfigureEndpointTestTransport +//{ +// public static TransportExtensions BrokerAlpha(this TestTransport transportConfig) +// { +// Configure(transportConfig, "Alpha"); +// transportConfig.NoNativePubSub(); +// return transportConfig; +// } - public static TransportExtensions BrokerBravo(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Bravo"); - transportConfig.NoNativePubSub(); - return transportConfig; - } +// public static TransportExtensions BrokerBravo(this TransportExtensions transportConfig) +// { +// Configure(transportConfig, "Bravo"); +// transportConfig.NoNativePubSub(); +// return transportConfig; +// } - public static TransportExtensions BrokerCharlie(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Charlie"); - transportConfig.NoNativePubSub(); - return transportConfig; - } +// public static TransportExtensions BrokerCharlie(this TransportExtensions transportConfig) +// { +// Configure(transportConfig, "Charlie"); +// transportConfig.NoNativePubSub(); +// return transportConfig; +// } - public static TransportExtensions BrokerDelta(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Delta"); - transportConfig.NoNativePubSub(); - return transportConfig; - } +// public static TransportExtensions BrokerDelta(this TransportExtensions transportConfig) +// { +// Configure(transportConfig, "Delta"); +// transportConfig.NoNativePubSub(); +// return transportConfig; +// } - public static TransportExtensions BrokerYankee(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Yankee"); - return transportConfig; - } +// public static TransportExtensions BrokerYankee(this TransportExtensions transportConfig) +// { +// Configure(transportConfig, "Yankee"); +// return transportConfig; +// } - public static TransportExtensions BrokerZulu(this TransportExtensions transportConfig) - { - Configure(transportConfig, "Zulu"); - return transportConfig; - } +// public static TransportExtensions BrokerZulu(this TransportExtensions transportConfig) +// { +// Configure(transportConfig, "Zulu"); +// return transportConfig; +// } - static void Configure(TransportExtensions transportConfig, string brokerId) - { - var testRunId = TestContext.CurrentContext.Test.ID; +// static void Configure(TransportExtensions transportConfig, string brokerId) +// { +// var testRunId = TestContext.CurrentContext.Test.ID; - string tempDir; +// string tempDir; - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - //can't use bin dir since that will be too long on the build agents - tempDir = @"c:\temp"; - } - else - { - tempDir = Path.GetTempPath(); - } +// if (Environment.OSVersion.Platform == PlatformID.Win32NT) +// { +// //can't use bin dir since that will be too long on the build agents +// tempDir = @"c:\temp"; +// } +// else +// { +// tempDir = Path.GetTempPath(); +// } - var storageDir = Path.Combine(tempDir, testRunId, brokerId); +// var storageDir = Path.Combine(tempDir, testRunId, brokerId); - transportConfig.StorageDirectory(storageDir); - transportConfig.BrokerName(brokerId); - } -} \ No newline at end of file +// transportConfig.StorageDirectory(storageDir); +// transportConfig.BrokerName(brokerId); +// } +//} \ No newline at end of file diff --git a/src/AcceptanceTesting/Infrastructure/DeterministicGuid.cs b/src/AcceptanceTesting/Infrastructure/DeterministicGuid.cs index 97248bb..83e4271 100644 --- a/src/AcceptanceTesting/Infrastructure/DeterministicGuid.cs +++ b/src/AcceptanceTesting/Infrastructure/DeterministicGuid.cs @@ -9,7 +9,7 @@ static class DeterministicGuid public static Guid Create(params object[] data) { // use MD5 hash to get a 16-byte hash of the string - using (var provider = new MD5CryptoServiceProvider()) + using (var provider = MD5.Create()) { var inputBytes = Encoding.Default.GetBytes(string.Concat(data)); var hashBytes = provider.ComputeHash(inputBytes); diff --git a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/ConfigureExtensions.cs b/src/AcceptanceTesting/Infrastructure/EndpointTemplates/ConfigureExtensions.cs index a06179d..b877925 100644 --- a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/ConfigureExtensions.cs +++ b/src/AcceptanceTesting/Infrastructure/EndpointTemplates/ConfigureExtensions.cs @@ -8,8 +8,9 @@ public static class ConfigureExtensions { public static async Task DefinePersistence(this EndpointConfiguration config, RunDescriptor runDescriptor, EndpointCustomizationConfiguration endpointCustomizationConfiguration) { - var persistenceConfiguration = new ConfigureEndpointInMemoryPersistence(); + var persistenceConfiguration = TestSuiteConstraints.Current.CreatePersistenceConfiguration(); await persistenceConfiguration.Configure(endpointCustomizationConfiguration.EndpointName, config, runDescriptor.Settings, endpointCustomizationConfiguration.PublisherMetadata); + runDescriptor.OnTestCompleted(_ => persistenceConfiguration.Cleanup()); } public static void RegisterComponentsAndInheritanceHierarchy(this EndpointConfiguration builder, RunDescriptor runDescriptor) diff --git a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/EndpointConfigurationExtensions.cs b/src/AcceptanceTesting/Infrastructure/EndpointTemplates/EndpointConfigurationExtensions.cs deleted file mode 100644 index 4f60c01..0000000 --- a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/EndpointConfigurationExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace NServiceBus.AcceptanceTests -{ - using System; - using AcceptanceTesting.Support; - using Configuration.AdvancedExtensibility; - - public static class EndpointConfigurationExtensions - { - public static void ConfigureTransport(this EndpointConfiguration endpointConfiguration, Action configureTransport = null) - where T : IConfigureEndpointTestExecution, new() - { - var config = new T - { - ConfigureTransport = configureTransport - }; - endpointConfiguration.GetSettings().Set(config); - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/IConfigureEndpointTestExecution.cs b/src/AcceptanceTesting/Infrastructure/EndpointTemplates/IConfigureEndpointTestExecution.cs index d559f58..c1a2d63 100644 --- a/src/AcceptanceTesting/Infrastructure/EndpointTemplates/IConfigureEndpointTestExecution.cs +++ b/src/AcceptanceTesting/Infrastructure/EndpointTemplates/IConfigureEndpointTestExecution.cs @@ -1,6 +1,5 @@ namespace NServiceBus.AcceptanceTesting.Support { - using System; using System.Threading.Tasks; /// @@ -9,8 +8,7 @@ /// public interface IConfigureEndpointTestExecution { - Action ConfigureTransport { get; set; } - /// + /// /// Gives the transport/persistence a chance to configure before the test starts. /// /// The endpoint name. diff --git a/src/AcceptanceTesting/Infrastructure/SpyComponent.cs b/src/AcceptanceTesting/Infrastructure/SpyComponent.cs index 44a98e1..91da2c9 100644 --- a/src/AcceptanceTesting/Infrastructure/SpyComponent.cs +++ b/src/AcceptanceTesting/Infrastructure/SpyComponent.cs @@ -1,6 +1,6 @@ using System; +using System.Threading; using System.Threading.Tasks; -using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Transport; @@ -8,12 +8,12 @@ class SpyComponent : IComponentBehavior where T : ScenarioContext { - Action> transportConfiguration; - Func onMessage; + TransportDefinition transportConfiguration; + Func onMessage; string endpointName; - public SpyComponent(string endpointName, Action> transportConfiguration, - Func onMessage) + public SpyComponent(string endpointName, TransportDefinition transportConfiguration, + Func onMessage) { this.transportConfiguration = transportConfiguration; this.onMessage = onMessage; @@ -24,6 +24,6 @@ public Task CreateRunner(RunDescriptor run) { var scenarioContext = (T)run.ScenarioContext; - return Task.FromResult(new SpyComponentRunner(endpointName, transportConfiguration, (messageContext, messages) => onMessage(scenarioContext, messageContext, messages), scenarioContext)); + return Task.FromResult(new SpyComponentRunner(endpointName, transportConfiguration, (messageContext, messages, token) => onMessage(scenarioContext, messageContext, messages, token))); } } \ No newline at end of file diff --git a/src/AcceptanceTesting/Infrastructure/SpyComponentExtensions.cs b/src/AcceptanceTesting/Infrastructure/SpyComponentExtensions.cs index 78abe08..3dc3edd 100644 --- a/src/AcceptanceTesting/Infrastructure/SpyComponentExtensions.cs +++ b/src/AcceptanceTesting/Infrastructure/SpyComponentExtensions.cs @@ -1,17 +1,16 @@ using System; using System.Threading; using System.Threading.Tasks; -using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Transport; public static class SpyComponentExtensions { - public static IScenarioWithEndpointBehavior WithPosionSpyComponent(this IScenarioWithEndpointBehavior scenario, Action> transportConfiguration) + public static IScenarioWithEndpointBehavior WithPosionSpyComponent(this IScenarioWithEndpointBehavior scenario, TransportDefinition transportConfiguration) where TContext : ScenarioContext, IPoisonSpyContext { - return scenario.WithComponent(new SpyComponent("poison", transportConfiguration, (scenarioContext, messageContext, dispatcher) => + return scenario.WithComponent(new SpyComponent("poison", transportConfiguration, (scenarioContext, messageContext, dispatcher, token) => { var failureDetected = 0; @@ -29,8 +28,8 @@ public static IScenarioWithEndpointBehavior WithPosionSpyComponent WithSpyComponent(this IScenarioWithEndpointBehavior scenario, string endpointName, - Action> transportConfiguration, - Func onMessage) + TransportDefinition transportConfiguration, + Func onMessage) where TContext : ScenarioContext { return scenario.WithComponent(new SpyComponent(endpointName, transportConfiguration, onMessage)); diff --git a/src/AcceptanceTesting/Infrastructure/SpyComponentRunner.cs b/src/AcceptanceTesting/Infrastructure/SpyComponentRunner.cs index d2a279e..6418460 100644 --- a/src/AcceptanceTesting/Infrastructure/SpyComponentRunner.cs +++ b/src/AcceptanceTesting/Infrastructure/SpyComponentRunner.cs @@ -1,26 +1,22 @@ using System; using System.Threading; using System.Threading.Tasks; -using NServiceBus; -using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Raw; using NServiceBus.Transport; class SpyComponentRunner : ComponentRunner { - Action> transportConfiguration; - Func onMessage; - ScenarioContext scenarioContext; + TransportDefinition transportConfiguration; + Func onMessage; string endpointName; IReceivingRawEndpoint endpoint; - public SpyComponentRunner(string endpointName, Action> transportConfiguration, - Func onMessage, ScenarioContext scenarioContext) + public SpyComponentRunner(string endpointName, TransportDefinition transportConfiguration, + Func onMessage) { this.transportConfiguration = transportConfiguration; this.onMessage = onMessage; - this.scenarioContext = scenarioContext; this.endpointName = endpointName; } @@ -28,12 +24,9 @@ public SpyComponentRunner(string endpointName, Action(scenarioContext); + var config = RawEndpointConfiguration.Create(endpointName, transportConfiguration, onMessage, "poison"); + config.AutoCreateQueues(); config.CustomErrorHandlingPolicy(new IgnoreErrorsPolicy()); - var transport = config.UseTransport(); - transportConfiguration(transport); endpoint = await RawEndpoint.Start(config); } @@ -47,7 +40,7 @@ public override Task Stop() class IgnoreErrorsPolicy : IErrorHandlingPolicy { - public Task OnError(IErrorHandlingPolicyContext handlingContext, IDispatchMessages dispatcher) + public Task OnError(IErrorHandlingPolicyContext handlingContext, IMessageDispatcher dispatcher, CancellationToken token) { return Task.FromResult(ErrorHandleResult.Handled); } diff --git a/src/AcceptanceTesting/Infrastructure/SubscriptionBehaviorExtensions.cs b/src/AcceptanceTesting/Infrastructure/SubscriptionBehaviorExtensions.cs deleted file mode 100644 index 8ece908..0000000 --- a/src/AcceptanceTesting/Infrastructure/SubscriptionBehaviorExtensions.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus; -using NServiceBus.AcceptanceTesting; -using NServiceBus.Pipeline; -using NServiceBus.Transport; - -static class SubscriptionBehaviorExtensions -{ - public static void OnEndpointSubscribed(this EndpointConfiguration configuration, Action action) where TContext : ScenarioContext - { - configuration.Pipeline.Register("NotifySubscriptionBehavior", builder => - { - var context = builder.Build(); - return new SubscriptionBehavior(action, context, MessageIntentEnum.Subscribe); - }, "Provides notifications when endpoints subscribe"); - } - - public static void OnEndpointUnsubscribed(this EndpointConfiguration configuration, Action action) where TContext : ScenarioContext - { - configuration.Pipeline.Register("NotifyUnsubscriptionBehavior", builder => - { - var context = builder.Build(); - return new SubscriptionBehavior(action, context, MessageIntentEnum.Unsubscribe); - }, "Provides notifications when endpoints unsubscribe"); - } - - class SubscriptionBehavior : IBehavior where TContext : ScenarioContext - { - public SubscriptionBehavior(Action action, TContext scenarioContext, MessageIntentEnum intentToHandle) - { - this.action = action; - this.scenarioContext = scenarioContext; - this.intentToHandle = intentToHandle; - } - - public async Task Invoke(ITransportReceiveContext context, Func next) - { - await next(context).ConfigureAwait(false); - var subscriptionMessageType = GetSubscriptionMessageTypeFrom(context.Message); - if (subscriptionMessageType != null) - { - if (!context.Message.Headers.TryGetValue(Headers.SubscriberTransportAddress, out var returnAddress)) - { - context.Message.Headers.TryGetValue(Headers.ReplyToAddress, out returnAddress); - } - - var intent = (MessageIntentEnum)Enum.Parse(typeof(MessageIntentEnum), context.Message.Headers[Headers.MessageIntent], true); - if (intent != intentToHandle) - { - return; - } - - action(new SubscriptionEventArgs - { - MessageType = subscriptionMessageType, - SubscriberReturnAddress = returnAddress - }, scenarioContext); - } - } - - static string GetSubscriptionMessageTypeFrom(IncomingMessage msg) - { - return msg.Headers.TryGetValue(Headers.SubscriptionMessageType, out var headerValue) ? headerValue : null; - } - - Action action; - TContext scenarioContext; - MessageIntentEnum intentToHandle; - } -} - -public class SubscriptionEventArgs -{ - /// - /// The address of the subscriber. - /// - public string SubscriberReturnAddress { get; set; } - - /// - /// The type of message the client subscribed to. - /// - public string MessageType { get; set; } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/SubscriptionHelper.cs b/src/AcceptanceTesting/SubscriptionHelper.cs index 8359263..e86db73 100644 --- a/src/AcceptanceTesting/SubscriptionHelper.cs +++ b/src/AcceptanceTesting/SubscriptionHelper.cs @@ -1,15 +1,14 @@ using NServiceBus.Router; -using NServiceBus.Transport; public static class SubscriptionHelper { - public static InterfaceConfiguration InMemorySubscriptions(this InterfaceConfiguration interfaceConfig) where T : TransportDefinition, new() + public static InterfaceConfiguration InMemorySubscriptions(this InterfaceConfiguration interfaceConfig) { interfaceConfig.EnableMessageDrivenPublishSubscribe(new InMemorySubscriptionStorage()); return interfaceConfig; } - public static SendOnlyInterfaceConfiguration InMemorySubscriptions(this SendOnlyInterfaceConfiguration interfaceConfig) where T : TransportDefinition, new() + public static SendOnlyInterfaceConfiguration InMemorySubscriptions(this SendOnlyInterfaceConfiguration interfaceConfig) { interfaceConfig.EnableMessageDrivenPublishSubscribe(new InMemorySubscriptionStorage()); return interfaceConfig; diff --git a/src/AcceptanceTesting/TestTransport/AsyncFile.cs b/src/AcceptanceTesting/TestTransport/AsyncFile.cs deleted file mode 100644 index 958b102..0000000 --- a/src/AcceptanceTesting/TestTransport/AsyncFile.cs +++ /dev/null @@ -1,149 +0,0 @@ -namespace NServiceBus -{ - using System.Collections.Generic; - using System.IO; - using System.Text; - using System.Threading; - using System.Threading.Tasks; - - static class AsyncFile - { - public static async Task WriteBytes(string filePath, byte[] bytes) - { - using (var stream = CreateWriteStream(filePath, FileMode.Create)) - { - await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - } - - public static async Task WriteLines(string filePath, IEnumerable lines) - { - using (var stream = CreateWriteStream(filePath, FileMode.Create)) - { - await WriteLines(stream, lines).ConfigureAwait(false); - } - } - - //write to temp file first so we can do a atomic move - public static async Task WriteTextAtomic(string targetPath, string text) - { - var tempFile = Path.GetTempFileName(); - var bytes = Encoding.UTF8.GetBytes(text); - - try - { - using (var stream = CreateWriteStream(tempFile, FileMode.Open)) - { - await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - } - catch - { - File.Delete(tempFile); - throw; - } - - File.Move(tempFile, targetPath); - } - - static async Task WriteLines(FileStream stream, IEnumerable lines) - { - using (var writer = new StreamWriter(stream)) - { - foreach (var line in lines) - { - await writer.WriteLineAsync(line).ConfigureAwait(false); - } - } - } - - static FileStream CreateWriteStream(string filePath, FileMode fileMode) - { - return new FileStream(filePath, fileMode, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true); - } - - public static Task WriteText(string filePath, string text) - { - var bytes = Encoding.UTF8.GetBytes(text); - - return WriteBytes(filePath, bytes); - } - - public static async Task ReadText(string filePath) - { - using (var stream = new StreamReader(CreateReadStream(filePath), Encoding.UTF8)) - { - var result = await stream.ReadToEndAsync().ConfigureAwait(false); - - return result; - } - } - - public static async Task ReadBytes(string filePath, CancellationToken token) - { - using (var stream = CreateReadStream(filePath)) - { - var length = (int)stream.Length; - var body = new byte[length]; - await stream.ReadAsync(body, 0, length, token).ConfigureAwait(false); - - return body; - } - } - - static FileStream CreateReadStream(string filePath) - { - return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true); - } - - public static async Task Move(string sourcePath, string targetPath) - { - try - { - File.Move(sourcePath, targetPath); - } - catch (IOException) - { - return false; - } - - var count = 0; - - while (IsFileLocked(targetPath)) - { - await Task.Delay(100).ConfigureAwait(false); - - count++; - - if (count > 10) - { - break; - } - } - - return true; - } - - static bool IsFileLocked(string filePath) - { - try - { - using (File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None)) - { - //no-op - } - } - catch (IOException) - { - //the file is unavailable because it is: - //still being written to - //or being processed by another thread - //or does not exist (has already been processed) - return true; - } - - //file is not locked - return false; - } - } -} diff --git a/src/AcceptanceTesting/TestTransport/AsyncTimer.cs b/src/AcceptanceTesting/TestTransport/AsyncTimer.cs deleted file mode 100644 index a7d4c68..0000000 --- a/src/AcceptanceTesting/TestTransport/AsyncTimer.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.Threading; - using System.Threading.Tasks; - - class AsyncTimer - { - public void Start(Func callback, TimeSpan interval, Action errorCallback) - { - tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - - task = Task.Run(async () => - { - while (!token.IsCancellationRequested) - { - try - { - await Task.Delay(interval, token).ConfigureAwait(false); - await callback().ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // no-op - } - catch (Exception ex) - { - errorCallback(ex); - } - } - }, CancellationToken.None); - } - - public Task Stop() - { - if (tokenSource == null) - { - return Task.CompletedTask; - } - - tokenSource.Cancel(); - tokenSource.Dispose(); - - return task ?? Task.CompletedTask; - } - - Task task; - CancellationTokenSource tokenSource; - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/DelayedMessagePoller.cs b/src/AcceptanceTesting/TestTransport/DelayedMessagePoller.cs deleted file mode 100644 index eb95ed8..0000000 --- a/src/AcceptanceTesting/TestTransport/DelayedMessagePoller.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.Globalization; - using System.IO; - using System.Threading.Tasks; - using Logging; - - class DelayedMessagePoller - { - public DelayedMessagePoller(string basePath, string delayedDir) - { - this.basePath = basePath; - timer = new AsyncTimer(); - - delayedRootDirectory = delayedDir; - } - - void MoveDelayedMessagesToMainDirectory() - { - foreach (var delayDir in new DirectoryInfo(delayedRootDirectory).EnumerateDirectories()) - { - var timeToTrigger = DateTime.ParseExact(delayDir.Name, "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); - - if (DateTime.UtcNow >= timeToTrigger) - { - foreach (var fileInfo in delayDir.EnumerateFiles()) - { - File.Move(fileInfo.FullName, Path.Combine(basePath, fileInfo.Name)); - } - } - - //wait a bit more so we can safely delete the dir - if (DateTime.UtcNow >= timeToTrigger.AddSeconds(10)) - { - Directory.Delete(delayDir.FullName); - } - } - } - - public void Start() - { - timer.Start(() => - { - MoveDelayedMessagesToMainDirectory(); - - return Task.CompletedTask; - }, - TimeSpan.FromSeconds(1), - ex => Logger.Error("Unable to move expired messages to main input queue.", ex)); - } - - public Task Stop() - { - return timer.Stop(); - } - - string delayedRootDirectory; - AsyncTimer timer; - string basePath; - - static ILog Logger = LogManager.GetLogger(); - } -} diff --git a/src/AcceptanceTesting/TestTransport/DeliveryConstraintExtensions.cs b/src/AcceptanceTesting/TestTransport/DeliveryConstraintExtensions.cs deleted file mode 100644 index bc41dd6..0000000 --- a/src/AcceptanceTesting/TestTransport/DeliveryConstraintExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace NServiceBus -{ - using System.Collections.Generic; - using System.Linq; - using DeliveryConstraints; - - static class DeliveryConstraintExtensions - { - internal static bool TryGet(this List list, out T constraint) where T : DeliveryConstraint - { - constraint = list.OfType().FirstOrDefault(); - - return constraint != null; - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/DirectoryBasedTransaction.cs b/src/AcceptanceTesting/TestTransport/DirectoryBasedTransaction.cs deleted file mode 100644 index 592ff75..0000000 --- a/src/AcceptanceTesting/TestTransport/DirectoryBasedTransaction.cs +++ /dev/null @@ -1,153 +0,0 @@ -namespace NServiceBus -{ - using System.Collections.Concurrent; - using System.IO; - using System.Threading.Tasks; - using Logging; - - class DirectoryBasedTransaction : ITestTransportTransaction - { - public DirectoryBasedTransaction(string basePath, string pendingDirName, string committedDirName, string transactionId) - { - this.basePath = basePath; - - transactionDir = Path.Combine(basePath, pendingDirName, transactionId); - commitDir = Path.Combine(basePath, committedDirName, transactionId); - } - - public string FileToProcess { get; private set; } - - public Task BeginTransaction(string incomingFilePath) - { - Directory.CreateDirectory(transactionDir); - FileToProcess = Path.Combine(transactionDir, Path.GetFileName(incomingFilePath)); - - return AsyncFile.Move(incomingFilePath, FileToProcess); - } - - public Task Commit() - { - Directory.Move(transactionDir, commitDir); - committed = true; - - return Task.CompletedTask; - } - - public void Rollback() - { - //rollback by moving the file back to the main dir - File.Move(FileToProcess, Path.Combine(basePath, Path.GetFileName(FileToProcess))); - Directory.Delete(transactionDir, true); - } - - public void ClearPendingOutgoingOperations() - { - while (outgoingFiles.TryDequeue(out _)) { } - } - - public Task Enlist(string messagePath, string messageContents) - { - var inProgressFileName = Path.GetFileNameWithoutExtension(messagePath) + ".out"; - - var txPath = Path.Combine(transactionDir, inProgressFileName); - var committedPath = Path.Combine(commitDir, inProgressFileName); - - outgoingFiles.Enqueue(new OutgoingFile(committedPath, messagePath)); - - return AsyncFile.WriteText(txPath, messageContents); - } - - public bool Complete() - { - if (!committed) - { - return false; - } - - while (outgoingFiles.TryDequeue(out var outgoingFile)) - { - File.Move(outgoingFile.TxPath, outgoingFile.TargetPath); - } - - Directory.Delete(commitDir, true); - - return true; - } - - public static void RecoverPartiallyCompletedTransactions(string basePath, string pendingDirName, string committedDirName) - { - var pendingRootDir = Path.Combine(basePath, pendingDirName); - - if (Directory.Exists(pendingRootDir)) - { - foreach (var transactionDir in new DirectoryInfo(pendingRootDir).EnumerateDirectories()) - { - new DirectoryBasedTransaction(basePath, pendingDirName, committedDirName, transactionDir.Name) - .RecoverPending(); - } - } - - var committedRootDir = Path.Combine(basePath, committedDirName); - - if (Directory.Exists(committedRootDir)) - { - foreach (var transactionDir in new DirectoryInfo(committedRootDir).EnumerateDirectories()) - { - new DirectoryBasedTransaction(basePath, pendingDirName, committedDirName, transactionDir.Name) - .RecoverCommitted(); - } - } - } - - void RecoverPending() - { - var pendingDir = new DirectoryInfo(transactionDir); - - //only need to move the incoming file - foreach (var file in pendingDir.EnumerateFiles(TxtFileExtension)) - { - File.Move(file.FullName, Path.Combine(basePath, file.Name)); - } - - pendingDir.Delete(true); - } - - void RecoverCommitted() - { - var committedDir = new DirectoryInfo(commitDir); - - //for now just rollback the completed ones as well. We could consider making this smarter in the future - // but its good enough for now since duplicates is a possibility anyway - foreach (var file in committedDir.EnumerateFiles(TxtFileExtension)) - { - File.Move(file.FullName, Path.Combine(basePath, file.Name)); - } - - committedDir.Delete(true); - } - - string basePath; - string commitDir; - - bool committed; - - ConcurrentQueue outgoingFiles = new ConcurrentQueue(); - string transactionDir; - - const string TxtFileExtension = "*.txt"; - - static ILog log = LogManager.GetLogger(); - - class OutgoingFile - { - public OutgoingFile(string txPath, string targetPath) - { - TxPath = txPath; - TargetPath = targetPath; - } - - public string TxPath { get; } - public string TargetPath { get; } - } - } -} diff --git a/src/AcceptanceTesting/TestTransport/HeaderSerializer.cs b/src/AcceptanceTesting/TestTransport/HeaderSerializer.cs deleted file mode 100644 index 50262fe..0000000 --- a/src/AcceptanceTesting/TestTransport/HeaderSerializer.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace NServiceBus -{ - using System.Collections.Generic; - using System.IO; - using System.Runtime.Serialization.Json; - using System.Text; - - static class HeaderSerializer - { - public static string Serialize(Dictionary dictionary) - { - using (var stream = new MemoryStream()) - { - using (var writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, true, true, " ")) - { - serializer.WriteObject(writer, dictionary); - writer.Flush(); - } - - return Encoding.UTF8.GetString(stream.ToArray()); - } - } - - public static Dictionary Deserialize(string value) - { - using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(value))) - { - return (Dictionary)serializer.ReadObject(ms); - } - } - - static DataContractJsonSerializer serializer = new DataContractJsonSerializer( - type: typeof(Dictionary), - settings: new DataContractJsonSerializerSettings - { - UseSimpleDictionaryFormat = true - }); - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/ITestTransportTransaction.cs b/src/AcceptanceTesting/TestTransport/ITestTransportTransaction.cs deleted file mode 100644 index ae6283d..0000000 --- a/src/AcceptanceTesting/TestTransport/ITestTransportTransaction.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace NServiceBus -{ - using System.Threading.Tasks; - - interface ITestTransportTransaction - { - string FileToProcess { get; } - - Task BeginTransaction(string incomingFilePath); - - Task Commit(); - - void Rollback(); - - void ClearPendingOutgoingOperations(); - - Task Enlist(string messagePath, string messageContents); - - bool Complete(); - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/NoTransaction.cs b/src/AcceptanceTesting/TestTransport/NoTransaction.cs deleted file mode 100644 index ed3898a..0000000 --- a/src/AcceptanceTesting/TestTransport/NoTransaction.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.IO; - using System.Threading.Tasks; - - class NoTransaction : ITestTransportTransaction - { - public NoTransaction(string basePath, string pendingDirName) - { - processingDirectory = Path.Combine(basePath, pendingDirName, Guid.NewGuid().ToString()); - } - - public string FileToProcess { get; private set; } - - public Task BeginTransaction(string incomingFilePath) - { - Directory.CreateDirectory(processingDirectory); - FileToProcess = Path.Combine(processingDirectory, Path.GetFileName(incomingFilePath)); - - return AsyncFile.Move(incomingFilePath, FileToProcess); - } - - public Task Enlist(string messagePath, string messageContents) => AsyncFile.WriteText(messagePath, messageContents); - - public Task Commit() => Task.CompletedTask; - - public void Rollback() { } - - public void ClearPendingOutgoingOperations() { } - - public bool Complete() - { - Directory.Delete(processingDirectory, true); - - return true; - } - - string processingDirectory; - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/PathChecker.cs b/src/AcceptanceTesting/TestTransport/PathChecker.cs deleted file mode 100644 index 3aef0fd..0000000 --- a/src/AcceptanceTesting/TestTransport/PathChecker.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.IO; - - static class PathChecker - { - public static void ThrowForBadPath(string value, string valueName) - { - var invalidPathChars = Path.GetInvalidPathChars(); - - if (string.IsNullOrEmpty(value)) - { - return; - } - - if (value.IndexOfAny(invalidPathChars) < 0) - { - return; - } - - throw new Exception($"The value for '{valueName}' has illegal path characters. Provided value: {value}. Must not contain any of {string.Join(", ", invalidPathChars)}."); - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TaskEx.cs b/src/AcceptanceTesting/TestTransport/TaskEx.cs deleted file mode 100644 index 022a657..0000000 --- a/src/AcceptanceTesting/TestTransport/TaskEx.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace NServiceBus -{ - using System.Threading.Tasks; - - static class TaskEx - { - // ReSharper disable once UnusedParameter.Global - // Used to explicitly suppress the compiler warning about - // using the returned value from async operations - public static void Ignore(this Task task) - { - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TestTransport.cs b/src/AcceptanceTesting/TestTransport/TestTransport.cs deleted file mode 100644 index acd57fa..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransport.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace NServiceBus -{ - using Routing; - using Settings; - using Transport; - - /// - /// A transport optimized for development and learning use. DO NOT use in production. - /// - public class TestTransport : TransportDefinition, IMessageDrivenSubscriptionTransport - { - /// - /// Used by implementations to control if a connection string is necessary. - /// - public override bool RequiresConnectionString => false; - - /// - /// Gets an example connection string to use when reporting the lack of a configured connection string to the user. - /// - public override string ExampleConnectionStringForErrorMessage { get; } = ""; - - /// - /// Initializes all the factories and supported features for the transport. This method is called right before all features - /// are activated and the settings will be locked down. This means you can use the SettingsHolder both for providing - /// default capabilities as well as for initializing the transport's configuration based on those settings (the user cannot - /// provide information anymore at this stage). - /// - /// An instance of the current settings. - /// The connection string. - /// The supported factories. - public override TransportInfrastructure Initialize(SettingsHolder settings, string connectionString) - { - return new TestTransportInfrastructure(settings); - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TestTransportConfigurationExtensions.cs b/src/AcceptanceTesting/TestTransport/TestTransportConfigurationExtensions.cs deleted file mode 100644 index 1cb1ea8..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportConfigurationExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace NServiceBus -{ - using Configuration.AdvancedExtensibility; - - /// - /// Configuration options for the learning transport. - /// - public static class TestTransportConfigurationExtensions - { - public static void BrokerName(this TransportExtensions transportExtensions, string brokerName) - { - transportExtensions.GetSettings().Set(TestTransportInfrastructure.BrokerNameKey, brokerName); - } - - /// - /// Configures the location where message files are stored. - /// - /// The transport extensions to extend. - /// The storage path. - public static void StorageDirectory(this TransportExtensions transportExtensions, string path) - { - PathChecker.ThrowForBadPath(path, "StorageDirectory"); - - transportExtensions.GetSettings().Set(TestTransportInfrastructure.StorageLocationKey, path); - } - - /// - /// Allows messages of any size to be sent. - /// - /// The transport extensions to extend. - public static void NoPayloadSizeRestriction(this TransportExtensions transportExtensions) - { - transportExtensions.GetSettings().Set(TestTransportInfrastructure.NoPayloadSizeRestrictionKey, true); - } - - /// - /// Disables native pub/sub - /// - /// - public static void NoNativePubSub(this TransportExtensions transportExtensions) - { - transportExtensions.GetSettings().Set(TestTransportInfrastructure.NoNativePubSub, true); - } - } -} diff --git a/src/AcceptanceTesting/TestTransport/TestTransportDispatcher.cs b/src/AcceptanceTesting/TestTransport/TestTransportDispatcher.cs deleted file mode 100644 index f2167c0..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportDispatcher.cs +++ /dev/null @@ -1,244 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using AcceptanceTesting; - using DelayedDelivery; - using Extensibility; - using Performance.TimeToBeReceived; - using Transport; - using Unicast.Queuing; - - class TestTransportDispatcher : IDispatchMessages - { - public TestTransportDispatcher(string basePath, int maxMessageSizeKB, string brokerName, ScenarioContext scenarioContext) - { - if (maxMessageSizeKB > int.MaxValue / 1024) - { - throw new ArgumentException("The message size cannot be larger than int.MaxValue / 1024.", nameof(maxMessageSizeKB)); - } - - this.basePath = basePath; - this.maxMessageSizeKB = maxMessageSizeKB; - this.brokerName = brokerName; - } - - public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context) - { - return Task.WhenAll( - DispatchUnicast(outgoingMessages.UnicastTransportOperations, transaction), - DispatchMulticast(outgoingMessages.MulticastTransportOperations, transaction)); - } - - async Task DispatchMulticast(IEnumerable transportOperations, TransportTransaction transaction) - { - var tasks = new List(); - - foreach (var transportOperation in transportOperations) - { - if (!transportOperation.Message.Headers.TryGetValue(Headers.MessageId, out var messageId)) - { - messageId = transportOperation.Message.MessageId; - } - - if (!transportOperation.Message.Headers.TryGetValue(Headers.MessageIntent, out var intent)) - { - intent = ""; - } - - var subscribers = await GetSubscribersFor(transportOperation.MessageType) - .ConfigureAwait(false); - - foreach (var subscriber in subscribers) - { - tasks.Add(WriteMessage(subscriber, transportOperation, transaction)); - Console.WriteLine($"Publishing message {messageId} with intent {intent} sent to {subscriber}"); - } - } - - await Task.WhenAll(tasks) - .ConfigureAwait(false); - } - - Task DispatchUnicast(IEnumerable operations, TransportTransaction transaction) - { - return Task.WhenAll(operations.Select(operation => - { - PathChecker.ThrowForBadPath(operation.Destination, "message destination"); - - if (!operation.Message.Headers.TryGetValue(Headers.MessageId, out var messageId)) - { - messageId = operation.Message.MessageId; - } - - if (!operation.Message.Headers.TryGetValue(Headers.MessageIntent, out var intent)) - { - intent = ""; - } - Console.WriteLine($"Sending message {messageId} with intent {intent} sent to {operation.Destination}"); - - return WriteMessage(operation.Destination, operation, transaction); - })); - } - - async Task WriteMessage(string destination, IOutgoingTransportOperation transportOperation, TransportTransaction transaction) - { - var message = transportOperation.Message; - - if (destination.IndexOf("@", StringComparison.Ordinal) != -1) - { - var parts = destination.Split(new[] {'@'}, StringSplitOptions.RemoveEmptyEntries); - - var broker = parts[1]; - - if (broker != brokerName) - { - throw new Exception($"Attempt to send a message to broker {broker} through transport configured for {brokerName}."); - } - } - else - { - //Default to sending to local broker - destination = $"{destination}@{brokerName}"; - } - - var nativeMessageId = Guid.NewGuid().ToString(); - var destinationPath = Path.Combine(basePath, destination); - - if (!Directory.Exists(destinationPath)) - { - throw new QueueNotFoundException(destination, "Destination queue does not exist.", null); - } - - var bodyDir = Path.Combine(destinationPath, TestTransportMessagePump.BodyDirName); - - Directory.CreateDirectory(bodyDir); - - var bodyPath = Path.Combine(bodyDir, nativeMessageId) + TestTransportMessagePump.BodyFileSuffix; - - await AsyncFile.WriteBytes(bodyPath, message.Body) - .ConfigureAwait(false); - - DateTime? timeToDeliver = null; - - if (transportOperation.DeliveryConstraints.TryGet(out DoNotDeliverBefore doNotDeliverBefore)) - { - timeToDeliver = doNotDeliverBefore.At; - } - else if (transportOperation.DeliveryConstraints.TryGet(out DelayDeliveryWith delayDeliveryWith)) - { - timeToDeliver = DateTime.UtcNow + delayDeliveryWith.Delay; - } - - if (timeToDeliver.HasValue) - { - // we need to "ceil" the seconds to guarantee that we delay with at least the requested value - // since the folder name has only second resolution. - if (timeToDeliver.Value.Millisecond > 0) - { - timeToDeliver += TimeSpan.FromSeconds(1); - } - - destinationPath = Path.Combine(destinationPath, TestTransportMessagePump.DelayedDirName, timeToDeliver.Value.ToString("yyyyMMddHHmmss")); - - Directory.CreateDirectory(destinationPath); - } - - if (transportOperation.DeliveryConstraints.TryGet(out DiscardIfNotReceivedBefore timeToBeReceived) && timeToBeReceived.MaxTime < TimeSpan.MaxValue) - { - if (timeToDeliver.HasValue) - { - throw new Exception($"Postponed delivery of messages with TimeToBeReceived set is not supported. Remove the TimeToBeReceived attribute to postpone messages of type '{message.Headers[Headers.EnclosedMessageTypes]}'."); - } - - message.Headers[TestTransportHeaders.TimeToBeReceived] = timeToBeReceived.MaxTime.ToString(); - } - - var messagePath = Path.Combine(destinationPath, nativeMessageId) + ".metadata.txt"; - - var headerPayload = HeaderSerializer.Serialize(message.Headers); - var headerSize = Encoding.UTF8.GetByteCount(headerPayload); - - if (headerSize + message.Body.Length > maxMessageSizeKB * 1024) - { - throw new Exception($"The total size of the '{message.Headers[Headers.EnclosedMessageTypes]}' message body ({message.Body.Length} bytes) plus headers ({headerSize} bytes) is larger than {maxMessageSizeKB} KB and will not be supported on some production transports. Consider using the NServiceBus DataBus or the claim check pattern to avoid messages with a large payload. Use 'EndpointConfiguration.UseTransport().NoPayloadSizeRestriction()' to disable this check and proceed with the current message size."); - } - - if (transportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated && transaction.TryGet(out ITestTransportTransaction directoryBasedTransaction)) - { - await directoryBasedTransaction.Enlist(messagePath, headerPayload) - .ConfigureAwait(false); - } - else - { - // atomic avoids the file being locked when the receiver tries to process it - await AsyncFile.WriteTextAtomic(messagePath, headerPayload) - .ConfigureAwait(false); - } - } - - async Task> GetSubscribersFor(Type messageType) - { - var subscribers = new HashSet(); - - var allEventTypes = GetPotentialEventTypes(messageType); - - foreach (var eventType in allEventTypes) - { - var eventDir = Path.Combine(basePath, ".events", eventType.FullName); - - if (!Directory.Exists(eventDir)) - { - continue; - } - - foreach (var file in Directory.GetFiles(eventDir)) - { - var allText = await AsyncFile.ReadText(file) - .ConfigureAwait(false); - - subscribers.Add(allText); - } - } - - return subscribers; - } - - static IEnumerable GetPotentialEventTypes(Type messageType) - { - var allEventTypes = new HashSet(); - - var currentType = messageType; - - while (currentType != null) - { - //do not include the marker interfaces - if (IsCoreMarkerInterface(currentType)) - { - break; - } - - allEventTypes.Add(currentType); - - currentType = currentType.BaseType; - } - - foreach (var type in messageType.GetInterfaces().Where(i => !IsCoreMarkerInterface(i))) - { - allEventTypes.Add(type); - } - - return allEventTypes; - } - - static bool IsCoreMarkerInterface(Type type) => type == typeof(IMessage) || type == typeof(IEvent) || type == typeof(ICommand); - - int maxMessageSizeKB; - string brokerName; - string basePath; - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TestTransportHeaders.cs b/src/AcceptanceTesting/TestTransport/TestTransportHeaders.cs deleted file mode 100644 index 2e98502..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportHeaders.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace NServiceBus -{ - static class TestTransportHeaders - { - public const string TimeToBeReceived = "NServiceBus.Transport.Test.TimeToBeReceived"; - } -} diff --git a/src/AcceptanceTesting/TestTransport/TestTransportInfrastructure.cs b/src/AcceptanceTesting/TestTransport/TestTransportInfrastructure.cs deleted file mode 100644 index 5e2aa93..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportInfrastructure.cs +++ /dev/null @@ -1,137 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Threading.Tasks; - using AcceptanceTesting; - using DelayedDelivery; - using Performance.TimeToBeReceived; - using Routing; - using Settings; - using Transport; - - class TestTransportInfrastructure : TransportInfrastructure - { - public TestTransportInfrastructure(SettingsHolder settings) - { - this.settings = settings; - - if (!settings.TryGet(StorageLocationKey, out storagePath)) - { - var solutionRoot = FindSolutionRoot(); - storagePath = Path.Combine(solutionRoot, ".learningtransport"); - } - - brokerName = settings.GetOrDefault(BrokerNameKey) ?? ""; - - var errorQueueAddress = settings.ErrorQueueAddress(); - PathChecker.ThrowForBadPath(errorQueueAddress, "ErrorQueueAddress"); - - OutboundRoutingPolicy = settings.GetOrDefault(NoNativePubSub) - ? new OutboundRoutingPolicy(OutboundRoutingType.Unicast, OutboundRoutingType.Unicast, OutboundRoutingType.Unicast) - : new OutboundRoutingPolicy(OutboundRoutingType.Unicast, OutboundRoutingType.Multicast, OutboundRoutingType.Unicast); - } - - public override IEnumerable DeliveryConstraints { get; } = new[] - { - typeof(DiscardIfNotReceivedBefore), - typeof(DelayDeliveryWith), - typeof(DoNotDeliverBefore) - }; - - public override TransportTransactionMode TransactionMode => TransportTransactionMode.ReceiveOnly; - - public override OutboundRoutingPolicy OutboundRoutingPolicy { get; } - - string FindSolutionRoot() - { - var directory = AppDomain.CurrentDomain.BaseDirectory; - - while (true) - { - if (Directory.EnumerateFiles(directory).Any(file => file.EndsWith(".sln"))) - { - return directory; - } - - var parent = Directory.GetParent(directory); - - if (parent == null) - { - // throw for now. if we discover there is an edge then we can fix it in a patch. - throw new Exception("Couldn't find the solution directory for the learning transport. If the endpoint is outside the solution folder structure, make sure to specify a storage directory using the 'EndpointConfiguration.UseTransport().StorageDirectory()' API."); - } - - directory = parent.FullName; - } - } - - public override TransportReceiveInfrastructure ConfigureReceiveInfrastructure() - { - return new TransportReceiveInfrastructure(() => new TestTransportMessagePump(storagePath), - () => new TestTransportQueueCreator(storagePath), () => Task.FromResult(StartupCheckResult.Success)); - } - - public override TransportSendInfrastructure ConfigureSendInfrastructure() - { - var maxPayloadSize = settings.GetOrDefault(NoPayloadSizeRestrictionKey) ? int.MaxValue / 1024 : 64; //64 kB is the max size of the ASQ transport - - //var scenarioContext = settings.Get(); - - return new TransportSendInfrastructure(() => new TestTransportDispatcher(storagePath, maxPayloadSize, brokerName, null), () => Task.FromResult(StartupCheckResult.Success)); - } - - public override TransportSubscriptionInfrastructure ConfigureSubscriptionInfrastructure() - { - return new TransportSubscriptionInfrastructure(() => - { - var endpointName = settings.EndpointName(); - PathChecker.ThrowForBadPath(endpointName, "endpoint name"); - - var localAddress = settings.LocalAddress(); - PathChecker.ThrowForBadPath(localAddress, "localAddress"); - - return new TestTransportSubscriptionManager(storagePath, endpointName, localAddress); - }); - } - - public override EndpointInstance BindToLocalEndpoint(EndpointInstance instance) => instance; - - public override string ToTransportAddress(LogicalAddress logicalAddress) - { - var address = logicalAddress.EndpointInstance.Endpoint; - PathChecker.ThrowForBadPath(address, "endpoint name"); - - var discriminator = logicalAddress.EndpointInstance.Discriminator; - - if (!string.IsNullOrEmpty(discriminator)) - { - PathChecker.ThrowForBadPath(discriminator, "endpoint discriminator"); - - address += "-" + discriminator; - } - - var qualifier = logicalAddress.Qualifier; - - if (!string.IsNullOrEmpty(qualifier)) - { - PathChecker.ThrowForBadPath(qualifier, "address qualifier"); - - address += "-" + qualifier; - } - - return $"{address}@{brokerName}"; - } - - string storagePath; - SettingsHolder settings; - string brokerName; - - public const string StorageLocationKey = "TestTransport.StoragePath"; - public const string BrokerNameKey = "TestTransport.BrokerNameKey"; - public const string NoPayloadSizeRestrictionKey = "TestTransport.NoPayloadSizeRestrictionKey"; - public const string NoNativePubSub = "TestTransport.NoNativePubSub"; - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TestTransportMessagePump.cs b/src/AcceptanceTesting/TestTransport/TestTransportMessagePump.cs deleted file mode 100644 index 16cdeae..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportMessagePump.cs +++ /dev/null @@ -1,346 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.Collections.Concurrent; - using System.Diagnostics; - using System.IO; - using System.Threading; - using System.Threading.Tasks; - using Extensibility; - using Logging; - using Transport; - - class TestTransportMessagePump : IPushMessages - { - public TestTransportMessagePump(string basePath) - { - this.basePath = basePath; - } - - public Task Init(Func onMessage, Func> onError, CriticalError criticalError, PushSettings settings) - { - this.onMessage = onMessage; - this.onError = onError; - this.criticalError = criticalError; - - transactionMode = settings.RequiredTransactionMode; - - PathChecker.ThrowForBadPath(settings.InputQueue, "InputQueue"); - - messagePumpBasePath = Path.Combine(basePath, settings.InputQueue); - bodyDir = Path.Combine(messagePumpBasePath, BodyDirName); - delayedDir = Path.Combine(messagePumpBasePath, DelayedDirName); - - pendingTransactionDir = Path.Combine(messagePumpBasePath, PendingDirName); - committedTransactionDir = Path.Combine(messagePumpBasePath, CommittedDirName); - - if (settings.PurgeOnStartup) - { - if (Directory.Exists(messagePumpBasePath)) - { - Directory.Delete(messagePumpBasePath, true); - } - } - - delayedMessagePoller = new DelayedMessagePoller(messagePumpBasePath, delayedDir); - - return Task.CompletedTask; - } - - public void Start(PushRuntimeSettings limitations) - { - maxConcurrency = limitations.MaxConcurrency; - concurrencyLimiter = new SemaphoreSlim(maxConcurrency); - cancellationTokenSource = new CancellationTokenSource(); - - cancellationToken = cancellationTokenSource.Token; - - RecoverPendingTransactions(); - - EnsureDirectoriesExists(); - - messagePumpTask = Task.Run(ProcessMessages, cancellationToken); - - delayedMessagePoller.Start(); - } - - public async Task Stop() - { - cancellationTokenSource.Cancel(); - - await delayedMessagePoller.Stop() - .ConfigureAwait(false); - - await messagePumpTask - .ConfigureAwait(false); - - while (concurrencyLimiter.CurrentCount != maxConcurrency) - { - await Task.Delay(50, CancellationToken.None) - .ConfigureAwait(false); - } - - concurrencyLimiter.Dispose(); - } - - void RecoverPendingTransactions() - { - if (transactionMode != TransportTransactionMode.None) - { - DirectoryBasedTransaction.RecoverPartiallyCompletedTransactions(messagePumpBasePath, PendingDirName, CommittedDirName); - } - else - { - if (Directory.Exists(pendingTransactionDir)) - { - Directory.Delete(pendingTransactionDir, true); - } - } - } - - void EnsureDirectoriesExists() - { - Directory.CreateDirectory(messagePumpBasePath); - Directory.CreateDirectory(bodyDir); - Directory.CreateDirectory(delayedDir); - Directory.CreateDirectory(pendingTransactionDir); - - if (transactionMode != TransportTransactionMode.None) - { - Directory.CreateDirectory(committedTransactionDir); - } - } - - [DebuggerNonUserCode] - async Task ProcessMessages() - { - while (!cancellationToken.IsCancellationRequested) - { - try - { - await InnerProcessMessages() - .ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // graceful shutdown - } - catch (Exception ex) - { - criticalError.Raise("Failure to process messages", ex); - } - } - } - - async Task InnerProcessMessages() - { - log.Debug($"Started polling for new messages in {messagePumpBasePath}"); - - while (!cancellationToken.IsCancellationRequested) - { - var filesFound = false; - - foreach (var filePath in Directory.EnumerateFiles(messagePumpBasePath, "*.*")) - { - filesFound = true; - - var nativeMessageId = Path.GetFileNameWithoutExtension(filePath).Replace(".metadata", ""); - - await concurrencyLimiter.WaitAsync(cancellationToken) - .ConfigureAwait(false); - - ITestTransportTransaction transaction; - - try - { - transaction = GetTransaction(); - - var ableToLockFile = await transaction.BeginTransaction(filePath).ConfigureAwait(false); - - if (!ableToLockFile) - { - log.Debug($"Unable to lock file {filePath}({transaction.FileToProcess})"); - concurrencyLimiter.Release(); - continue; - } - } - catch (Exception ex) - { - log.Debug($"Failed to begin transaction {filePath}", ex); - - concurrencyLimiter.Release(); - throw; - } - - ProcessFile(transaction, nativeMessageId) - .ContinueWith(t => - { - try - { - if (log.IsDebugEnabled) - { - log.Debug($"Completing processing for {filePath}({transaction.FileToProcess}), exception (if any): {t.Exception}"); - } - - var wasCommitted = transaction.Complete(); - - if (wasCommitted) - { - File.Delete(Path.Combine(bodyDir, nativeMessageId + BodyFileSuffix)); - } - - if (t.Exception != null) - { - var baseEx = t.Exception.GetBaseException(); - - if (!(baseEx is OperationCanceledException)) - { - criticalError.Raise($"Failed to process {filePath}({transaction.FileToProcess})", baseEx); - } - } - } - catch (Exception ex) - { - criticalError.Raise($"Failure while trying to complete receive transaction for {filePath}({transaction.FileToProcess})" + filePath, ex); - } - finally - { - concurrencyLimiter.Release(); - } - }, CancellationToken.None) - .Ignore(); - } - - if (!filesFound) - { - await Task.Delay(10, cancellationToken).ConfigureAwait(false); - } - } - } - - ITestTransportTransaction GetTransaction() - { - if (transactionMode == TransportTransactionMode.None) - { - return new NoTransaction(messagePumpBasePath, PendingDirName); - } - - return new DirectoryBasedTransaction(messagePumpBasePath, PendingDirName, CommittedDirName, Guid.NewGuid().ToString()); - } - - async Task ProcessFile(ITestTransportTransaction transaction, string messageId) - { - var message = await AsyncFile.ReadText(transaction.FileToProcess) - .ConfigureAwait(false); - - var bodyPath = Path.Combine(bodyDir, $"{messageId}{BodyFileSuffix}"); - var headers = HeaderSerializer.Deserialize(message); - - if (headers.TryGetValue(TestTransportHeaders.TimeToBeReceived, out var ttbrString)) - { - headers.Remove(TestTransportHeaders.TimeToBeReceived); - - var ttbr = TimeSpan.Parse(ttbrString); - - //file.move preserves create time - var sentTime = File.GetCreationTimeUtc(transaction.FileToProcess); - - var utcNow = DateTime.UtcNow; - if (sentTime + ttbr < utcNow) - { - await transaction.Commit() - .ConfigureAwait(false); - log.InfoFormat("Dropping message '{0}' as the specified TimeToBeReceived of '{1}' expired since sending the message at '{2:O}'. Current UTC time is '{3:O}'", messageId, ttbrString, sentTime, utcNow); - return; - } - } - - var tokenSource = new CancellationTokenSource(); - - var body = await AsyncFile.ReadBytes(bodyPath, cancellationToken) - .ConfigureAwait(false); - - var transportTransaction = new TransportTransaction(); - - if (transactionMode == TransportTransactionMode.SendsAtomicWithReceive) - { - transportTransaction.Set(transaction); - } - - var messageContext = new MessageContext(messageId, headers, body, transportTransaction, tokenSource, new ContextBag()); - - try - { - await onMessage(messageContext) - .ConfigureAwait(false); - } - catch (Exception exception) - { - transaction.ClearPendingOutgoingOperations(); - var processingFailures = retryCounts.AddOrUpdate(messageId, id => 1, (id, currentCount) => currentCount + 1); - - var errorContext = new ErrorContext(exception, headers, messageId, body, transportTransaction, processingFailures); - - // the transport tests assume that all transports use a circuit breaker to be resilient against exceptions - // in onError. Since we don't need that robustness, we just retry onError once should it fail. - ErrorHandleResult actionToTake; - try - { - actionToTake = await onError(errorContext) - .ConfigureAwait(false); - } - catch (Exception) - { - actionToTake = await onError(errorContext) - .ConfigureAwait(false); - } - - if (actionToTake == ErrorHandleResult.RetryRequired) - { - transaction.Rollback(); - - return; - } - } - - if (tokenSource.IsCancellationRequested) - { - transaction.Rollback(); - - return; - } - - await transaction.Commit() - .ConfigureAwait(false); - } - - CancellationToken cancellationToken; - CancellationTokenSource cancellationTokenSource; - SemaphoreSlim concurrencyLimiter; - Task messagePumpTask; - Func onMessage; - Func> onError; - ConcurrentDictionary retryCounts = new ConcurrentDictionary(); - string messagePumpBasePath; - string basePath; - DelayedMessagePoller delayedMessagePoller; - TransportTransactionMode transactionMode; - int maxConcurrency; - string bodyDir; - string pendingTransactionDir; - string committedTransactionDir; - string delayedDir; - - CriticalError criticalError; - - - static ILog log = LogManager.GetLogger(); - - public const string BodyFileSuffix = ".body.txt"; - public const string BodyDirName = ".bodies"; - public const string DelayedDirName = ".delayed"; - - const string CommittedDirName = ".committed"; - const string PendingDirName = ".pending"; - } -} diff --git a/src/AcceptanceTesting/TestTransport/TestTransportQueueCreator.cs b/src/AcceptanceTesting/TestTransport/TestTransportQueueCreator.cs deleted file mode 100644 index 17faaad..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportQueueCreator.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace NServiceBus -{ - using System.IO; - using System.Threading.Tasks; - using Transport; - - class TestTransportQueueCreator : ICreateQueues - { - readonly string storagePath; - - public TestTransportQueueCreator(string storagePath) - { - this.storagePath = storagePath; - } - - public Task CreateQueueIfNecessary(QueueBindings queueBindings, string identity) - { - foreach (var queueBinding in queueBindings.ReceivingAddresses) - { - var queuePath = Path.Combine(storagePath, queueBinding); - Directory.CreateDirectory(queuePath); - } - - foreach (var queueBinding in queueBindings.SendingAddresses) - { - var queuePath = Path.Combine(storagePath, queueBinding); - Directory.CreateDirectory(queuePath); - } - - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/AcceptanceTesting/TestTransport/TestTransportSubscriptionManager.cs b/src/AcceptanceTesting/TestTransport/TestTransportSubscriptionManager.cs deleted file mode 100644 index d007a59..0000000 --- a/src/AcceptanceTesting/TestTransport/TestTransportSubscriptionManager.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace NServiceBus -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Extensibility; - using Transport; - - class TestTransportSubscriptionManager : IManageSubscriptions - { - public TestTransportSubscriptionManager(string basePath, string endpointName, string localAddress) - { - this.endpointName = endpointName; - this.localAddress = localAddress; - this.basePath = Path.Combine(basePath, ".events"); - } - - public async Task Subscribe(Type eventType, ContextBag context) - { - var eventDir = GetEventDirectory(eventType); - - // that way we can detect that there is indeed a publisher for the event. That said it also means that we will have do "retries" here due to race condition. - Directory.CreateDirectory(eventDir); - - var subscriptionEntryPath = GetSubscriptionEntryPath(eventDir); - - var attempts = 0; - - // since we have a design that can run into concurrency exceptions we perform a few retries - while (true) - { - try - { - await AsyncFile.WriteText(subscriptionEntryPath, localAddress).ConfigureAwait(false); - - return; - } - catch (IOException) - { - attempts++; - - if (attempts > 10) - { - throw; - } - - //allow the other task to complete - await Task.Delay(100).ConfigureAwait(false); - } - } - } - - public async Task Unsubscribe(Type eventType, ContextBag context) - { - var eventDir = GetEventDirectory(eventType); - var subscriptionEntryPath = GetSubscriptionEntryPath(eventDir); - - var attempts = 0; - - // since we have a design that can run into concurrency exceptions we perform a few retries - while(true) - { - try - { - if (!File.Exists(subscriptionEntryPath)) - { - return; - } - - File.Delete(subscriptionEntryPath); - - return; - } - catch (IOException) - { - attempts++; - - if (attempts > 10) - { - throw; - } - - //allow the other task to complete - await Task.Delay(100).ConfigureAwait(false); - } - } - } - - string GetSubscriptionEntryPath(string eventDir) => Path.Combine(eventDir, endpointName + ".subscription"); - - string GetEventDirectory(Type eventType) => Path.Combine(basePath, eventType.FullName); - - string basePath; - string endpointName; - string localAddress; - } -} \ No newline at end of file diff --git a/src/Billing/Billing.csproj b/src/Billing/Billing.csproj index 8cb7db6..43ba54f 100644 --- a/src/Billing/Billing.csproj +++ b/src/Billing/Billing.csproj @@ -5,7 +5,6 @@ 7.1 - diff --git a/src/Client/Client.csproj b/src/Client/Client.csproj index 8cb7db6..43ba54f 100644 --- a/src/Client/Client.csproj +++ b/src/Client/Client.csproj @@ -5,7 +5,6 @@ 7.1 - diff --git a/src/LoadTests.Receiver.Router/LoadTests.Receiver.Router.csproj b/src/LoadTests.Receiver.Router/LoadTests.Receiver.Router.csproj index 54806eb..79f5759 100644 --- a/src/LoadTests.Receiver.Router/LoadTests.Receiver.Router.csproj +++ b/src/LoadTests.Receiver.Router/LoadTests.Receiver.Router.csproj @@ -7,7 +7,6 @@ - diff --git a/src/LoadTests.Sender.Router/LoadTests.Sender.Router.csproj b/src/LoadTests.Sender.Router/LoadTests.Sender.Router.csproj index a8cc68f..4a69091 100644 --- a/src/LoadTests.Sender.Router/LoadTests.Sender.Router.csproj +++ b/src/LoadTests.Sender.Router/LoadTests.Sender.Router.csproj @@ -14,7 +14,6 @@ - diff --git a/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_publishing_from_message_driven_pubsub_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_publishing_from_message_driven_pubsub_endpoint.cs deleted file mode 100644 index e3febac..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_publishing_from_message_driven_pubsub_endpoint.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.BridgeConnector -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_publishing_from_message_driven_pubsub_endpoint : NServiceBusAcceptanceTest - { - [Test] - public async Task It_should_deliver_the_message_to_both_subscribers() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); - }) - .WithEndpoint(c => c.When(x => x.BaseEventSubscribed && x.DerivedEventSubscribed, s => s.Publish(new MyDerivedEvent()))) - .WithEndpoint() - .WithEndpoint() - .Done(c => c.BaseEventDelivered && c.DerivedEventDelivered) - .Run(); - - Assert.IsTrue(result.BaseEventDelivered); - Assert.IsTrue(result.DerivedEventDelivered); - } - - class Context : ScenarioContext - { - public bool BaseEventDelivered { get; set; } - public bool DerivedEventDelivered { get; set; } - public bool BaseEventSubscribed { get; set; } - public bool DerivedEventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); - - c.OnEndpointSubscribed((args, context) => - { - if (args.MessageType.Contains("MyBaseEvent")) - { - context.BaseEventSubscribed = true; - } - else - { - context.DerivedEventSubscribed = true; - } - }); - }); - } - } - - class BaseEventSubscriber : EndpointConfigurationBuilder - { - public BaseEventSubscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerBravo().Routing(); - var bridge = routing.ConnectToBridge("Router"); - bridge.RegisterPublisher(typeof(MyBaseEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - } - - class BaseEventHandler : IHandleMessages - { - Context scenarioContext; - - public BaseEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyBaseEvent message, IMessageHandlerContext context) - { - scenarioContext.BaseEventDelivered = true; - return Task.CompletedTask; - } - } - } - - class DerivedEventSubscriber : EndpointConfigurationBuilder - { - public DerivedEventSubscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerBravo().Routing(); - var bridge = routing.ConnectToBridge("Router"); - bridge.RegisterPublisher(typeof(MyDerivedEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - } - - class DerivedEventHandler : IHandleMessages - { - Context scenarioContext; - - public DerivedEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyDerivedEvent message, IMessageHandlerContext context) - { - scenarioContext.DerivedEventDelivered = true; - return Task.CompletedTask; - } - } - } - - class MyBaseEvent : IEvent - { - } - - class MyDerivedEvent : MyBaseEvent - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_replying_to_a_message.cs b/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_replying_to_a_message.cs deleted file mode 100644 index cd5dda0..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/BridgeConnector/When_replying_to_a_message.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.BridgeConnector -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_replying_to_a_message : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_deliver_the_reply_without_the_need_to_configure_the_bridge() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .Done(c => c.RequestReceived && c.ResponseReceived) - .Run(); - - Assert.IsTrue(result.RequestReceived); - Assert.IsTrue(result.ResponseReceived); - } - - class Context : ScenarioContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToBridge("Router"); - bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers.cs b/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers.cs deleted file mode 100644 index 0248fc8..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Deduplication -{ - using System.Data.SqlClient; - using System.Threading; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_publishing_via_two_routers : NServiceBusAcceptanceTest - { - const string ConnectionString = "data source = (local); initial catalog=test1; integrated security=true"; - - [Test] - public async Task Should_deliver_the_event() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Green", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Red-Blue", () => new SqlConnection(ConnectionString), 10); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Green"); - routeTable.AddForwardRoute("Green", "Blue", "Red-Blue"); - }) - .WithRouter("Red-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Red", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Green-Blue", () => new SqlConnection(ConnectionString), 5); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Red"); - routeTable.AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(ctx => ctx.EventSubscribed, s => s.Send(new MyMessage - { - Counter = 0 - }))) - .WithEndpoint() - .Done(c => c.Counter > 5) - .Run(TimeSpan.FromSeconds(60)); - - Assert.IsTrue(result.AreSendsDeduplicated); - Assert.IsTrue(result.ArePublishesDeduplicated); - } - - class Context : ScenarioContext - { - int counter; - - public int Counter => Volatile.Read(ref counter); - public bool EventSubscribed { get; set; } - public bool AreSendsDeduplicated { get; set; } - public bool ArePublishesDeduplicated { get; set; } - - public int IncrementCounter() - { - return Interlocked.Increment(ref counter); - } - } - - class GreenEndpoint : EndpointConfigurationBuilder - { - public GreenEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - var bridge = transport.Routing().ConnectToRouter("Green-Blue"); - bridge.RouteToEndpoint(typeof(MyMessage), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent response, IMessageHandlerContext context) - { - scenarioContext.ArePublishesDeduplicated = context.MessageHeaders.ContainsKey(RouterDeduplicationHeaders.SequenceNumber); - var incremented = scenarioContext.IncrementCounter(); - - return context.Send(new MyMessage - { - Counter = incremented - }); - } - } - } - - class RedEndpoint : EndpointConfigurationBuilder - { - public RedEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - - c.OnEndpointSubscribed((args, context) => - { - context.EventSubscribed = true; - }); - }); - } - - class MyMessageHandler : IHandleMessages - { - Context scenarioContext; - - public MyMessageHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyMessage request, IMessageHandlerContext context) - { - scenarioContext.AreSendsDeduplicated = context.MessageHeaders.ContainsKey(RouterDeduplicationHeaders.SequenceNumber); - - return context.Publish(new MyEvent - { - Counter = request.Counter - }); - } - } - } - - class MyMessage : ICommand - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - - class MyEvent : IEvent - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers_native_pubsub.cs b/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers_native_pubsub.cs deleted file mode 100644 index cae6ff6..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_publishing_via_two_routers_native_pubsub.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Deduplication -{ - using System.Data.SqlClient; - using System.Threading; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_publishing_via_two_routers_native_pubsub : NServiceBusAcceptanceTest - { - const string ConnectionString = "data source = (local); initial catalog=test1; integrated security=true"; - - [Test] - public async Task Should_deliver_the_event_in_message_driven_mode() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerYankee()); - //linkInterface.DisableNativePubSub(); - linkInterface.InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Green", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Red-Blue", () => new SqlConnection(ConnectionString), 10); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Green"); - routeTable.AddForwardRoute("Green", "Blue", "Red-Blue"); - }) - .WithRouter("Red-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerYankee()); - //linkInterface.DisableNativePubSub(); - linkInterface.InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Red", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Green-Blue", () => new SqlConnection(ConnectionString), 5); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Red"); - routeTable.AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(ctx => ctx.EventSubscribed, s => s.Send(new MyMessage - { - Counter = 0 - }))) - .WithEndpoint() - .Done(c => c.Counter > 5) - .Run(TimeSpan.FromSeconds(60)); - - Assert.IsTrue(result.AreSendsDeduplicated); - Assert.IsTrue(result.ArePublishesDeduplicated); - } - - class Context : ScenarioContext - { - int counter; - - public int Counter => Volatile.Read(ref counter); - public bool EventSubscribed { get; set; } - public bool AreSendsDeduplicated { get; set; } - public bool ArePublishesDeduplicated { get; set; } - - public int IncrementCounter() - { - return Interlocked.Increment(ref counter); - } - } - - class GreenEndpoint : EndpointConfigurationBuilder - { - public GreenEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - var bridge = transport.Routing().ConnectToRouter("Green-Blue"); - bridge.RouteToEndpoint(typeof(MyMessage), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent response, IMessageHandlerContext context) - { - scenarioContext.ArePublishesDeduplicated = context.MessageHeaders.ContainsKey(RouterDeduplicationHeaders.SequenceNumber); - - var incremented = scenarioContext.IncrementCounter(); - return context.Send(new MyMessage - { - Counter = incremented - }); - } - } - } - - class RedEndpoint : EndpointConfigurationBuilder - { - public RedEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - - c.OnEndpointSubscribed((args, context) => - { - context.EventSubscribed = true; - }); - }); - } - - class MyMessageHandler : IHandleMessages - { - Context scenarioContext; - - public MyMessageHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyMessage request, IMessageHandlerContext context) - { - scenarioContext.AreSendsDeduplicated = context.MessageHeaders.ContainsKey(RouterDeduplicationHeaders.SequenceNumber); - - return context.Publish(new MyEvent - { - Counter = request.Counter - }); - } - } - } - - class MyMessage : ICommand - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - - class MyEvent : IEvent - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_sending_via_two_routers.cs b/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_sending_via_two_routers.cs deleted file mode 100644 index ddccf6c..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Deduplication/When_sending_via_two_routers.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Deduplication -{ - using System.Data.SqlClient; - using System.Threading; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_sending_via_two_routers : NServiceBusAcceptanceTest - { - const string ConnectionString = "data source = (local); initial catalog=test1; integrated security=true"; - - [Test] - public async Task Should_deliver_the_reply_back() - { - await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Green", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Red-Blue", () => new SqlConnection(ConnectionString), 10); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Green"); - routeTable.AddForwardRoute("Green", "Blue", "Red-Blue"); - }) - .WithRouter("Red-Blue", cfg => - { - var deduplicationConfig = cfg.ConfigureDeduplication(); -#pragma warning disable 618 - deduplicationConfig.EnableInstaller(true); -#pragma warning restore 618 - - var linkInterface = cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - var sqlInterface = cfg.AddInterface("Red", t => - { - t.ConnectionString(ConnectionString); - t.Transactions(TransportTransactionMode.SendsAtomicWithReceive); - }); - sqlInterface.InMemorySubscriptions(); - sqlInterface.EnableDeduplication(linkInterface.Name, "Green-Blue", () => new SqlConnection(ConnectionString), 5); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Red"); - routeTable.AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(s => s.Send(new GreenRequest - { - Counter = 0 - }))) - .WithEndpoint() - .Done(c => c.Counter > 20) - .Run(TimeSpan.FromSeconds(60)); - } - - class Context : ScenarioContext - { - int counter; - - public int Counter => Volatile.Read(ref counter); - - public int IncrementCounter() - { - return Interlocked.Increment(ref counter); - } - } - - class GreenEndpoint : EndpointConfigurationBuilder - { - public GreenEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - var bridge = transport.Routing().ConnectToRouter("Green-Blue"); - bridge.RouteToEndpoint(typeof(GreenRequest), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - }); - } - - class GreenResponseHandler : IHandleMessages - { - Context scenarioContext; - - public GreenResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(GreenResponse response, IMessageHandlerContext context) - { - var incremented = scenarioContext.IncrementCounter(); - return context.Send(new GreenRequest - { - Counter = incremented - }); - } - } - } - - class RedEndpoint : EndpointConfigurationBuilder - { - public RedEndpoint() - { - EndpointSetup(c => - { - var transport = c.UseTransport(); - transport.ConnectionString(ConnectionString); - }); - } - - class GreenRequestHandler : IHandleMessages - { - public Task Handle(GreenRequest request, IMessageHandlerContext context) - { - var correlation = context.MessageHeaders[Headers.CorrelationId]; - Console.WriteLine(correlation); - return context.Reply(new GreenResponse - { - Counter = request.Counter - }); - } - } - } - - class GreenRequest : IMessage - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - - class GreenResponse : IMessage - { - public int Counter { get; set; } - - public override string ToString() - { - return Counter.ToString(); - } - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/BrokerSettings.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/BrokerSettings.cs new file mode 100644 index 0000000..fd103b8 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/BrokerSettings.cs @@ -0,0 +1,45 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using System.IO; + using NUnit.Framework; + + public class BrokerSettings + { + AcceptanceTestingTransport transportDefinition; + + public BrokerSettings(AcceptanceTestingTransport transportDefinition) + { + this.transportDefinition = transportDefinition; + } + + void SetStoragePath(string broker) + { + var storageDir = Path.Combine(Path.GetTempPath(), "learn", TestContext.CurrentContext.Test.ID, broker); + transportDefinition.StorageLocation = storageDir; + } + public void Alpha() + { + SetStoragePath("Alpha"); + } + + public void Bravo() + { + SetStoragePath("Bravo"); + } + + public void Charlie() + { + SetStoragePath("Charlie"); + } + + public void Yankee() + { + SetStoragePath("Yankee"); + } + + public void Zulu() + { + SetStoragePath("Zulu"); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/ConfigureExtensions.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/ConfigureExtensions.cs new file mode 100644 index 0000000..36639a3 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/ConfigureExtensions.cs @@ -0,0 +1,49 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using Configuration.AdvancedExtensibility; + using Transport; + + public static class ConfigureExtensions + { + public static RoutingSettings ConfigureRouting(this EndpointConfiguration configuration) => + new RoutingSettings(configuration.GetSettings()); + + public static TransportDefinition ConfigureTransport(this EndpointConfiguration configuration) => + configuration.GetSettings().Get(); + + public static BrokerSettings ConfigureBroker(this EndpointConfiguration configuration) + { + return new BrokerSettings((AcceptanceTestingTransport)configuration.GetSettings().Get()); + } + + public static TTransportDefinition ConfigureTransport( + this EndpointConfiguration configuration) + where TTransportDefinition : TransportDefinition => + (TTransportDefinition)configuration.GetSettings().Get(); + + public static BrokerSettings Broker(this InterfaceConfiguration iface) + { + return new BrokerSettings((AcceptanceTestingTransport)iface.Transport); + } + + public static BrokerSettings Broker(this AcceptanceTestingTransport transport) + { + return new BrokerSettings(transport); + } + + public static InterfaceConfiguration AddInterface(this RouterConfiguration cfg, string name, bool nativePubSub = true) + { + var transport = new AcceptanceTestingTransport(true, nativePubSub); + transport.TransportTransactionMode = TransportTransactionMode.ReceiveOnly; + + var @interface = cfg.AddInterface(name, transport); + + if (!transport.SupportsPublishSubscribe) + { + @interface.InMemorySubscriptions(); + } + + return @interface; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/DefaultServer.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/DefaultServer.cs new file mode 100644 index 0000000..21e5600 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/DefaultServer.cs @@ -0,0 +1,42 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using System; + using System.IO; + using System.Threading.Tasks; + using AcceptanceTesting.Customization; + using AcceptanceTesting.Support; + using NUnit.Framework; + + public class DefaultServer : IEndpointSetupTemplate + { + public virtual async Task GetConfiguration(RunDescriptor runDescriptor, EndpointCustomizationConfiguration endpointConfiguration, + Func configurationBuilderCustomization) + { + var builder = new EndpointConfiguration(endpointConfiguration.EndpointName); + builder.EnableInstallers(); + + builder.Recoverability() + .Delayed(delayed => delayed.NumberOfRetries(0)) + .Immediate(immediate => immediate.NumberOfRetries(0)); + builder.SendFailedMessagesTo("error"); + builder.UseSerialization(); + + //Default value. Needs to be overridden by selected broker + var storageDir = Path.Combine(Path.GetTempPath(), "learn", TestContext.CurrentContext.Test.ID); + + builder.UseTransport(new AcceptanceTestingTransport + { + StorageLocation = storageDir + }); + + builder.UsePersistence(); + + await configurationBuilderCustomization(builder).ConfigureAwait(false); + + // scan types at the end so that all types used by the configuration have been loaded into the AppDomain + builder.TypesToIncludeInScan(endpointConfiguration.GetTypesScopedByTestClass()); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/EndpointCustomizationConfigurationExtensions.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/EndpointCustomizationConfigurationExtensions.cs new file mode 100644 index 0000000..a4efd8d --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/EndpointCustomizationConfigurationExtensions.cs @@ -0,0 +1,54 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using NServiceBus.AcceptanceTesting.Support; + using NServiceBus.Hosting.Helpers; + + public static class EndpointCustomizationConfigurationExtensions + { + public static IEnumerable GetTypesScopedByTestClass(this EndpointCustomizationConfiguration endpointConfiguration) + { + var assemblyScanner = new AssemblyScanner + { + ScanFileSystemAssemblies = false + }; + + var assemblies = assemblyScanner.GetScannableAssemblies(); + + var assembliesToScan = assemblies.Assemblies + //exclude acceptance tests by default + .Where(a => a != Assembly.GetExecutingAssembly()).ToList(); + var types = assembliesToScan + .SelectMany(a => a.GetTypes()); + + types = types.Union(GetNestedTypeRecursive(endpointConfiguration.BuilderType.DeclaringType, endpointConfiguration.BuilderType)); + + types = types.Union(endpointConfiguration.TypesToInclude); + + return types.Where(t => !endpointConfiguration.TypesToExclude.Contains(t)).ToList(); + } + + static IEnumerable GetNestedTypeRecursive(Type rootType, Type builderType) + { + if (rootType == null) + { + throw new InvalidOperationException("Make sure you nest the endpoint infrastructure inside the TestFixture as nested classes"); + } + + yield return rootType; + + if (typeof(IEndpointConfigurationFactory).IsAssignableFrom(rootType) && rootType != builderType) + { + yield break; + } + + foreach (var nestedType in rootType.GetNestedTypes(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SelectMany(t => GetNestedTypeRecursive(t, builderType))) + { + yield return nestedType; + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/IPoisonSpyContext.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/IPoisonSpyContext.cs new file mode 100644 index 0000000..6632dba --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/IPoisonSpyContext.cs @@ -0,0 +1,8 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + public interface IPoisonSpyContext + { + string ExceptionMessage { get; set; } + bool PoisonMessageDetected { get; set; } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/InMemorySubscriptionStorage.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/InMemorySubscriptionStorage.cs new file mode 100644 index 0000000..eeceb8f --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/InMemorySubscriptionStorage.cs @@ -0,0 +1,90 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using NServiceBus; + using Configuration.AdvancedExtensibility; + using Extensibility; + using Features; + using Microsoft.Extensions.DependencyInjection; + using Persistence; + using Unicast.Subscriptions; + using Unicast.Subscriptions.MessageDrivenSubscriptions; + + public class InMemoryPersistence : PersistenceDefinition + { + internal InMemoryPersistence() + { + Supports(s => { s.EnableFeatureByDefault(); }); + } + } + + public static class InMemoryPersistenceExtensions + { + public static void UseStorage(this PersistenceExtensions extensions, InMemorySubscriptionStorage storageInstance) + { + extensions.GetSettings().Set("InMemoryPersistence.StorageInstance", storageInstance); + } + } + + public class InMemorySubscriptionPersistence : Feature + { + internal InMemorySubscriptionPersistence() + { +#pragma warning disable 618 + DependsOn(); +#pragma warning restore 618 + } + + protected override void Setup(FeatureConfigurationContext context) + { + var storageInstance = context.Settings.GetOrDefault("InMemoryPersistence.StorageInstance"); + context.Services.AddSingleton(storageInstance ?? new InMemorySubscriptionStorage()); + } + } + + public class InMemorySubscriptionStorage : ISubscriptionStorage + { + public Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context, CancellationToken token) + { + var dict = storage.GetOrAdd(messageType, type => new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase)); + + dict.AddOrUpdate(BuildKey(subscriber), _ => subscriber, (_, __) => subscriber); + return Task.CompletedTask; + } + + static string BuildKey(Subscriber subscriber) + { + return $"{subscriber.TransportAddress ?? ""}_{subscriber.Endpoint ?? ""}"; + } + + public Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context, CancellationToken token) + { + if (storage.TryGetValue(messageType, out var dict)) + { + dict.TryRemove(BuildKey(subscriber), out var _); + } + + return Task.CompletedTask; + } + + public Task> GetSubscriberAddressesForMessage(IEnumerable messageTypes, ContextBag context, CancellationToken token) + { + var result = new HashSet(); + foreach (var m in messageTypes) + { + if (storage.TryGetValue(m, out var list)) + { + result.UnionWith(list.Values); + } + } + + return Task.FromResult((IEnumerable)result); + } + + ConcurrentDictionary> storage = new ConcurrentDictionary>(); + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/NServiceBusAcceptanceTest.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/NServiceBusAcceptanceTest.cs new file mode 100644 index 0000000..8ad417b --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/NServiceBusAcceptanceTest.cs @@ -0,0 +1,40 @@ +namespace NServiceBus.Router.AcceptanceTests +{ + using System.Linq; + using System.Threading; + using AcceptanceTesting.Customization; + using NUnit.Framework; + + /// + /// Base class for all the NSB test that sets up our conventions + /// + [TestFixture] + public abstract class NServiceBusAcceptanceTest + { + [SetUp] + public void SetUp() + { +#if NETFRAMEWORK + // Hack: prevents SerializationException ... Type 'x' in assembly 'y' is not marked as serializable. + // https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/mitigation-deserialization-of-objects-across-app-domains + System.Configuration.ConfigurationManager.GetSection("X"); +#endif + Conventions.EndpointNamingConvention = t => + { + string classAndEndpoint = t.FullName.Split('.').Last(); + + string testName = classAndEndpoint.Split('+').First(); + + testName = testName.Replace("When_", ""); + + string endpointBuilder = classAndEndpoint.Split('+').Last(); + + testName = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(testName); + + testName = testName.Replace("_", ""); + + return testName + "." + endpointBuilder; + }; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponent.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponent.cs new file mode 100644 index 0000000..cab9cc9 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponent.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting; +using NServiceBus.AcceptanceTesting.Support; + +namespace NServiceBus.Router.AcceptanceTests +{ + class RouterComponent : IComponentBehavior + { + Func configCallback; + + public RouterComponent(Func config) + { + this.configCallback = config; + } + + public Task CreateRunner(RunDescriptor run) + { + var config = configCallback(run.ScenarioContext); + config.Settings.Set(run.ScenarioContext); + config.AutoCreateQueues(); + var newFactories = new List>(); + + foreach (var factory in config.InterfaceFactories) + { + Interface NewFactory() + { + var port = factory(); + return port; + } + + newFactories.Add(NewFactory); + } + + config.InterfaceFactories = newFactories; + var @switch = Router.Create(config); + return Task.FromResult(new Runner(@switch, "Router")); + } + + class Runner : ComponentRunner + { + IRouter router; + + public Runner(IRouter router, string name) + { + this.router = router; + Name = name; + } + + public override Task Start(CancellationToken token) + { + return router.Initialize(); + } + + public override Task ComponentsStarted(CancellationToken token) + { + return router.Start(); + } + + public override Task Stop() + { + return router != null + ? router.Stop() + : Task.CompletedTask; + } + + public override string Name { get; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponentExtensions.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponentExtensions.cs new file mode 100644 index 0000000..50b3a28 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/RouterComponentExtensions.cs @@ -0,0 +1,32 @@ +using System; +using NServiceBus.AcceptanceTesting; +using NServiceBus.AcceptanceTesting.Support; +using NServiceBus.Router; + +namespace NServiceBus.Router.AcceptanceTests +{ + public static class RouterComponentExtensions + { + public static IScenarioWithEndpointBehavior WithRouter(this IScenarioWithEndpointBehavior scenario, string name, Action configCallback) + where TContext : ScenarioContext + { + return scenario.WithComponent(new RouterComponent(s => + { + var cfg = new RouterConfiguration(name); + configCallback(cfg); + return cfg; + })); + } + + public static IScenarioWithEndpointBehavior WithRouter(this IScenarioWithEndpointBehavior scenario, string name, Action configCallback) + where TContext : ScenarioContext + { + return scenario.WithComponent(new RouterComponent(s => + { + var cfg = new RouterConfiguration(name); + configCallback((TContext)s, cfg); + return cfg; + })); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponent.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponent.cs new file mode 100644 index 0000000..3da2dd6 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponent.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting; +using NServiceBus.AcceptanceTesting.Support; +using NServiceBus.Transport; + +namespace NServiceBus.Router.AcceptanceTests +{ + class SpyComponent : IComponentBehavior + where T : ScenarioContext + { + TransportDefinition transportConfiguration; + Func onMessage; + string endpointName; + + public SpyComponent(string endpointName, TransportDefinition transportConfiguration, + Func onMessage) + { + this.transportConfiguration = transportConfiguration; + this.onMessage = onMessage; + this.endpointName = endpointName; + } + + public Task CreateRunner(RunDescriptor run) + { + var scenarioContext = (T)run.ScenarioContext; + + return Task.FromResult(new SpyComponentRunner(endpointName, transportConfiguration, (messageContext, messages, token) => onMessage(scenarioContext, messageContext, messages, token))); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentExtensions.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentExtensions.cs new file mode 100644 index 0000000..3366e6c --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting; +using NServiceBus.AcceptanceTesting.Support; +using NServiceBus.Transport; + +namespace NServiceBus.Router.AcceptanceTests +{ + public static class SpyComponentExtensions + { + public static IScenarioWithEndpointBehavior WithPosionSpyComponent(this IScenarioWithEndpointBehavior scenario, TransportDefinition transportConfiguration) + where TContext : ScenarioContext, IPoisonSpyContext + { + return scenario.WithComponent(new SpyComponent("poison", transportConfiguration, (scenarioContext, messageContext, dispatcher, token) => + { + var failureDetected = 0; + + if (Interlocked.CompareExchange(ref failureDetected, 1, 0) == 0) + { + if (messageContext.Headers.TryGetValue("NServiceBus.ExceptionInfo.Message", out var exceptionMessage)) + { + scenarioContext.ExceptionMessage = exceptionMessage; + } + + scenarioContext.PoisonMessageDetected = true; + } + + return Task.CompletedTask; + })); + } + + public static IScenarioWithEndpointBehavior WithSpyComponent(this IScenarioWithEndpointBehavior scenario, + string endpointName, + TransportDefinition transportConfiguration, + Func onMessage) + where TContext : ScenarioContext + { + return scenario.WithComponent(new SpyComponent(endpointName, transportConfiguration, onMessage)); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentRunner.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentRunner.cs new file mode 100644 index 0000000..175ac98 --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SpyComponentRunner.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting.Support; +using NServiceBus.Raw; +using NServiceBus.Transport; + +namespace NServiceBus.Router.AcceptanceTests +{ + class SpyComponentRunner : ComponentRunner + { + TransportDefinition transportConfiguration; + Func onMessage; + string endpointName; + IReceivingRawEndpoint endpoint; + + public SpyComponentRunner(string endpointName, TransportDefinition transportConfiguration, + Func onMessage) + { + this.transportConfiguration = transportConfiguration; + this.onMessage = onMessage; + this.endpointName = endpointName; + } + + public override string Name => endpointName; + + public override async Task Start(CancellationToken token) + { + var config = RawEndpointConfiguration.Create(endpointName, transportConfiguration, onMessage, "poison"); + config.AutoCreateQueues(); + config.CustomErrorHandlingPolicy(new IgnoreErrorsPolicy()); + + endpoint = await RawEndpoint.Start(config); + } + + public override Task Stop() + { + return endpoint != null + ? endpoint.Stop() + : Task.CompletedTask; + } + + class IgnoreErrorsPolicy : IErrorHandlingPolicy + { + public Task OnError(IErrorHandlingPolicyContext handlingContext, IMessageDispatcher dispatcher, CancellationToken token) + { + return Task.FromResult(ErrorHandleResult.Handled); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SubscriptionHelper.cs b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SubscriptionHelper.cs new file mode 100644 index 0000000..a1d9f7b --- /dev/null +++ b/src/NServiceBus.Router.AcceptanceTests/Infrastructure/SubscriptionHelper.cs @@ -0,0 +1,17 @@ +using NServiceBus.Router; +using NServiceBus.Router.AcceptanceTests; + +public static class SubscriptionHelper +{ + public static InterfaceConfiguration InMemorySubscriptions(this InterfaceConfiguration interfaceConfig) + { + interfaceConfig.EnableMessageDrivenPublishSubscribe(new InMemorySubscriptionStorage()); + return interfaceConfig; + } + + public static SendOnlyInterfaceConfiguration InMemorySubscriptions(this SendOnlyInterfaceConfiguration interfaceConfig) + { + interfaceConfig.EnableMessageDrivenPublishSubscribe(new InMemorySubscriptionStorage()); + return interfaceConfig; + } +} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_connecting_to_two_routers.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_connecting_to_two_routers.cs deleted file mode 100644 index 8841f6d..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_connecting_to_two_routers.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_connecting_to_two_routers : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_deliver_the_messages_to_destination_endpoints() - { - var result = await Scenario.Define() - .WithRouter("RouterA", cfg => - { - cfg.AddInterface("Left", t => t.BrokerCharlie()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerAlpha()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithRouter("RouterB", cfg => - { - cfg.AddInterface("Left", t => t.BrokerCharlie()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(async s => - { - await s.Send(new MyRequestA()); - await s.Send(new MyRequestB()); - })) - .WithEndpoint() - .WithEndpoint() - .Done(c => c.ReceivedByB && c.ReceivedByA) - .Run(); - - Assert.IsTrue(result.ReceivedByB); - Assert.IsTrue(result.ReceivedByA); - } - - class Context : ScenarioContext - { - public bool ReceivedByA { get; set; } - public bool ReceivedByB { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerCharlie().Routing(); - - var routerA = routing.ConnectToRouter("RouterA"); - routerA.RouteToEndpoint(typeof(MyRequestA), Conventions.EndpointNamingConvention(typeof(ReceiverA))); - - var routerB = routing.ConnectToRouter("RouterB"); - routerB.RouteToEndpoint(typeof(MyRequestB), Conventions.EndpointNamingConvention(typeof(ReceiverB))); - }); - } - } - - class ReceiverA : EndpointConfigurationBuilder - { - public ReceiverA() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerAlpha(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequestA requestA, IMessageHandlerContext context) - { - scenarioContext.ReceivedByA = true; - return Task.CompletedTask; - } - } - } - - class ReceiverB : EndpointConfigurationBuilder - { - public ReceiverB() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequestB requestB, IMessageHandlerContext context) - { - scenarioContext.ReceivedByB = true; - return Task.CompletedTask; - } - } - } - - class MyRequestA : IMessage - { - } - - class MyRequestB : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_bridge.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_bridge.cs deleted file mode 100644 index d0790ce..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_bridge.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_publishing_via_double_unicast_bridge : NServiceBusAcceptanceTest - { - [Test] - public async Task It_should_deliver_the_message() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Blue", "Green"); - }) - .WithRouter("Blue-Red", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(x => x.EventSubscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - } - - class Context : ScenarioContext - { - public bool EventDelivered { get; set; } - public bool EventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); - - c.OnEndpointSubscribed((args, context) => - { - context.EventSubscribed = true; - }); - }); - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerCharlie().Routing(); - var ramp = routing.ConnectToRouter("Blue-Red"); - ramp.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventDelivered = true; - return Task.CompletedTask; - } - } - } - - class MyEvent : IEvent - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_multicast_bridge.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_multicast_bridge.cs deleted file mode 100644 index b0aa451..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_publishing_via_double_unicast_multicast_bridge.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_publishing_via_double_unicast_multicast_bridge : NServiceBusAcceptanceTest - { - [Test] - public async Task It_should_deliver_the_message() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Blue", "Green"); - }) - .WithRouter("Blue-Red", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(x => x.EventSubscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - } - - class Context : ScenarioContext - { - public bool EventDelivered { get; set; } - public bool EventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); - - c.OnEndpointSubscribed((args, context) => - { - context.EventSubscribed = true; - }); - }); - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerCharlie().Routing(); - var bridge = routing.ConnectToRouter("Blue-Red"); - bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventDelivered = true; - return Task.CompletedTask; - } - } - } - - class MyEvent : IEvent - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sender_delegates_routing.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sender_delegates_routing.cs deleted file mode 100644 index 6f3e339..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sender_delegates_routing.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using System; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_sender_delegates_routing : NServiceBusAcceptanceTest - { - static string ReceiverEndpoint => Conventions.EndpointNamingConvention(typeof(Receiver)); - - [Test] - public async Task Should_use_custom_destination_finder_on_destinations_router() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddRoute((iface, destination) => destination.Site == "MySite", "Site = MySite", "Blue-Red", "Blue"); - }) - .WithRouter("Blue-Red", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - - var staticRouting = cfg.UseStaticRoutingProtocol(); - staticRouting.AddForwardRoute("Blue", "Red"); - cfg.AddRule(_ => new CustomDestinationRule()); - }) - .WithEndpoint(c => c.When(s => - { - var ops = new SendOptions(); - ops.SendToSites("MySite"); - return s.Send(new MyRequest(), ops); - })) - .WithEndpoint() - .Done(c => c.RequestReceived && c.ResponseReceived) - .Run(); - - Assert.IsTrue(result.RequestReceived); - Assert.IsTrue(result.ResponseReceived); - } - - class CustomDestinationRule : IRule - { - public Task Invoke(SendPreroutingContext context, Func next) - { - context.Destinations.Add(new Destination(ReceiverEndpoint, null)); - return next(context); - } - } - - class Context : ScenarioContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var router = routing.ConnectToRouter("Green-Blue"); - router.DelegateRouting(typeof(MyRequest)); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerCharlie(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_between_sites.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_between_sites.cs deleted file mode 100644 index 98a5f36..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_between_sites.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - [TestFixture] - public class When_sending_between_sites : NServiceBusAcceptanceTest - { - const string ReceiverEndpoint = "SendingBetweenSites.Receiver"; - - [Test] - public async Task Should_deliver_the_reply_back() - { - var result = await Scenario.Define() - .WithRouter("Green-Yellow", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Yellow", t => t.BrokerBravo()).InMemorySubscriptions(); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddRoute((i, d) => i == "Green" && d.Endpoint == ReceiverEndpoint && d.Site == "Blue", - $"Endpoint = {ReceiverEndpoint} AND Interface = Green AND Site = Blue", - "Yellow-Blue", "Yellow"); - routeTable.AddRoute((i, d) => i == "Green" && d.Endpoint == ReceiverEndpoint && d.Site == "Red", - $"Endpoint = {ReceiverEndpoint} AND Interface = Green AND Site = Red", - "Yellow-Red", "Yellow"); - }) - .WithRouter("Yellow-Blue", cfg => - { - cfg.AddInterface("Yellow", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerCharlie()).InMemorySubscriptions(); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Yellow", "Blue"); - }) - .WithRouter("Yellow-Red", cfg => - { - cfg.AddInterface("Yellow", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerDelta()).InMemorySubscriptions(); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Yellow", "Red"); - }) - .WithEndpoint(c => c.When(async s => - { - await SendToSite(s, "Blue").ConfigureAwait(false); - await SendToSite(s, "Red").ConfigureAwait(false); - })) - .WithEndpoint() - .WithEndpoint() - .Done(c => c.BlueRequestReceived - && c.BlueResponseReceived - && c.RedRequestReceived - && c.RedResponseReceived) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(result.BlueResponseReceived); - Assert.IsTrue(result.RedResponseReceived); - } - - static Task SendToSite(IMessageSession s, string site) - { - var ops = new SendOptions(); - ops.SendToSites(site); - return s.Send(new MyRequest(), ops); - } - - class Context : ScenarioContext - { - public bool RedRequestReceived { get; set; } - public bool RedResponseReceived { get; set; } - public bool BlueRequestReceived { get; set; } - public bool BlueResponseReceived { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Green-Yellow"); - bridge.RouteToEndpoint(typeof(MyRequest), ReceiverEndpoint); - }); - } - - class BlueResponseHandler : IHandleMessages - { - Context scenarioContext; - - public BlueResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(BlueResponse response, IMessageHandlerContext context) - { - scenarioContext.BlueResponseReceived = true; - return Task.CompletedTask; - } - } - - class RedResponseHandler : IHandleMessages - { - Context scenarioContext; - - public RedResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(RedResponse request, IMessageHandlerContext context) - { - scenarioContext.RedResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class BlueReceiver : EndpointConfigurationBuilder - { - public BlueReceiver() - { - EndpointSetup(c => - { - c.UseTransport().BrokerCharlie(); - }).CustomEndpointName(ReceiverEndpoint); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.BlueRequestReceived = true; - return context.Reply(new BlueResponse()); - } - } - } - - class RedReceiver : EndpointConfigurationBuilder - { - public RedReceiver() - { - EndpointSetup(c => - { - c.UseTransport().BrokerDelta(); - }).CustomEndpointName(ReceiverEndpoint); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RedRequestReceived = true; - return context.Reply(new RedResponse()); - } - } - } - - class MyRequest : IMessage - { - } - - class BlueResponse : IMessage - { - } - - class RedResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_three_routers.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_three_routers.cs deleted file mode 100644 index 2df489c..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_three_routers.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_sending_via_three_routers : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_deliver_the_reply() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Green", "Blue", "Blue-Red"); - }) - .WithRouter("Blue-Red", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Blue", "Red", "Red-Yellow"); - }) - .WithRouter("Red-Yellow", cfg => - { - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - cfg.AddInterface("Yellow", t => t.BrokerDelta()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Red", "Yellow"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .Done(c => c.RequestReceived && c.ResponseReceived) - .Run(); - - Assert.IsTrue(result.RequestReceived); - Assert.IsTrue(result.ResponseReceived); - } - - class Context : ScenarioContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Green-Blue"); - bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerDelta(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_two_routers.cs b/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_two_routers.cs deleted file mode 100644 index d2789cd..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/MultipleRouters/When_sending_via_two_routers.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.MultipleRouters -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_sending_via_two_routers : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_deliver_the_reply_back() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Green"); - routeTable.AddForwardRoute("Green", "Blue", "Red-Blue"); - }) - .WithRouter("Red-Blue", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Red", t => t.BrokerCharlie()).InMemorySubscriptions(); - - var routeTable = cfg.UseStaticRoutingProtocol(); - routeTable.AddForwardRoute("Blue", "Red"); - routeTable.AddForwardRoute("Red", "Blue", "Green-Blue"); - }) - .WithEndpoint(c => c.When(s => - { - var ops = new SendOptions(); - //ops.SendToSites("Red"); - return s.Send(new GreenRequest(), ops); - })) - .WithEndpoint(c => c.When(s => - { - var ops = new SendOptions(); - //ops.SendToSites("Green"); - return s.Send(new RedRequest(), ops); - })) - .Done(c => c.GreenRequestReceived - && c.GreenResponseReceived - && c.RedRequestReceived - && c.RedResponseReceived) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(result.GreenRequestReceived); - Assert.IsTrue(result.GreenResponseReceived); - } - - class Context : ScenarioContext - { - public bool GreenRequestReceived { get; set; } - public bool GreenResponseReceived { get; set; } - public bool RedRequestReceived { get; set; } - public bool RedResponseReceived { get; set; } - } - - class GreenEndpoint : EndpointConfigurationBuilder - { - public GreenEndpoint() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Green-Blue"); - bridge.RouteToEndpoint(typeof(GreenRequest), Conventions.EndpointNamingConvention(typeof(RedEndpoint))); - }); - } - - class GreenResponseHandler : IHandleMessages - { - Context scenarioContext; - - public GreenResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(GreenResponse response, IMessageHandlerContext context) - { - scenarioContext.GreenResponseReceived = true; - return Task.CompletedTask; - } - } - - class RedRequestHandler : IHandleMessages - { - Context scenarioContext; - - public RedRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(RedRequest request, IMessageHandlerContext context) - { - scenarioContext.RedRequestReceived = true; - return context.Reply(new RedResponse()); - } - } - } - - class RedEndpoint : EndpointConfigurationBuilder - { - public RedEndpoint() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerCharlie().Routing(); - var bridge = routing.ConnectToRouter("Red-Blue"); - bridge.RouteToEndpoint(typeof(RedRequest), Conventions.EndpointNamingConvention(typeof(GreenEndpoint))); - }); - } - - class RedResponseHandler : IHandleMessages - { - Context scenarioContext; - - public RedResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(RedResponse response, IMessageHandlerContext context) - { - scenarioContext.RedResponseReceived = true; - return Task.CompletedTask; - } - } - - class GreenRequestHandler : IHandleMessages - { - Context scenarioContext; - - public GreenRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(GreenRequest request, IMessageHandlerContext context) - { - scenarioContext.GreenRequestReceived = true; - return context.Reply(new GreenResponse()); - } - } - } - - class GreenRequest : IMessage - { - } - - class GreenResponse : IMessage - { - } - - class RedRequest : IMessage - { - } - - class RedResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/NServiceBus.Router.AcceptanceTests.csproj b/src/NServiceBus.Router.AcceptanceTests/NServiceBus.Router.AcceptanceTests.csproj index b8194f0..e401955 100644 --- a/src/NServiceBus.Router.AcceptanceTests/NServiceBus.Router.AcceptanceTests.csproj +++ b/src/NServiceBus.Router.AcceptanceTests/NServiceBus.Router.AcceptanceTests.csproj @@ -1,25 +1,20 @@  - net461;netcoreapp3.1 + net48;net6.0 latest - - - - - - - - - - + + + + + + + - + - - \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_interface_is_not_configured.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_interface_is_not_configured.cs deleted file mode 100644 index e45ee25..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_interface_is_not_configured.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System.Linq; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_interface_is_not_configured : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "NotConfigured"); - }) - .WithEndpoint(c => c.When(s => s.Send(new PoisonMessage()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerAlpha()) - .Done(c => c.PoisonMessageDetected || c.RequestReceived) - .Run(); - - Assert.IsFalse(result.RequestReceived); - Assert.IsTrue(result.PoisonMessageDetected); - Assert.AreEqual("Interface \'NotConfigured\' has not been configured.", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var router = routing.ConnectToRouter("Router"); - router.RouteToEndpoint(typeof(PoisonMessage), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(PoisonMessage request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return Task.CompletedTask; - } - } - } - - class PoisonMessage : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_correlation_id_is_overridden.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_correlation_id_is_overridden.cs deleted file mode 100644 index 77d6a15..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_correlation_id_is_overridden.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System; - using System.Linq; - using AcceptanceTesting.Customization; - using Pipeline; - - [TestFixture] - public class When_reply_correlation_id_is_overridden : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerBravo()) - .Done(c => c.ResponseReceived || c.PoisonMessageDetected) - .Run(); - - Assert.IsFalse(result.ResponseReceived); - Assert.IsTrue(result.PoisonMessageDetected); - Assert.AreEqual("Cannot decode value in \'NServiceBus.CorrelationId\' header: Expected type followed by a delimiter, found \'MyCorrelation\'", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Router"); - bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - c.Pipeline.Register(new OverrideCorrelationIdBehavior(), "Removes correlation header"); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - - class OverrideCorrelationIdBehavior : IBehavior - { - public Task Invoke(IDispatchContext context, Func next) - { - foreach (var operation in context.Operations) - { - operation.Message.Headers[Headers.CorrelationId] = "MyCorrelation"; - } - - return next(context); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_contain_correlation_id.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_contain_correlation_id.cs deleted file mode 100644 index 92389e6..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_contain_correlation_id.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System; - using System.Linq; - using AcceptanceTesting.Customization; - using Pipeline; - - [TestFixture] - public class When_reply_does_not_contain_correlation_id : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerBravo()) - .Done(c => c.ResponseReceived || c.PoisonMessageDetected) - .Run(); - - Assert.IsFalse(result.ResponseReceived); - Assert.IsTrue(result.PoisonMessageDetected); - StringAssert.StartsWith("The reply has to contain either 'NServiceBus.CorrelationId' header", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Router"); - bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - c.Pipeline.Register(new ClearCorrelationIdBehavior(), "Removes correlation header"); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - - class ClearCorrelationIdBehavior : IBehavior - { - public Task Invoke(IDispatchContext context, Func next) - { - foreach (var operation in context.Operations) - { - operation.Message.Headers.Remove(Headers.CorrelationId); - } - - return next(context); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_specify_iface.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_specify_iface.cs deleted file mode 100644 index e60de64..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_reply_does_not_specify_iface.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System; - using System.Linq; - using AcceptanceTesting.Customization; - using Pipeline; - - [TestFixture] - public class When_reply_does_not_specify_iface : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerBravo()) - .Done(c => c.ResponseReceived || c.PoisonMessageDetected) - .Run(); - - Assert.IsFalse(result.ResponseReceived); - Assert.IsTrue(result.PoisonMessageDetected); - Assert.AreEqual("The reply message does not contain \'iface\' correlation parameter required to route the message.", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var bridge = routing.ConnectToRouter("Router"); - bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - c.Pipeline.Register(new RemoveIfaceFromCorrelationIdBehavior(), "Removes correlation header"); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - - class RemoveIfaceFromCorrelationIdBehavior : IBehavior - { - public Task Invoke(IDispatchContext context, Func next) - { - foreach (var operation in context.Operations) - { - operation.Message.Headers[Headers.CorrelationId] - = operation.Message.Headers[Headers.CorrelationId].Replace("iface|4|Left|", ""); - } - - return next(context); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_routing_configuration_contains_cycles.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_routing_configuration_contains_cycles.cs deleted file mode 100644 index 89f2859..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_routing_configuration_contains_cycles.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System.Linq; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_routing_configuration_contains_cycles : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Green-Blue", cfg => - { - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Green", "Blue", "Blue-Green"); - }) - .WithRouter("Blue-Green", cfg => - { - cfg.AddInterface("Blue", t => t.BrokerBravo()).InMemorySubscriptions(); - cfg.AddInterface("Green", t => t.BrokerAlpha()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Blue", "Green", "Green-Blue"); - }) - .WithEndpoint(c => c.When(s => s.Send(new PoisonMessage()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerAlpha()) - .WithPosionSpyComponent(t => t.BrokerBravo()) - .Done(c => c.PoisonMessageDetected || c.RequestReceived) - .Run(); - - Assert.IsFalse(result.RequestReceived); - Assert.IsTrue(result.PoisonMessageDetected); - Assert.AreEqual("Routing cycle detected: via|10|Green-Blue|via|10|Blue-Green", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var router = routing.ConnectToRouter("Green-Blue"); - router.RouteToEndpoint(typeof(PoisonMessage), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - c.UseTransport().BrokerCharlie(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(PoisonMessage request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return Task.CompletedTask; - } - } - } - - class PoisonMessage : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_sender_does_not_specify_destination.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_sender_does_not_specify_destination.cs deleted file mode 100644 index 5f074ff..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_sender_does_not_specify_destination.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System.Linq; - - [TestFixture] - public class When_sender_does_not_specify_destination : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new PoisonMessage()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerAlpha()) - .Done(c => c.PoisonMessageDetected || c.RequestReceived) - .Run(); - - Assert.IsFalse(result.RequestReceived); - Assert.IsTrue(result.PoisonMessageDetected); - StringAssert.StartsWith("No destination found for message", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var router = routing.ConnectToRouter("Router"); - router.DelegateRouting(typeof(PoisonMessage)); - }); - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(PoisonMessage request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return Task.CompletedTask; - } - } - } - - class PoisonMessage : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/Poison/When_there_is_no_route.cs b/src/NServiceBus.Router.AcceptanceTests/Poison/When_there_is_no_route.cs deleted file mode 100644 index c3ad7e9..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/Poison/When_there_is_no_route.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.Poison -{ - using System.Linq; - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_there_is_no_route : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_move_message_to_poison_queue() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); - - cfg.UseStaticRoutingProtocol(); - }) - .WithEndpoint(c => c.When(s => s.Send(new PoisonMessage()))) - .WithEndpoint() - .WithPosionSpyComponent(t => t.BrokerAlpha()) - .Done(c => c.PoisonMessageDetected || c.RequestReceived) - .Run(); - - Assert.IsFalse(result.RequestReceived); - Assert.IsTrue(result.PoisonMessageDetected); - Assert.AreEqual("No route for destination ThereIsNoRoute.Receiver", result.ExceptionMessage); - Assert.IsTrue(result.Logs.Any(l => l.Message.Contains(result.ExceptionMessage))); - } - - class Context : ScenarioContext, IPoisonSpyContext - { - public bool RequestReceived { get; set; } - public string ExceptionMessage { get; set; } - public bool PoisonMessageDetected { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var router = routing.ConnectToRouter("Router"); - router.RouteToEndpoint(typeof(PoisonMessage), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(PoisonMessage request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return Task.CompletedTask; - } - } - } - - class PoisonMessage : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_forwarding_a_message_via_sendonly_router.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_forwarding_a_message_via_sendonly_router.cs index 3a52528..1ddcec0 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_forwarding_a_message_via_sendonly_router.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_forwarding_a_message_via_sendonly_router.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_deliver_the_message() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddSendOnlyInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); }) @@ -41,7 +39,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); }); @@ -55,7 +55,7 @@ public Receiver() EndpointSetup(c => { //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages.cs index 1d3a76b..6551324 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_not_complain() var result = await Scenario.Define() .WithRouter("Router", (ctx, cfg) => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); cfg.AddRule(_ => new CustomDestinationRule(ctx)); @@ -63,7 +61,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var router = routing.ConnectToRouter("Router"); router.DelegateRouting(typeof(MyRequest)); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages_in_prerouting.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages_in_prerouting.cs index 29d19e5..bd03f71 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages_in_prerouting.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_intentionally_dropping_messages_in_prerouting.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -18,8 +16,8 @@ public async Task Should_not_complain() var result = await Scenario.Define() .WithRouter("Router", (ctx, cfg) => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); cfg.AddRule(_ => new DropMessagesRule(ctx)); @@ -59,7 +57,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var router = routing.ConnectToRouter("Router"); router.DelegateRouting(typeof(MyRequest)); c.Pipeline.Register(new RemoveIntentBehavior(), "Remove message intent header"); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_publisher_first.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_publisher_first.cs deleted file mode 100644 index 07b2d24..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_publisher_first.cs +++ /dev/null @@ -1,349 +0,0 @@ -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Linq; - using System.Threading.Tasks; - using AcceptanceTesting; - using AcceptanceTesting.Customization; - using Features; - using Migrator; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - using Pipeline; - using Unicast.Subscriptions; - using Unicast.Subscriptions.MessageDrivenSubscriptions; - using InMemoryPersistence = global::InMemoryPersistence; - - [TestFixture] - public class When_migrating_transport_publisher_first : NServiceBusAcceptanceTest - { - static string PublisherEndpointName => Conventions.EndpointNamingConvention(typeof(Publisher)); - static string SubscriberEndpointName => Conventions.EndpointNamingConvention(typeof(Subscriber)); - - [Test] - public async Task Should_not_lose_events() - { - var subscriptionStorage = new InMemorySubscriptionStorage(); - - var beforeMigration = await Scenario.Define(c => c.Step = "Before migration") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Subscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventReceivedByNonMigratedSubscriber) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(beforeMigration.EventReceivedByNonMigratedSubscriber); - - //After the publisher is migrated we should not need to re-subscribe to be able to receive events - //To prove that we don't call subscribe in this test run - var publisherMigrated = await Scenario.Define(c => c.Step = "Publisher migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.EndpointsStarted, s => - { - return s.Publish(new MyEvent()); - })) - .WithEndpoint() - .Done(c => c.EventReceivedByNonMigratedSubscriber) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(publisherMigrated.EventReceivedByNonMigratedSubscriber); - - //After restarting the subscriber it sends the subscribe message to a migrated publisher - //To prove that a subscribe message can reach to publisher via the router we use a brand new subscription store - - subscriptionStorage = new InMemorySubscriptionStorage(); - var subscriberResubscribed = await Scenario.Define(c => c.Step = "Resubscribed after publisher migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Subscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventReceivedByNonMigratedSubscriber) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(subscriberResubscribed.EventReceivedByNonMigratedSubscriber); - - //Migrate subscriber - var subscriberMigrated = await Scenario.Define(c => c.Step = "Subscriber migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.EndpointsStarted, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.AreEqual(1, subscriberMigrated.EventsReceivedByMigratedSubscriber); - - var resubscribedNativeAfterMigration = await Scenario.Define(c => c.Step = "Resubscribed native after subscriber migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - config.Pipeline.Register(new UnsubscribeWhenMigratedSuppressingBehavior(), "Disables the unsubscribe behavior"); - - }).When(ctx => ctx.Subscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, async (s, ctx) => - { - await s.Subscribe(typeof(MyEvent)); - ctx.Subscribed = true; - })) - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1 && c.EventsReceivedAtTransportLevel >= 2) - .Run(TimeSpan.FromSeconds(30)); - - Assert.AreEqual(2, resubscribedNativeAfterMigration.EventsReceivedAtTransportLevel); - Assert.AreEqual(1, resubscribedNativeAfterMigration.EventsReceivedByMigratedSubscriber); - - //Re-subscribe after migration. This will send a subscribe message that will trigger removal of old subscription -- Unsubscribed will be set - var resubscribedAfterMigration = await Scenario.Define(c => c.Step = "Resubscribed after subscriber migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Unsubscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, (s, ctx) => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.AreEqual(1, resubscribedAfterMigration.EventsReceivedByMigratedSubscriber); - - //Compatibility mode disabled after all endpoints are migrated - var compatModeDisabled = await Scenario.Define(c => c.Step = "Compatibility mode disabled") - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(compatModeDisabled.EventsReceivedByMigratedSubscriber >= 1); - } - - class Context : ScenarioContext - { - public bool Subscribed { get; set; } - public bool EventReceivedByNonMigratedSubscriber { get; set; } - public int EventsReceivedByMigratedSubscriber { get; set; } - public string Step { get; set; } - public bool Unsubscribed { get; set; } - public int EventsReceivedAtTransportLevel { get; set; } - } - - class UnsubscribeWhenMigratedDetector : Behavior - { - ISubscriptionStorage subscriptionStorage; - Context scenarioContext; - - public UnsubscribeWhenMigratedDetector(ISubscriptionStorage subscriptionStorage, Context scenarioContext) - { - this.subscriptionStorage = subscriptionStorage; - this.scenarioContext = scenarioContext; - } - - public override async Task Invoke(ITransportReceiveContext context, Func next) - { - if (!context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeEndpoint", out var subscriberEndpoint) - || !context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeType", out var messageTypeString)) - { - await next(); - return; - } - - var messageType = new MessageType(messageTypeString); - var allSubscribers = await subscriptionStorage.GetSubscriberAddressesForMessage(new[] { messageType }, context.Extensions).ConfigureAwait(false); - var wasSubscribed = allSubscribers.Any(s => s.Endpoint == subscriberEndpoint); - - await next(); - - allSubscribers = await subscriptionStorage.GetSubscriberAddressesForMessage(new[] { messageType }, context.Extensions).ConfigureAwait(false); - var isSubscribed = allSubscribers.Any(s => s.Endpoint == subscriberEndpoint); - - scenarioContext.Unsubscribed = wasSubscribed && !isSubscribed; - } - } - - /// - /// Ensures that unsubscribe message is ignored in order to check if de-duplication works - /// - class UnsubscribeWhenMigratedSuppressingBehavior : Behavior - { - public override async Task Invoke(ITransportReceiveContext context, Func next) - { - if (context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeEndpoint", out _) - || context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeType", out _)) - { - return; - } - - await next(); - } - } - - class IgnoreDuplicatesDetector : Behavior - { - Context scenarioContext; - - public IgnoreDuplicatesDetector(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public override async Task Invoke(ITransportReceiveContext context, Func next) - { - await next().ConfigureAwait(false); - scenarioContext.EventsReceivedAtTransportLevel++; - } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - c.UseTransport().BrokerAlpha(); - c.OnEndpointSubscribed((args, ctx) => - { - ctx.Subscribed = true; - }); - }); - } - } - - class MigratedPublisher : EndpointConfigurationBuilder - { - public MigratedPublisher() - { - EndpointSetup(c => - { - c.OnEndpointSubscribed((args, ctx) => - { - ctx.Subscribed = true; - }); - c.Pipeline.Register(b => new UnsubscribeWhenMigratedDetector(b.Build(), b.Build()), "Removes old subscriptions"); - c.EnableTransportMigration(oldTrans => - { - oldTrans.BrokerAlpha(); - }, newTrans => - { - newTrans.BrokerYankee(); - }); - }).CustomEndpointName(PublisherEndpointName); - } - } - - class MigratedPublisherNoCompatMode : EndpointConfigurationBuilder - { - public MigratedPublisherNoCompatMode() - { - EndpointSetup(c => - { - c.UseTransport().BrokerYankee(); - }).CustomEndpointName(PublisherEndpointName); - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - var routing = c.UseTransport().BrokerAlpha().Routing(); - routing.RegisterPublisher(typeof(MyEvent), PublisherEndpointName); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventReceivedByNonMigratedSubscriber = true; - return Task.CompletedTask; - } - } - } - - class MigratedSubscriber : EndpointConfigurationBuilder - { - public MigratedSubscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - var routing = c.EnableTransportMigration(to => - { - to.BrokerAlpha(); - }, tn => - { - tn.BrokerYankee(); - }); - routing.RegisterPublisher(typeof(MyEvent), PublisherEndpointName); - - c.UsePersistence().UseStorage(new InMemorySubscriptionStorage()); - c.Pipeline.Register(b => new IgnoreDuplicatesDetector(b.Build()), - "Ignores events published both natively and via message driven pub sub"); - - }).CustomEndpointName(SubscriberEndpointName); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventsReceivedByMigratedSubscriber++; - return Task.CompletedTask; - } - } - } - - class MigratedSubscriberNoCompatMode : EndpointConfigurationBuilder - { - public MigratedSubscriberNoCompatMode() - { - EndpointSetup(c => - { - c.DisableFeature(); - c.UseTransport().BrokerYankee(); - - }).CustomEndpointName(SubscriberEndpointName); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventsReceivedByMigratedSubscriber++; - return Task.CompletedTask; - } - } - } - - class MyEvent : IEvent - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_sends.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_sends.cs deleted file mode 100644 index 81c731a..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_sends.cs +++ /dev/null @@ -1,279 +0,0 @@ -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Threading.Tasks; - using AcceptanceTesting; - using AcceptanceTesting.Customization; - using Migrator; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - - [TestFixture] - public class When_migrating_transport_sends : NServiceBusAcceptanceTest - { - static string SenderEndpointName => Conventions.EndpointNamingConvention(typeof(Sender)); - static string ReceiverEndpointName => Conventions.EndpointNamingConvention(typeof(Receiver)); - - [Test] - public async Task Should_not_lose_messages_before_migration() - { - var beforeMigration = await Scenario.Define() - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Send(new MyMessage()))) - .WithEndpoint() - .Done(c => c.MessageReceivedByNonMigratedReceiver && c.ReplyReceivedByNonMigratedSender) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(beforeMigration.MessageReceivedByNonMigratedReceiver); - Assert.IsTrue(beforeMigration.ReplyReceivedByNonMigratedSender); - } - - [Test] - public async Task Should_not_lose_messages_when_sender_is_migrated() - { - - var senderMigrated = await Scenario.Define() - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Send(new MyMessage()))) - .WithEndpoint() - .Done(c => c.MessageReceivedByNonMigratedReceiver && c.ReplyReceivedByMigratedSender >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(senderMigrated.MessageReceivedByNonMigratedReceiver); - Assert.IsTrue(senderMigrated.ReplyReceivedByMigratedSender >= 1); - } - - [Test] - public async Task Should_not_lose_messages_when_receiver_is_migrated() - { - - var senderMigrated = await Scenario.Define() - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Send(new MyMessage()))) - .WithEndpoint() - .Done(c => c.MessagesReceivedByMigratedReceiver >= 1 && c.ReplyReceivedByNonMigratedSender) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(senderMigrated.ReplyReceivedByNonMigratedSender); - Assert.IsTrue(senderMigrated.MessagesReceivedByMigratedReceiver >= 1); - } - - [Test] - public async Task Should_not_lose_messages_when_both_sender_and_receiver_is_migrated() - { - var receiverMigrated = await Scenario.Define() - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Send(new MyMessage()))) - .WithEndpoint() - .Done(c => c.MessagesReceivedByMigratedReceiver >= 1 && c.ReplyReceivedByMigratedSender >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(receiverMigrated.MessagesReceivedByMigratedReceiver >= 1); - Assert.IsTrue(receiverMigrated.ReplyReceivedByMigratedSender >= 1); - } - - [Test] - public async Task Should_not_lose_messages_after_migration() - { - var compatModeDisabled = await Scenario.Define() - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Send(new MyMessage()))) - .WithEndpoint() - .Done(c => c.MessagesReceivedByMigratedReceiver >= 1 && c.ReplyReceivedByMigratedSender >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(compatModeDisabled.MessagesReceivedByMigratedReceiver >= 1); - Assert.IsTrue(compatModeDisabled.ReplyReceivedByMigratedSender >= 1); - } - - class Context : ScenarioContext - { - public bool MessageReceivedByNonMigratedReceiver { get; set; } - public int MessagesReceivedByMigratedReceiver { get; set; } - public bool ReplyReceivedByNonMigratedSender { get; set; } - public int ReplyReceivedByMigratedSender { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - routing.RouteToEndpoint(typeof(MyMessage), ReceiverEndpointName); - }); - } - - class MyReplyHandler : IHandleMessages - { - Context scenarioContext; - - public MyReplyHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyReply message, IMessageHandlerContext context) - { - scenarioContext.ReplyReceivedByNonMigratedSender = true; - return Task.CompletedTask; - } - } - } - - class MigratedSender : EndpointConfigurationBuilder - { - public MigratedSender() - { - EndpointSetup(c => - { - var routing = c.EnableTransportMigration(oldTrans => - { - oldTrans.BrokerAlpha(); - }, newTrans => - { - newTrans.BrokerYankee(); - }); - routing.RouteToEndpoint(typeof(MyMessage), ReceiverEndpointName); - }).CustomEndpointName(SenderEndpointName); - } - - class MyReplyHandler : IHandleMessages - { - Context scenarioContext; - - public MyReplyHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyReply message, IMessageHandlerContext context) - { - scenarioContext.ReplyReceivedByMigratedSender++; - return Task.CompletedTask; - } - } - } - - class MigratedSenderNoCompatMode : EndpointConfigurationBuilder - { - public MigratedSenderNoCompatMode() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerYankee().Routing(); - routing.RouteToEndpoint(typeof(MyMessage), ReceiverEndpointName); - }).CustomEndpointName(SenderEndpointName); - } - - class MyReplyHandler : IHandleMessages - { - Context scenarioContext; - - public MyReplyHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyReply message, IMessageHandlerContext context) - { - scenarioContext.ReplyReceivedByMigratedSender++; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - c.UseTransport().BrokerAlpha(); - }); - } - - class MyMessageHandler : IHandleMessages - { - Context scenarioContext; - - public MyMessageHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyMessage message, IMessageHandlerContext context) - { - scenarioContext.MessageReceivedByNonMigratedReceiver = true; - return context.Reply(new MyReply()); - } - } - } - - class MigratedReceiver : EndpointConfigurationBuilder - { - public MigratedReceiver() - { - EndpointSetup(c => - { - c.EnableTransportMigration(to => - { - to.BrokerAlpha(); - }, tn => - { - tn.BrokerYankee(); - }); - }).CustomEndpointName(ReceiverEndpointName); - } - - class MyMessageHandler : IHandleMessages - { - Context scenarioContext; - - public MyMessageHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyMessage message, IMessageHandlerContext context) - { - scenarioContext.MessagesReceivedByMigratedReceiver++; - return context.Reply(new MyReply()); - } - } - } - - class MigratedReceiverNoCompatMode : EndpointConfigurationBuilder - { - public MigratedReceiverNoCompatMode() - { - EndpointSetup(c => - { - c.UseTransport().BrokerYankee(); - - }).CustomEndpointName(ReceiverEndpointName); - } - - class MyMessageHandler : IHandleMessages - { - Context scenarioContext; - - public MyMessageHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyMessage message, IMessageHandlerContext context) - { - scenarioContext.MessagesReceivedByMigratedReceiver++; - return context.Reply(new MyReply()); - } - } - } - - class MyMessage : ICommand - { - } - - class MyReply : IMessage - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_subscriber_first.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_subscriber_first.cs deleted file mode 100644 index 5edf5a1..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_migrating_transport_subscriber_first.cs +++ /dev/null @@ -1,315 +0,0 @@ -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Linq; - using System.Threading.Tasks; - using AcceptanceTesting; - using AcceptanceTesting.Customization; - using Features; - using Migrator; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - using Pipeline; - using Unicast.Subscriptions; - using Unicast.Subscriptions.MessageDrivenSubscriptions; - using InMemoryPersistence = global::InMemoryPersistence; - - [TestFixture] - public class When_migrating_transport_subscriber_first : NServiceBusAcceptanceTest - { - static string PublisherEndpointName => Conventions.EndpointNamingConvention(typeof(Publisher)); - static string SubscriberEndpointName => Conventions.EndpointNamingConvention(typeof(Subscriber)); - - [Test] - public async Task Should_not_lose_events() - { - var subscriptionStorage = new InMemorySubscriptionStorage(); - - var beforeMigration = await Scenario.Define(c => c.Step = "Before migration") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Subscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventReceivedByNonMigratedSubscriber) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(beforeMigration.EventReceivedByNonMigratedSubscriber); - - //Migrate subscriber - //After the subscriber is migrated we should not need to re-subscribe to be able to receive events - //To prove that we don't call subscribe in this test run - var subscriberMigrated = await Scenario.Define(c => c.Step = "Subscriber migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.EndpointsStarted, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(subscriberMigrated.EventsReceivedByMigratedSubscriber >= 1); - - //After restarting the subscriber it sends the subscribe message to the publisher - //To prove that a subscribe message can reach to publisher via the router we use a brand new subscription store - subscriptionStorage = new InMemorySubscriptionStorage(); - var subscriberResubscribed = await Scenario.Define(c => c.Step = "Resubscribed after migration") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Subscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(subscriberResubscribed.EventsReceivedByMigratedSubscriber >= 1); - - //After migrating but prior to resubscribing we should detect that the published messages gets through two routers and drop it - var publisherMigrated = await Scenario.Define(c => c.Step = "Publisher migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.EndpointsStarted, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1 && c.EventsReceivedAtTransportLevel >= 2) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(publisherMigrated.EventsReceivedByMigratedSubscriber >= 1); - Assert.IsTrue(publisherMigrated.EventsReceivedAtTransportLevel >= 1); - - //After resubscribing we should detect that the subscribe messages gets through two routers and drop the old subscription - var resubscribedAfterPublisherMigrated = await Scenario.Define(c => c.Step = "Resubscribed after publisher migrated") - .WithEndpoint(c => c.CustomConfig(config => - { - config.UsePersistence().UseStorage(subscriptionStorage); - }).When(ctx => ctx.Unsubscribed, s => s.Publish(new MyEvent()))) - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Subscribe(typeof(MyEvent)))) - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1 && c.Unsubscribed) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(resubscribedAfterPublisherMigrated.EventsReceivedByMigratedSubscriber >= 1); - - //Compatibility mode disabled after all endpoints are migrated - var compatModeDisabled = await Scenario.Define(c => c.Step = "Compatibility mode disabled") - .WithEndpoint(c => c.When(ctx => ctx.EndpointsStarted, s => s.Publish(new MyEvent()))) - .WithEndpoint() - .Done(c => c.EventsReceivedByMigratedSubscriber >= 1) - .Run(TimeSpan.FromSeconds(30)); - - Assert.IsTrue(compatModeDisabled.EventsReceivedByMigratedSubscriber >= 1); - } - - class Context : ScenarioContext - { - public bool Subscribed { get; set; } - public bool EventReceivedByNonMigratedSubscriber { get; set; } - public int EventsReceivedByMigratedSubscriber { get; set; } - public string Step { get; set; } - public bool Unsubscribed { get; set; } - public int EventsReceivedAtTransportLevel { get; set; } - } - - class UnsubscribeWhenMigratedDetector : Behavior - { - ISubscriptionStorage subscriptionStorage; - Context scenarioContext; - - public UnsubscribeWhenMigratedDetector(ISubscriptionStorage subscriptionStorage, Context scenarioContext) - { - this.subscriptionStorage = subscriptionStorage; - this.scenarioContext = scenarioContext; - } - - public override async Task Invoke(ITransportReceiveContext context, Func next) - { - if (!context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeEndpoint", out var subscriberEndpoint) - || !context.Message.Headers.TryGetValue("NServiceBus.Router.Migrator.UnsubscribeType", out var messageTypeString)) - { - await next(); - return; - } - - var messageType = new MessageType(messageTypeString); - var allSubscribers = await subscriptionStorage.GetSubscriberAddressesForMessage(new[] { messageType }, context.Extensions).ConfigureAwait(false); - var wasSubscribed = allSubscribers.Any(s => s.Endpoint == subscriberEndpoint); - - await next(); - - allSubscribers = await subscriptionStorage.GetSubscriberAddressesForMessage(new[] { messageType }, context.Extensions).ConfigureAwait(false); - var isSubscribed = allSubscribers.Any(s => s.Endpoint == subscriberEndpoint); - - scenarioContext.Unsubscribed = wasSubscribed && !isSubscribed; - } - } - - class IgnoreDuplicatesDetector : Behavior - { - Context scenarioContext; - - public IgnoreDuplicatesDetector(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public override async Task Invoke(ITransportReceiveContext context, Func next) - { - await next().ConfigureAwait(false); - scenarioContext.EventsReceivedAtTransportLevel++; - } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - c.UseTransport().BrokerAlpha(); - c.OnEndpointSubscribed((args, ctx) => - { - ctx.Subscribed = true; - }); - }); - } - } - - class MigratedPublisher : EndpointConfigurationBuilder - { - public MigratedPublisher() - { - EndpointSetup(c => - { - c.OnEndpointSubscribed((args, ctx) => - { - ctx.Subscribed = true; - }); - c.Pipeline.Register(b => new UnsubscribeWhenMigratedDetector(b.Build(), b.Build()), "Removes old subscriptions"); - c.EnableTransportMigration(oldTrans => - { - oldTrans.BrokerAlpha(); - }, newTrans => - { - newTrans.BrokerYankee(); - }); - }).CustomEndpointName(PublisherEndpointName); - } - } - - class MigratedPublisherNoCompatMode : EndpointConfigurationBuilder - { - public MigratedPublisherNoCompatMode() - { - EndpointSetup(c => - { - c.UseTransport().BrokerYankee(); - }).CustomEndpointName(PublisherEndpointName); - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - - var routing = c.UseTransport().BrokerAlpha().Routing(); - routing.RegisterPublisher(typeof(MyEvent), PublisherEndpointName); - }); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventReceivedByNonMigratedSubscriber = true; - return Task.CompletedTask; - } - } - } - - class MigratedSubscriber : EndpointConfigurationBuilder - { - public MigratedSubscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - - var routing = c.EnableTransportMigration(to => - { - to.BrokerAlpha(); - }, tn => - { - tn.BrokerYankee(); - }); - - routing.RegisterPublisher(typeof(MyEvent), PublisherEndpointName); - - c.UsePersistence().UseStorage(new InMemorySubscriptionStorage()); - c.Pipeline.Register(b => new IgnoreDuplicatesDetector(b.Build()), - "Ignores events published both natively and via message driven pub sub"); - - }).CustomEndpointName(SubscriberEndpointName); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventsReceivedByMigratedSubscriber++; - return Task.CompletedTask; - } - } - } - - class MigratedSubscriberNoCompatMode : EndpointConfigurationBuilder - { - public MigratedSubscriberNoCompatMode() - { - EndpointSetup(c => - { - c.DisableFeature(); - c.UseTransport().BrokerYankee(); - - }).CustomEndpointName(SubscriberEndpointName); - } - - class MyEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyEvent message, IMessageHandlerContext context) - { - scenarioContext.EventsReceivedByMigratedSubscriber++; - return Task.CompletedTask; - } - } - } - - class MyEvent : IEvent - { - } - } -} diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_mutating_messages.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_mutating_messages.cs index 55a3a4e..0dab219 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_mutating_messages.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_mutating_messages.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -21,8 +19,8 @@ public async Task Receiver_should_see_modified_body() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); cfg.AddRule(_ => new MessageMutator()); @@ -44,7 +42,7 @@ class MessageMutator : IRule public Task Invoke(PreroutingContext context, Func next) { - var message = DeserializeMessage(context.Body, jsonSerializer); + var message = DeserializeMessage(context.Body.ToArray(), jsonSerializer); message.Number += 2; context.Body = SerializeMessage(message, jsonSerializer); return next(context); @@ -93,7 +91,8 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyMessage), Conventions.EndpointNamingConvention(typeof(Receiver))); }); @@ -107,7 +106,7 @@ public Receiver() EndpointSetup(c => { //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_not_all_interfaces_are_interested_in_an_event.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_not_all_interfaces_are_interested_in_an_event.cs index 1df84b5..50d481c 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_not_all_interfaces_are_interested_in_an_event.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_not_all_interfaces_are_interested_in_an_event.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,10 +15,11 @@ public async Task It_should_forward_the_message_only_to_interested_interfaces() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Red", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Green", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Red", false).Broker().Alpha(); + cfg.AddInterface("Green", false).Broker().Bravo(); + //Charlie broker is not interested in the event - cfg.AddInterface("Blue", t => t.BrokerCharlie()).InMemorySubscriptions(); + cfg.AddInterface("Blue", false).Broker().Charlie(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Green", "Red"); }) @@ -45,7 +44,9 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + c.OnEndpointSubscribed((args, context) => { context.EventSubscribed = true; @@ -60,7 +61,10 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publisher_is_scaled_out.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publisher_is_scaled_out.cs index 98ef402..1c78fdf 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publisher_is_scaled_out.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publisher_is_scaled_out.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -20,8 +18,9 @@ public async Task Should_deliver_subscribe_messages_to_all_instances() var result = await Scenario.Define() .WithRouter("Router", cfg => { - var leftIface = cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + var leftIface = cfg.AddInterface("Left", false); + leftIface.Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); leftIface.EndpointInstances.AddOrReplaceInstances("publishers", new List @@ -53,7 +52,7 @@ public PublisherA() { EndpointSetup(c => { - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); c.MakeInstanceUniquelyAddressable("A"); c.OnEndpointSubscribed((args, context) => { @@ -69,7 +68,7 @@ public PublisherB() { EndpointSetup(c => { - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); c.MakeInstanceUniquelyAddressable("B"); c.OnEndpointSubscribed((args, context) => { @@ -85,7 +84,9 @@ public Subscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), PublisherEndpointName); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented.cs deleted file mode 100644 index fce3abd..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented.cs +++ /dev/null @@ -1,145 +0,0 @@ -#if NET461 -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Threading.Tasks; - using System.Transactions; - using AcceptanceTesting; - using Events; - using Features; - using NServiceBus; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - using Conventions = AcceptanceTesting.Customization.Conventions; - - [TestFixture] - public class When_publishing_from_asb_endpoint_oriented : NServiceBusAcceptanceTest - { - static string PublisherEndpointName => Conventions.EndpointNamingConvention(typeof(Publisher)); - - [Test] - public async Task It_should_deliver_the_message_to_both_subscribers() - { - var result = await Scenario.Define() - .WithRouter("Router", (c, cfg) => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - var leftIface = cfg.AddInterface("Right", t => - { - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - t.ConnectionString(connString); - - var topology = t.UseEndpointOrientedTopology(); - topology.RegisterPublisher(typeof(MyAsbEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - leftIface.LimitMessageProcessingConcurrencyTo(1); //To ensure when tracer arrives the subscribe request has already been processed.; - cfg.AddRule(_ => new SuppressTransactionScopeRule()); - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(x => x.EventSubscribed, s => s.Publish(new MyAsbEvent()))) - .WithEndpoint(c => c.When(async s => - { - await s.Subscribe().ConfigureAwait(false); - await s.Send(new TracerMessage()).ConfigureAwait(false); - })) - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - } - - class SuppressTransactionScopeRule : IRule - { - public Task Invoke(RawContext context, Func next) - { - using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) - { - return next(context); - } - } - } - - static bool EventConvention(Type x) - { - return x.Namespace == "Events"; - } - - class Context : ScenarioContext - { - public bool EventDelivered { get; set; } - public bool EventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - var transport = c.UseTransport(); - transport.ConnectionString(connString); - transport.UseEndpointOrientedTopology(); - - c.Conventions().DefiningEventsAs(EventConvention); - }); - } - - class TracerHandler : IHandleMessages - { - Context scenarioContext; - - public TracerHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(TracerMessage message, IMessageHandlerContext context) - { - scenarioContext.EventSubscribed = true; - return Task.CompletedTask; - } - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - var routing = c.UseTransport().BrokerAlpha().Routing(); - var ramp = routing.ConnectToRouter("Router"); - ramp.RegisterPublisher(typeof(MyAsbEvent), PublisherEndpointName); - ramp.RouteToEndpoint(typeof(TracerMessage), PublisherEndpointName); - - c.Conventions().DefiningEventsAs(EventConvention); - }); - } - - class BaseEventHandler : IHandleMessages - { - Context scenarioContext; - - public BaseEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyAsbEvent message, IMessageHandlerContext context) - { - scenarioContext.EventDelivered = true; - return Task.CompletedTask; - } - } - } - - class TracerMessage : IMessage - { - } - } -} -#endif diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented_while_router_is_restarted.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented_while_router_is_restarted.cs deleted file mode 100644 index 8962534..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_asb_endpoint_oriented_while_router_is_restarted.cs +++ /dev/null @@ -1,159 +0,0 @@ -#if NET461 -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Threading.Tasks; - using System.Transactions; - using AcceptanceTesting; - using Events; - using Features; - using NServiceBus; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - using Conventions = AcceptanceTesting.Customization.Conventions; - - [TestFixture] - public class When_publishing_from_asb_endpoint_oriented_while_router_is_restarted : NServiceBusAcceptanceTest - { - InMemorySubscriptionStorage subscriptionStorage = new InMemorySubscriptionStorage(); - static string PublisherEndpointName => Conventions.EndpointNamingConvention(typeof(Publisher)); - - [Test] - public async Task It_should_deliver_the_message_to_both_subscribers() - { - var result = await Scenario.Define() - .WithRouter("Router", ConfigureRouter) - .WithEndpoint(c => c.When(x => x.EventSubscribed, s => s.Publish(new MyAsbEvent()))) - .WithEndpoint(c => c.When(async s => - { - await s.Subscribe().ConfigureAwait(false); - await s.Send(new TracerMessage()).ConfigureAwait(false); - })) - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - Console.WriteLine("Restarting router"); - - result = await Scenario.Define() - .WithRouter("Router", ConfigureRouter) - .WithEndpoint(c => c.When(x => x.EndpointsStarted, s => s.Publish(new MyAsbEvent()))) - .WithEndpoint() - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - } - - void ConfigureRouter(Context c, RouterConfiguration cfg) - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).EnableMessageDrivenPublishSubscribe(subscriptionStorage); - var leftIface = cfg.AddInterface("Right", t => - { - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - t.ConnectionString(connString); - - var topology = t.UseEndpointOrientedTopology(); - topology.EnableMigrationToForwardingTopology(); - topology.RegisterPublisher(typeof(MyAsbEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); - }); - leftIface.LimitMessageProcessingConcurrencyTo(1); //To ensure when tracer arrives the subscribe request has already been processed.; - cfg.AddRule(_ => new SuppressTransactionScopeRule()); - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - } - - class SuppressTransactionScopeRule : IRule - { - public Task Invoke(RawContext context, Func next) - { - using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) - { - return next(context); - } - } - } - - static bool EventConvention(Type x) - { - return x.Namespace == "Events"; - } - - class Context : ScenarioContext - { - public bool EventDelivered { get; set; } - public bool EventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - var transport = c.UseTransport(); - transport.ConnectionString(connString); - transport.UseEndpointOrientedTopology(); - - c.Conventions().DefiningEventsAs(EventConvention); - }); - } - - class TracerHandler : IHandleMessages - { - Context scenarioContext; - - public TracerHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(TracerMessage message, IMessageHandlerContext context) - { - scenarioContext.EventSubscribed = true; - return Task.CompletedTask; - } - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - var routing = c.UseTransport().BrokerAlpha().Routing(); - var ramp = routing.ConnectToRouter("Router"); - ramp.RegisterPublisher(typeof(MyAsbEvent), PublisherEndpointName); - ramp.RouteToEndpoint(typeof(TracerMessage), PublisherEndpointName); - - c.Conventions().DefiningEventsAs(EventConvention); - }); - } - - class BaseEventHandler : IHandleMessages - { - Context scenarioContext; - - public BaseEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyAsbEvent message, IMessageHandlerContext context) - { - scenarioContext.EventDelivered = true; - return Task.CompletedTask; - } - } - } - - class TracerMessage : IMessage - { - } - } -} -#endif diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_endpoint_auto.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_endpoint_auto.cs index 7d00251..f7bbd68 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_endpoint_auto.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_endpoint_auto.cs @@ -1,143 +1,151 @@ -using System.Threading.Tasks; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using InMemoryPersistence = global::InMemoryPersistence; - - [TestFixture] - public class When_publishing_from_message_driven_endpoint_auto : NServiceBusAcceptanceTest - { - [Test] - public async Task It_should_deliver_the_message_to_both_subscribers() - { - var alphaSubscriptionStore = new InMemorySubscriptionStorage(); - var bravoSubscriptionStore = new InMemorySubscriptionStorage(); - - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("A", t => t.BrokerAlpha()).EnableMessageDrivenPublishSubscribe(alphaSubscriptionStore); - cfg.AddInterface("B", t => t.BrokerBravo()).EnableMessageDrivenPublishSubscribe(bravoSubscriptionStore); - cfg.AddInterface("C", t => t.BrokerYankee()); - - cfg.UseStaticRoutingProtocol(); - }) - .WithEndpoint(c => - { - c.CustomConfig(cfg => - { - cfg.UsePersistence().UseStorage(alphaSubscriptionStore); - }).When(x => x.EndpointsStarted, async (s, ctx) => - { - //Need to retry sending because there is no reliable way to figure when the router is subscribed - while (!ctx.BaseEventDelivered || !ctx.DerivedEventDelivered) - { - await s.Publish(new MyDerivedEvent2()); - await Task.Delay(1000); - } - }); - }) - .WithEndpoint(c => c.CustomConfig(cfg => - { - cfg.UsePersistence().UseStorage(bravoSubscriptionStore); - })) - .WithEndpoint() - .Done(c => c.BaseEventDelivered && c.DerivedEventDelivered) - .Run(); - - Assert.IsTrue(result.BaseEventDelivered); - Assert.IsTrue(result.DerivedEventDelivered); - } - - class Context : ScenarioContext - { - public bool BaseEventDelivered { get; set; } - public bool DerivedEventDelivered { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - - routing.ConnectToRouter("Router", false, true); - }); - } - } - - class BaseEventSubscriber : EndpointConfigurationBuilder - { - public BaseEventSubscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerBravo() - .Routing(); - - routing.ConnectToRouter("Router", true, false); - }); - } - - class BaseEventHandler : IHandleMessages - { - Context scenarioContext; - - public BaseEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyBaseEvent2 message, IMessageHandlerContext context) - { - scenarioContext.BaseEventDelivered = true; - return Task.CompletedTask; - } - } - } - - class DerivedEventSubscriber : EndpointConfigurationBuilder - { - public DerivedEventSubscriber() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerYankee() - .Routing(); - - routing.ConnectToRouter("Router", true, false); - }); - } - - class DerivedEventHandler : IHandleMessages - { - Context scenarioContext; - - public DerivedEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyDerivedEvent2 message, IMessageHandlerContext context) - { - scenarioContext.DerivedEventDelivered = true; - return Task.CompletedTask; - } - } - } - - class MyBaseEvent2 : IEvent - { - } - - class MyDerivedEvent2 : MyBaseEvent2 - { - } - } -} +using System.Threading.Tasks; +using NServiceBus.AcceptanceTesting; +using NUnit.Framework; + +namespace NServiceBus.Router.AcceptanceTests.SingleRouter +{ + [TestFixture] + public class When_publishing_from_message_driven_endpoint_auto : NServiceBusAcceptanceTest + { + [Test] + public async Task It_should_deliver_the_message_to_both_subscribers() + { + var alphaSubscriptionStore = new InMemorySubscriptionStorage(); + var bravoSubscriptionStore = new InMemorySubscriptionStorage(); + + var result = await Scenario.Define() + .WithRouter("Router", cfg => + { + var a = cfg.AddInterface("A", false); + a.EnableMessageDrivenPublishSubscribe(alphaSubscriptionStore); + a.Broker().Alpha(); + + var b = cfg.AddInterface("B", false); + b.EnableMessageDrivenPublishSubscribe(alphaSubscriptionStore); + b.Broker().Bravo(); + + cfg.AddInterface("C").Broker().Yankee(); + + cfg.UseStaticRoutingProtocol(); + }) + .WithEndpoint(c => + { + c.CustomConfig(cfg => + { + cfg.UsePersistence().UseStorage(alphaSubscriptionStore); + }).When(x => x.EndpointsStarted, async (s, ctx) => + { + //Need to retry sending because there is no reliable way to figure when the router is subscribed + while (!ctx.BaseEventDelivered || !ctx.DerivedEventDelivered) + { + await s.Publish(new MyDerivedEvent2()); + await Task.Delay(1000); + } + }); + }) + .WithEndpoint(c => c.CustomConfig(cfg => + { + cfg.UsePersistence().UseStorage(bravoSubscriptionStore); + })) + .WithEndpoint() + .Done(c => c.BaseEventDelivered && c.DerivedEventDelivered) + .Run(); + + Assert.IsTrue(result.BaseEventDelivered); + Assert.IsTrue(result.DerivedEventDelivered); + } + + class Context : ScenarioContext + { + public bool BaseEventDelivered { get; set; } + public bool DerivedEventDelivered { get; set; } + } + + class Publisher : EndpointConfigurationBuilder + { + public Publisher() + { + EndpointSetup(c => + { + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); + + routing.ConnectToRouter("Router", false, true); + }); + } + } + + class BaseEventSubscriber : EndpointConfigurationBuilder + { + public BaseEventSubscriber() + { + EndpointSetup(c => + { + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); + + routing.ConnectToRouter("Router", true, false); + }); + } + + class BaseEventHandler : IHandleMessages + { + Context scenarioContext; + + public BaseEventHandler(Context scenarioContext) + { + this.scenarioContext = scenarioContext; + } + + public Task Handle(MyBaseEvent2 message, IMessageHandlerContext context) + { + scenarioContext.BaseEventDelivered = true; + return Task.CompletedTask; + } + } + } + + class DerivedEventSubscriber : EndpointConfigurationBuilder + { + public DerivedEventSubscriber() + { + EndpointSetup(c => + { + c.ConfigureBroker().Yankee(); + + var routing = c.ConfigureRouting(); + + routing.ConnectToRouter("Router", true, false); + }); + } + + class DerivedEventHandler : IHandleMessages + { + Context scenarioContext; + + public DerivedEventHandler(Context scenarioContext) + { + this.scenarioContext = scenarioContext; + } + + public Task Handle(MyDerivedEvent2 message, IMessageHandlerContext context) + { + scenarioContext.DerivedEventDelivered = true; + return Task.CompletedTask; + } + } + } + + class MyBaseEvent2 : IEvent + { + } + + class MyDerivedEvent2 : MyBaseEvent2 + { + } + } +} diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_pubsub_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_pubsub_endpoint.cs index 877da0b..0943147 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_pubsub_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_message_driven_pubsub_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); }) @@ -47,7 +45,9 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + c.OnEndpointSubscribed((args, context) => { @@ -70,7 +70,10 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyBaseEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); }); @@ -99,7 +102,9 @@ public DerivedEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyDerivedEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint.cs index d593a5f..26b9b62 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NServiceBus.Features; using NUnit.Framework; @@ -20,11 +18,12 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - var left = cfg.AddInterface("Left", t => t.BrokerYankee()); + var left = cfg.AddInterface("Left"); + left.Broker().Yankee(); //To ensure when tracer arrives the subscribe request has already been processed. left.LimitMessageProcessingConcurrencyTo(1); - - cfg.AddInterface("Right", t => t.BrokerAlpha()).InMemorySubscriptions(); + + cfg.AddInterface("Right", false).Broker().Alpha(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); }) @@ -61,7 +60,7 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerYankee(); + c.ConfigureBroker().Yankee(); }); } @@ -95,8 +94,10 @@ public BaseEventSubscriber() { EndpointSetup(c => { + c.ConfigureBroker().Alpha(); + c.DisableFeature(); - var routing = c.UseTransport().BrokerAlpha().Routing(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyBaseEvent1), PublisherEndpoint); bridge.RouteToEndpoint(typeof(TracerMessage), PublisherEndpoint); @@ -126,8 +127,10 @@ public DerivedEventSubscriber() { EndpointSetup(c => { + c.ConfigureBroker().Alpha(); + c.DisableFeature(); - var routing = c.UseTransport().BrokerAlpha().Routing(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyDerivedEvent1), PublisherEndpoint); bridge.RouteToEndpoint(typeof(TracerMessage), PublisherEndpoint); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint_auto.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint_auto.cs index 4b2205e..a29eab6 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint_auto.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_publishing_from_native_pubsub_endpoint_auto.cs @@ -1,13 +1,9 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter { - using InMemoryPersistence = global::InMemoryPersistence; - [TestFixture] public class When_publishing_from_native_pubsub_endpoint_auto : NServiceBusAcceptanceTest { @@ -19,9 +15,11 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("A", t => t.BrokerZulu()); - cfg.AddInterface("B", t => t.BrokerYankee()); - cfg.AddInterface("C", t => t.BrokerAlpha()).EnableMessageDrivenPublishSubscribe(alphaSubscriptionStore); + cfg.AddInterface("A").Broker().Zulu(); + cfg.AddInterface("B").Broker().Yankee(); + var c = cfg.AddInterface("C", false); + c.Broker().Alpha(); + c.EnableMessageDrivenPublishSubscribe(alphaSubscriptionStore); cfg.UseStaticRoutingProtocol(); }) @@ -62,7 +60,7 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerZulu(); + c.ConfigureBroker().Zulu(); }); } } @@ -73,8 +71,9 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerYankee() - .Routing(); + c.ConfigureBroker().Yankee(); + + var routing = c.ConfigureRouting(); routing.ConnectToRouter("Router", true, false); }); @@ -103,8 +102,9 @@ public DerivedEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha() - .Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); routing.ConnectToRouter("Router", true, false); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_receiver_is_scaled_out.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_receiver_is_scaled_out.cs index 428c342..e995475 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_receiver_is_scaled_out.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_receiver_is_scaled_out.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -21,9 +19,9 @@ public async Task Should_deliver_messages_to_all_instances() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - var right = cfg.AddInterface("Right", t => t.BrokerBravo()); - right.InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + var right = cfg.AddInterface("Right", false); + right.Broker().Bravo(); right.EndpointInstances.AddOrReplaceInstances("config", new List { @@ -63,7 +61,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyRequest), ReceiverEndpointName); }); @@ -76,7 +76,7 @@ public ReceiverA() { EndpointSetup(c => { - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); c.MakeInstanceUniquelyAddressable("A"); }) .CustomEndpointName(ReceiverEndpointName); @@ -106,7 +106,7 @@ public ReceiverB() { EndpointSetup(c => { - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); c.MakeInstanceUniquelyAddressable("B"); }) .CustomEndpointName(ReceiverEndpointName); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message.cs index a61c1e2..ab0aec8 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_deliver_the_reply_without_the_need_to_configure_the_bri var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); }) @@ -29,7 +27,7 @@ public async Task Should_deliver_the_reply_without_the_need_to_configure_the_bri Assert.IsTrue(result.RequestReceived); Assert.IsTrue(result.ResponseReceived); - Assert.AreEqual("Router@Alpha", result.ReplyToInTheResponse); + Assert.AreEqual("Router", result.ReplyToInTheResponse); } class Context : ScenarioContext @@ -45,7 +43,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); }); @@ -77,7 +77,7 @@ public Receiver() EndpointSetup(c => { //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message_with_asb.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message_with_asb.cs deleted file mode 100644 index 268a107..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_message_with_asb.cs +++ /dev/null @@ -1,132 +0,0 @@ -#if NET461 -using System; -using System.Threading.Tasks; -using System.Transactions; -using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; -using NServiceBus.Configuration.AdvancedExtensibility; -using NServiceBus.Serialization; -using NServiceBus.Settings; -using NUnit.Framework; - -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using AcceptanceTesting.Customization; - - [TestFixture] - public class When_replying_to_a_message_with_asb : NServiceBusAcceptanceTest - { - [Test] - public async Task Should_deliver_the_reply_without_the_need_to_configure_the_bridge() - { - var result = await Scenario.Define() - .WithRouter("Router", cfg => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => - { - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - t.ConnectionString(connString); - t.UseForwardingTopology(); - }); - cfg.CircuitBreakerThreshold = int.MaxValue; - cfg.DelayedRetries = 0; - cfg.AddRule(_ => new SuppressTransactionScopeRule()); - cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); - }) - .WithEndpoint(c => c.When(s => s.Send(new MyRequest()))) - .WithEndpoint() - .Done(c => c.RequestReceived && c.ResponseReceived) - .Run(); - - Assert.IsTrue(result.RequestReceived); - Assert.IsTrue(result.ResponseReceived); - } - - class SuppressTransactionScopeRule : IRule - { - public Task Invoke(RawContext context, Func next) - { - using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) - { - return next(context); - } - } - } - - class Context : ScenarioContext - { - public bool RequestReceived { get; set; } - public bool ResponseReceived { get; set; } - } - - class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(c => - { - var routing = c.UseTransport().BrokerAlpha().Routing(); - var ramp = routing.ConnectToRouter("Router"); - ramp.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); - }); - } - - class MyResponseHandler : IHandleMessages - { - Context scenarioContext; - - public MyResponseHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyResponse response, IMessageHandlerContext context) - { - scenarioContext.ResponseReceived = true; - return Task.CompletedTask; - } - } - } - - class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(c => - { - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - var transport = c.UseTransport(); - transport.ConnectionString(connString); - transport.UseForwardingTopology(); - }); - } - - class MyRequestHandler : IHandleMessages - { - Context scenarioContext; - - public MyRequestHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyRequest request, IMessageHandlerContext context) - { - scenarioContext.RequestReceived = true; - return context.Reply(new MyResponse()); - } - } - } - - class MyRequest : IMessage - { - } - - class MyResponse : IMessage - { - } - } -} -#endif \ No newline at end of file diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_reply.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_reply.cs index 32b4931..944e848 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_reply.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_a_reply.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_deliver_the_final_reply() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); }) @@ -45,7 +43,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); }); @@ -76,7 +76,7 @@ public Receiver() EndpointSetup(c => { //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_message_driven_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_message_driven_endpoint.cs index d2c4917..252492d 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_message_driven_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_message_driven_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NServiceBus.Features; using NUnit.Framework; @@ -20,11 +18,12 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - var left = cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); + var left = cfg.AddInterface("Left", false); + left.Broker().Alpha(); //To ensure when tracer arrives the subscribe request has already been processed. left.LimitMessageProcessingConcurrencyTo(1); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); }) @@ -53,7 +52,8 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -85,8 +85,11 @@ public Subscriber() { EndpointSetup(c => { + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + c.DisableFeature(); - var routing = c.UseTransport().BrokerBravo().Routing(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), PublisherEndpoint); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_native_pubsub_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_native_pubsub_endpoint.cs index cb67eaf..752717e 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_native_pubsub_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_replying_to_an_event_from_native_pubsub_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NServiceBus.Features; using NUnit.Framework; @@ -20,11 +18,12 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - var left = cfg.AddInterface("Left", t => t.BrokerYankee()); + var left = cfg.AddInterface("Left"); + left.Broker().Yankee(); //To ensure when tracer arrives the subscribe request has already been processed. left.LimitMessageProcessingConcurrencyTo(1); - cfg.AddInterface("Right", t => t.BrokerZulu()); + cfg.AddInterface("Right").Broker().Zulu(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); }) @@ -54,7 +53,7 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerYankee(); + c.ConfigureBroker().Yankee(); }); } @@ -97,8 +96,10 @@ public Subscriber() { EndpointSetup(c => { + c.ConfigureBroker().Zulu(); + c.DisableFeature(); - var routing = c.UseTransport().BrokerZulu().Routing(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), PublisherEndpoint); bridge.RouteToEndpoint(typeof(TracerMessage), PublisherEndpoint); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_routing_metrics.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_routing_metrics.cs index 242afe2..eb8fa3d 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_routing_metrics.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_routing_metrics.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -15,16 +13,24 @@ public class When_routing_metrics : NServiceBusAcceptanceTest [Test] public async Task Should_deliver_the_reply_without_the_need_to_configure_the_bridge() { + var spyTransport = new AcceptanceTestingTransport(false, false); + spyTransport.Broker().Bravo(); + var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("MSMQ", t => t.Transactions(TransportTransactionMode.ReceiveOnly).BrokerAlpha()).DisableMessageDrivenPublishSubscribe(); - cfg.AddInterface("SQL", t => t.BrokerBravo()).DisableMessageDrivenPublishSubscribe(); + var msmq = cfg.AddInterface("MSMQ"); + msmq.DisableMessageDrivenPublishSubscribe(); + msmq.Broker().Alpha(); + var sql = cfg.AddInterface("SQL"); + sql.DisableMessageDrivenPublishSubscribe(); + sql.Broker().Bravo(); + cfg.UseStaticRoutingProtocol(); cfg.AddRule(c => new MetricsPreroutingTerminator("SQL", "Metrics")); }) - .WithSpyComponent("Metrics", t => t.BrokerBravo(), (scenarioContext, messageContext, _) => + .WithSpyComponent("Metrics", spyTransport, (scenarioContext, messageContext, _, __) => { if (messageContext.Headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) && messageTypes == "NServiceBus.Metrics.EndpointMetadataReport") @@ -81,7 +87,7 @@ public Sender() { EndpointSetup(c => { - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); c.EnableMetrics().SendMetricDataToServiceControl("Router", TimeSpan.FromSeconds(1)); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sender_delegates_routing.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sender_delegates_routing.cs index 2fcc4ea..0f8edbd 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sender_delegates_routing.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sender_delegates_routing.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -20,8 +18,8 @@ public async Task Should_use_custom_destination_finder_on_router() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); cfg.AddRule(_ => new CustomDestinationRule()); @@ -56,7 +54,9 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); var router = routing.ConnectToRouter("Router"); router.DelegateRouting(typeof(MyRequest)); }); @@ -86,7 +86,7 @@ public Receiver() EndpointSetup(c => { //No bridge configuration needed for reply - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_a_message_based_on_other_message.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_a_message_based_on_other_message.cs index 8d1da6d..da6b486 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_a_message_based_on_other_message.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_a_message_based_on_other_message.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_unwrap_correlation_id_when_sending_the_second_message() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); @@ -32,7 +30,7 @@ public async Task Should_unwrap_correlation_id_when_sending_the_second_message() Assert.IsTrue(result.ResponseReceived); //Ensure the correlation ID header to not grow forever - Assert.AreEqual(118, result.ReceivedCorrelationId.Length); + Assert.AreEqual(112, result.ReceivedCorrelationId.Length); } class Context : ScenarioContext @@ -48,7 +46,10 @@ public Sender() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyRequest), Conventions.EndpointNamingConvention(typeof(Receiver))); }); @@ -78,7 +79,10 @@ public Receiver() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyResponse), Conventions.EndpointNamingConvention(typeof(Sender))); }); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_from_sendonly_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_from_sendonly_endpoint.cs index cf803f0..b188470 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_from_sendonly_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_sending_from_sendonly_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -17,8 +15,8 @@ public async Task Should_deliver_the_message() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); }) @@ -42,7 +40,8 @@ public Sender() EndpointSetup(c => { c.SendOnly(); - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RouteToEndpoint(typeof(MyMessage), Conventions.EndpointNamingConvention(typeof(Receiver))); @@ -56,7 +55,7 @@ public Receiver() { EndpointSetup(c => { - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_not_aware_of_router.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_not_aware_of_router.cs index 4db5b58..01a9dd4 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_not_aware_of_router.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_not_aware_of_router.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -18,8 +16,12 @@ public async Task Subscribe_message_routing_has_to_be_configured_at_router() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + var left = cfg.AddInterface("Left", false); + left.Broker().Alpha(); + left.InMemorySubscriptions(); + var right = cfg.AddInterface("Right", false); + right.Broker().Bravo(); + right.InMemorySubscriptions(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); cfg.AddRule(_ => new PublisherRule()); @@ -54,7 +56,10 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + + var routing = c.ConfigureRouting(); + routing.EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -70,9 +75,12 @@ public Subscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + + var routing = c.ConfigureRouting(); + //Send Subscribe message to Router - routing.RegisterPublisher(typeof(MyEvent), "Router"); + routing.EnableMessageDrivenPubSubCompatibilityMode().RegisterPublisher(typeof(MyEvent), "Router"); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_scaled_out.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_scaled_out.cs index 18a8083..5f9ec4a 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_scaled_out.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscriber_is_scaled_out.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -20,8 +18,8 @@ public async Task Should_deliver_messages_to_all_instances() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); }) .WithEndpoint(s => s.When(ctx => ctx.Subscribed, async (session, ctx) => @@ -55,8 +53,9 @@ public Publisher() { EndpointSetup(c => { - c.UseTransport().BrokerAlpha(); - + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + c.OnEndpointSubscribed((args, context) => { context.Subscribed = true; @@ -71,7 +70,9 @@ public SubscriberA() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); @@ -104,7 +105,8 @@ public SubscriberB() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyEvent), Conventions.EndpointNamingConvention(typeof(Publisher))); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_asb.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_asb.cs deleted file mode 100644 index 83a6fcb..0000000 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_asb.cs +++ /dev/null @@ -1,121 +0,0 @@ -#if NET461 -namespace NServiceBus.Router.AcceptanceTests.SingleRouter -{ - using System; - using System.Threading.Tasks; - using AcceptanceTesting; - using Configuration.AdvancedExtensibility; - using Events; - using Features; - using NServiceBus; - using NServiceBus.AcceptanceTests; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NUnit.Framework; - using Serialization; - using Settings; - using Conventions = AcceptanceTesting.Customization.Conventions; - - [TestFixture] - public class When_subscribing_from_asb : NServiceBusAcceptanceTest - { - static string PublisherEndpointName => Conventions.EndpointNamingConvention(typeof(Publisher)); - - [Test] - public async Task It_should_deliver_the_message_even_is_subscriber_name_exceeds_the_asb_limit() - { - var result = await Scenario.Define() - .WithRouter("Router", (c, cfg) => - { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - var leftIface = cfg.AddInterface("Right", t => - { - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - t.ConnectionString(connString); - t.Transactions(TransportTransactionMode.ReceiveOnly); - - t.UseForwardingTopology(); - t.Sanitization().UseStrategy(); - }); - leftIface.LimitMessageProcessingConcurrencyTo(1); //To ensure when tracer arrives the subscribe request has already been processed.; - cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); - }) - .WithEndpoint(c => c.When(x => x.EventSubscribed, s => s.Publish(new MyAsbEvent()))) - .WithEndpoint(c => c.When(async s => - { - await s.Subscribe().ConfigureAwait(false); - })) - .Done(c => c.EventDelivered) - .Run(); - - Assert.IsTrue(result.EventDelivered); - } - - static bool EventConvention(Type x) - { - return x.Namespace == "Events"; - } - - class Context : ScenarioContext - { - public bool EventDelivered { get; set; } - public bool EventSubscribed { get; set; } - } - - class Publisher : EndpointConfigurationBuilder - { - public Publisher() - { - EndpointSetup(c => - { - //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); - c.LimitMessageProcessingConcurrencyTo(1); - c.Conventions().DefiningEventsAs(EventConvention); - c.OnEndpointSubscribed((args, context) => - { - context.EventSubscribed = true; - }); - }); - } - } - - class Subscriber : EndpointConfigurationBuilder - { - public Subscriber() - { - EndpointSetup(c => - { - c.DisableFeature(); - - var connString = Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString"); - var transport = c.UseTransport(); - transport.ConnectionString(connString); - transport.UseForwardingTopology(); - transport.Sanitization().UseStrategy(); - - var router = transport.Routing().ConnectToRouter("Router"); - router.RegisterPublisher(typeof(MyAsbEvent), PublisherEndpointName); - - c.Conventions().DefiningEventsAs(EventConvention); - }).CustomEndpointName("SubscriberWithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongName"); - } - - class MyAsbEventHandler : IHandleMessages - { - Context scenarioContext; - - public MyAsbEventHandler(Context scenarioContext) - { - this.scenarioContext = scenarioContext; - } - - public Task Handle(MyAsbEvent message, IMessageHandlerContext context) - { - scenarioContext.EventDelivered = true; - return Task.CompletedTask; - } - } - } - } -} -#endif diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_and_message_driven_endpoints.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_and_message_driven_endpoints.cs index 18aba26..7090ec7 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_and_message_driven_endpoints.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_and_message_driven_endpoints.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -19,13 +17,16 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("B", t => t.BrokerYankee()).LimitMessageProcessingConcurrencyTo(1); + var b = cfg.AddInterface("B"); + b.LimitMessageProcessingConcurrencyTo(1); + b.Broker().Yankee(); //BaseEventSubscriber - Broker A - cfg.AddInterface("A", t => t.BrokerAlpha()).InMemorySubscriptions(); + var a = cfg.AddInterface("A", false); + a.Broker().Alpha(); //DerivedEventSubscriber - Broker C` - cfg.AddInterface("C", t => t.BrokerZulu()); + cfg.AddInterface("C").Broker().Zulu(); var routeTable = cfg.UseStaticRoutingProtocol(); routeTable.AddForwardRoute("A", "B"); @@ -64,7 +65,7 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerYankee(); + c.ConfigureBroker().Yankee(); }); } @@ -98,7 +99,8 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyBaseEvent3), PublisherEndpoint); bridge.RouteToEndpoint(typeof(TracerMessage), PublisherEndpoint); @@ -128,8 +130,9 @@ public DerivedEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerZulu() - .Routing(); + c.ConfigureBroker().Zulu(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyDerivedEvent3), PublisherEndpoint); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_pubsub_endpoint.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_pubsub_endpoint.cs index 50db018..483d748 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_pubsub_endpoint.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_from_native_pubsub_endpoint.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -19,8 +17,8 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("A", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("B", t => t.BrokerYankee()); + cfg.AddInterface("A", false).Broker().Alpha(); + cfg.AddInterface("B").Broker().Yankee(); cfg.UseStaticRoutingProtocol().AddForwardRoute("B", "A"); }) @@ -49,7 +47,8 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -72,8 +71,9 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerYankee() - .Routing(); + c.ConfigureBroker().Yankee(); + + var routing = c.ConfigureRouting(); var ramp = routing.ConnectToRouter("Router"); ramp.RegisterPublisher(typeof(MyBaseEvent2), PublisherEndpoint); @@ -103,8 +103,9 @@ public DerivedEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerYankee() - .Routing(); + c.ConfigureBroker().Yankee(); + + var routing = c.ConfigureRouting(); var ramp = routing.ConnectToRouter("Router"); ramp.RegisterPublisher(typeof(MyDerivedEvent2), PublisherEndpoint); diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_locally_and_via_router.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_locally_and_via_router.cs index 4320a1e..92dd4d0 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_locally_and_via_router.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_subscribing_locally_and_via_router.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -20,8 +18,8 @@ public async Task It_should_receive_both_events() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("Left", t => t.BrokerAlpha()).InMemorySubscriptions(); - cfg.AddInterface("Right", t => t.BrokerBravo()).InMemorySubscriptions(); + cfg.AddInterface("Left", false).Broker().Alpha(); + cfg.AddInterface("Right", false).Broker().Bravo(); cfg.UseStaticRoutingProtocol().AddForwardRoute("Right", "Left"); cfg.UseStaticRoutingProtocol().AddForwardRoute("Left", "Right"); @@ -51,7 +49,8 @@ public LocalPublisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -75,7 +74,8 @@ public RemotePublisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerBravo(); + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -98,10 +98,12 @@ public Subscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerAlpha().Routing(); + c.ConfigureBroker().Alpha(); + var routing = c.ConfigureRouting(); + var routingCompat = routing.EnableMessageDrivenPubSubCompatibilityMode(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(RemoteEvent), Conventions.EndpointNamingConvention(typeof(RemotePublisher))); - routing.RegisterPublisher(typeof(LocalEvent), Conventions.EndpointNamingConvention(typeof(LocalPublisher))); + routingCompat.RegisterPublisher(typeof(LocalEvent), Conventions.EndpointNamingConvention(typeof(LocalPublisher))); }); } diff --git a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_using_sql_persistence.cs b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_using_sql_persistence.cs index 325722f..50243bd 100644 --- a/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_using_sql_persistence.cs +++ b/src/NServiceBus.Router.AcceptanceTests/SingleRouter/When_using_sql_persistence.cs @@ -1,8 +1,6 @@ using System.Data.SqlClient; using System.Threading.Tasks; using NServiceBus.AcceptanceTesting; -using NServiceBus.AcceptanceTests; -using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; namespace NServiceBus.Router.AcceptanceTests.SingleRouter @@ -23,8 +21,12 @@ public async Task It_should_deliver_the_message_to_both_subscribers() var result = await Scenario.Define() .WithRouter("Router", cfg => { - cfg.AddInterface("A", t => t.BrokerAlpha()).EnableMessageDrivenPublishSubscribe(GetSubscriptionStorage("A")); - cfg.AddInterface("D", t => t.BrokerBravo()).EnableMessageDrivenPublishSubscribe(GetSubscriptionStorage("D")); + var a = cfg.AddInterface("A", false); + a.Broker().Alpha(); + a.EnableMessageDrivenPublishSubscribe(GetSubscriptionStorage("A")); + var d = cfg.AddInterface("D", false); + d.Broker().Bravo(); + d.EnableMessageDrivenPublishSubscribe(GetSubscriptionStorage("D")); cfg.UseStaticRoutingProtocol().AddForwardRoute("D", "A"); }) @@ -67,7 +69,8 @@ public Publisher() EndpointSetup(c => { //No bridge configuration needed for publisher - c.UseTransport().BrokerAlpha(); + c.ConfigureBroker().Alpha(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); c.OnEndpointSubscribed((args, context) => { @@ -90,7 +93,10 @@ public BaseEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); + + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyBaseEvent), PublisherEndpoint); }); @@ -119,7 +125,8 @@ public DerivedEventSubscriber() { EndpointSetup(c => { - var routing = c.UseTransport().BrokerBravo().Routing(); + c.ConfigureBroker().Bravo(); + var routing = c.ConfigureRouting(); var bridge = routing.ConnectToRouter("Router"); bridge.RegisterPublisher(typeof(MyDerivedEvent), PublisherEndpoint); }); diff --git a/src/NServiceBus.Router.Connector/NServiceBus.Router.Connector.csproj b/src/NServiceBus.Router.Connector/NServiceBus.Router.Connector.csproj index 5fbbf6c..10234b2 100644 --- a/src/NServiceBus.Router.Connector/NServiceBus.Router.Connector.csproj +++ b/src/NServiceBus.Router.Connector/NServiceBus.Router.Connector.csproj @@ -1,6 +1,6 @@  - net461;netstandard2.0 + net48;net6.0 ..\..\binaries false true @@ -8,7 +8,7 @@ - + diff --git a/src/NServiceBus.Router.Connector/RouterAutoSubscribeBehavior.cs b/src/NServiceBus.Router.Connector/RouterAutoSubscribeBehavior.cs index db5f05e..b0c7690 100644 --- a/src/NServiceBus.Router.Connector/RouterAutoSubscribeBehavior.cs +++ b/src/NServiceBus.Router.Connector/RouterAutoSubscribeBehavior.cs @@ -34,7 +34,7 @@ public override async Task Invoke(IOutgoingPublishContext context, Func ne foreach (var router in autoPublishRouters) { var subscriber = new Subscriber(router, null); - await subscriptionStorage.Subscribe(subscriber, new MessageType(messageType), new ContextBag()).ConfigureAwait(false); + await subscriptionStorage.Subscribe(subscriber, new MessageType(messageType), new ContextBag(), context.CancellationToken).ConfigureAwait(false); } cache.AddOrUpdate(messageType, true, (key, _) => true); diff --git a/src/NServiceBus.Router.Connector/RouterConnectionFeature.cs b/src/NServiceBus.Router.Connector/RouterConnectionFeature.cs index 84d21c8..1db09be 100644 --- a/src/NServiceBus.Router.Connector/RouterConnectionFeature.cs +++ b/src/NServiceBus.Router.Connector/RouterConnectionFeature.cs @@ -1,4 +1,5 @@ using System.Linq; +using Microsoft.Extensions.DependencyInjection; using NServiceBus; using NServiceBus.Features; using NServiceBus.Routing; @@ -9,8 +10,9 @@ class RouterConnectionFeature : Feature { protected override void Setup(FeatureConfigurationContext context) { - var transportInfra = context.Settings.Get(); - var nativePubSub = transportInfra.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Multicast; + var transportDefinition = context.Settings.Get(); + + var nativePubSub = transportDefinition.SupportsPublishSubscribe; var settingsCollection = context.Settings.Get(); var unicastRouteTable = context.Settings.Get(); var bindings = context.Settings.Get(); @@ -28,11 +30,11 @@ protected override void Setup(FeatureConfigurationContext context) unicastRouteTable.AddOrReplaceRoutes("NServiceBus.Router_"+connection.RouterAddress, routes); } - if (transportInfra.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Unicast) + if (!nativePubSub) { //Register the auto-publish-to-router behavior - context.Pipeline.Register(b => new RouterAutoSubscribeBehavior(compiledSettings.AutoPublishRouters, b.Build()), "Automatically subscribes routers to published events."); + context.Pipeline.Register(b => new RouterAutoSubscribeBehavior(compiledSettings.AutoPublishRouters, b.GetService()), "Automatically subscribes routers to published events."); } @@ -43,12 +45,19 @@ protected override void Setup(FeatureConfigurationContext context) var isSendOnlyEndpoint = context.Settings.GetOrDefault("Endpoint.SendOnly"); if (!isSendOnlyEndpoint) { - var distributorAddress = context.Settings.GetOrDefault("LegacyDistributor.Address"); - var subscriberAddress = distributorAddress ?? context.Settings.LocalAddress(); + var subscriberAddress = context.LocalQueueAddress(); - context.Pipeline.Register(b => new RouterSubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), b.Build(), compiledSettings, nativePubSub), + context.Pipeline.Register(b => + { + var resolver = b.GetService(); + return new RouterSubscribeBehavior(resolver.ToTransportAddress(subscriberAddress), context.Settings.EndpointName(), b.GetService(), compiledSettings, nativePubSub); + }, "Dispatches the subscribe request via a router."); - context.Pipeline.Register(b => new RouterUnsubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), b.Build(), compiledSettings, nativePubSub), + context.Pipeline.Register(b => + { + var resolver = b.GetService(); + return new RouterUnsubscribeBehavior(resolver.ToTransportAddress(subscriberAddress), context.Settings.EndpointName(), b.GetService(), compiledSettings, nativePubSub); + }, "Dispatches the unsubscribe request via a router."); } } diff --git a/src/NServiceBus.Router.Connector/RouterSubscribeBehavior.cs b/src/NServiceBus.Router.Connector/RouterSubscribeBehavior.cs index a048d32..3775266 100644 --- a/src/NServiceBus.Router.Connector/RouterSubscribeBehavior.cs +++ b/src/NServiceBus.Router.Connector/RouterSubscribeBehavior.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using NServiceBus; using NServiceBus.Logging; @@ -9,7 +10,7 @@ class RouterSubscribeBehavior : Behavior { - public RouterSubscribeBehavior(string subscriberAddress, string subscriberEndpoint, IDispatchMessages dispatcher, CompiledRouterConnectionSettings compiledSettings, bool nativePubSub) + public RouterSubscribeBehavior(string subscriberAddress, string subscriberEndpoint, IMessageDispatcher dispatcher, CompiledRouterConnectionSettings compiledSettings, bool nativePubSub) { this.subscriberAddress = subscriberAddress; this.subscriberEndpoint = subscriberEndpoint; @@ -20,47 +21,49 @@ public RouterSubscribeBehavior(string subscriberAddress, string subscriberEndpoi public override async Task Invoke(ISubscribeContext context, Func next) { - var eventType = context.EventType; - compiledSettings.TryGetPublisher(eventType, out var publisherInfo); - - //Router auto-subscribe - foreach (var router in compiledSettings.AutoSubscribeRouters) + foreach (var eventType in context.EventTypes) { - if (publisherInfo != null && publisherInfo.Router == router) + compiledSettings.TryGetPublisher(eventType, out var publisherInfo); + + //Router auto-subscribe + foreach (var router in compiledSettings.AutoSubscribeRouters) { - //We have an explicit publisher registration for this router - continue; + if (publisherInfo != null && publisherInfo.Router == router) + { + //We have an explicit publisher registration for this router + continue; + } + Logger.Debug($"Sending subscribe request for {eventType.AssemblyQualifiedName} to router queue {router}."); + await SendSubscribeMessage(context, eventType, null, router, context.CancellationToken).ConfigureAwait(false); } - Logger.Debug($"Sending subscribe request for {eventType.AssemblyQualifiedName} to router queue {router}."); - await SendSubscribeMessage(context, eventType, null, router).ConfigureAwait(false); - } - if (publisherInfo != null) - { - Logger.Debug($"Sending subscribe request for {eventType.AssemblyQualifiedName} to router queue {publisherInfo.Router} to be forwarded to {publisherInfo.Endpoint}"); + if (publisherInfo != null) + { + Logger.Debug($"Sending subscribe request for {eventType.AssemblyQualifiedName} to router queue {publisherInfo.Router} to be forwarded to {publisherInfo.Endpoint}"); - await SendSubscribeMessage(context, eventType, publisherInfo.Endpoint, publisherInfo.Router).ConfigureAwait(false); + await SendSubscribeMessage(context, eventType, publisherInfo.Endpoint, publisherInfo.Router, context.CancellationToken).ConfigureAwait(false); - if (nativePubSub) + if (nativePubSub) + { + await next().ConfigureAwait(false); + } + } + else { await next().ConfigureAwait(false); } } - else - { - await next().ConfigureAwait(false); - } } - async Task SendSubscribeMessage(ISubscribeContext context, Type eventType, string publisherEndpoint, string router) + async Task SendSubscribeMessage(ISubscribeContext context, Type eventType, string publisherEndpoint, string router, CancellationToken cancellationToken) { - var subscriptionMessage = ControlMessageFactory.Create(MessageIntentEnum.Subscribe); + var subscriptionMessage = ControlMessageFactory.Create(MessageIntent.Subscribe); subscriptionMessage.Headers[Headers.SubscriptionMessageType] = eventType.AssemblyQualifiedName; subscriptionMessage.Headers[Headers.ReplyToAddress] = subscriberAddress; subscriptionMessage.Headers[Headers.SubscriberTransportAddress] = subscriberAddress; subscriptionMessage.Headers[Headers.SubscriberEndpoint] = subscriberEndpoint; - subscriptionMessage.Headers[Headers.TimeSent] = DateTimeExtensions.ToWireFormattedString(DateTime.UtcNow); + subscriptionMessage.Headers[Headers.TimeSent] = DateTimeOffsetHelper.ToWireFormattedString(DateTime.UtcNow); subscriptionMessage.Headers[Headers.NServiceBusVersion] = "6.3.1"; //The code has been copied from 6.3.1 if (publisherEndpoint != null) @@ -70,10 +73,10 @@ async Task SendSubscribeMessage(ISubscribeContext context, Type eventType, strin var transportOperation = new TransportOperation(subscriptionMessage, new UnicastAddressTag(router)); var transportTransaction = context.Extensions.GetOrCreate(); - await dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction, context.Extensions).ConfigureAwait(false); + await dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction, cancellationToken).ConfigureAwait(false); } - IDispatchMessages dispatcher; + IMessageDispatcher dispatcher; readonly CompiledRouterConnectionSettings compiledSettings; bool nativePubSub; string subscriberAddress; diff --git a/src/NServiceBus.Router.Connector/RouterUnsubscribeBehavior.cs b/src/NServiceBus.Router.Connector/RouterUnsubscribeBehavior.cs index ca6bebe..e079536 100644 --- a/src/NServiceBus.Router.Connector/RouterUnsubscribeBehavior.cs +++ b/src/NServiceBus.Router.Connector/RouterUnsubscribeBehavior.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using NServiceBus; using NServiceBus.Logging; @@ -10,7 +9,7 @@ class RouterUnsubscribeBehavior : Behavior { - public RouterUnsubscribeBehavior(string subscriberAddress, string subscriberEndpoint, IDispatchMessages dispatcher, CompiledRouterConnectionSettings compiledSettings, bool invokeTerminator) + public RouterUnsubscribeBehavior(string subscriberAddress, string subscriberEndpoint, IMessageDispatcher dispatcher, CompiledRouterConnectionSettings compiledSettings, bool invokeTerminator) { this.subscriberAddress = subscriberAddress; this.subscriberEndpoint = subscriberEndpoint; @@ -26,19 +25,19 @@ public override async Task Invoke(IUnsubscribeContext context, Func next) { Logger.Debug($"Sending unsubscribe request for {eventType.AssemblyQualifiedName} to router queue {publisherInfo.Router} to be forwarded to {publisherInfo.Endpoint}"); - var subscriptionMessage = ControlMessageFactory.Create(MessageIntentEnum.Unsubscribe); + var subscriptionMessage = ControlMessageFactory.Create(MessageIntent.Unsubscribe); subscriptionMessage.Headers[Headers.SubscriptionMessageType] = eventType.AssemblyQualifiedName; subscriptionMessage.Headers[Headers.ReplyToAddress] = subscriberAddress; subscriptionMessage.Headers[Headers.SubscriberTransportAddress] = subscriberAddress; subscriptionMessage.Headers[Headers.SubscriberEndpoint] = subscriberEndpoint; subscriptionMessage.Headers["NServiceBus.Bridge.DestinationEndpoint"] = publisherInfo.Endpoint; - subscriptionMessage.Headers[Headers.TimeSent] = DateTimeExtensions.ToWireFormattedString(DateTime.UtcNow); + subscriptionMessage.Headers[Headers.TimeSent] = DateTimeOffsetHelper.ToWireFormattedString(DateTime.UtcNow); subscriptionMessage.Headers[Headers.NServiceBusVersion] = "6.3.1"; //The code has been copied from 6.3.1 var transportOperation = new TransportOperation(subscriptionMessage, new UnicastAddressTag(publisherInfo.Router)); var transportTransaction = context.Extensions.GetOrCreate(); - await dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction, context.Extensions).ConfigureAwait(false); + await dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction, context.CancellationToken).ConfigureAwait(false); if (invokeTerminator) { @@ -51,7 +50,7 @@ public override async Task Invoke(IUnsubscribeContext context, Func next) } } - IDispatchMessages dispatcher; + IMessageDispatcher dispatcher; readonly CompiledRouterConnectionSettings compiledSettings; bool invokeTerminator; string subscriberAddress; diff --git a/src/NServiceBus.Router.SqlServer/DeduplicationExtensions.cs b/src/NServiceBus.Router.SqlServer/DeduplicationExtensions.cs index 949541b..226c79b 100644 --- a/src/NServiceBus.Router.SqlServer/DeduplicationExtensions.cs +++ b/src/NServiceBus.Router.SqlServer/DeduplicationExtensions.cs @@ -16,7 +16,7 @@ public static class DeduplicationExtensions /// Address of the other router. /// Connection factory to use. /// Size of an epoch. - public static void EnableDeduplication(this InterfaceConfiguration iface, string outgoingInterface, string destinationRouter, Func connectionFactory, int epochSize) + public static void EnableDeduplication(this InterfaceConfiguration iface, string outgoingInterface, string destinationRouter, Func connectionFactory, int epochSize) { var settings = iface.RouterConfiguration.Settings.GetOrCreate(); settings.EnableLink(iface.Name, outgoingInterface, destinationRouter, connectionFactory, epochSize); diff --git a/src/NServiceBus.Router.SqlServer/NServiceBus.Router.SqlServer.csproj b/src/NServiceBus.Router.SqlServer/NServiceBus.Router.SqlServer.csproj index 83caca7..7bed49c 100644 --- a/src/NServiceBus.Router.SqlServer/NServiceBus.Router.SqlServer.csproj +++ b/src/NServiceBus.Router.SqlServer/NServiceBus.Router.SqlServer.csproj @@ -1,6 +1,6 @@  - netstandard2.0 + net48;net6.0 ..\..\binaries false true @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/src/NServiceBus.Router.Tests/InboxPersisterTests.cs b/src/NServiceBus.Router.Tests/InboxPersisterTests.cs deleted file mode 100644 index 89c19fb..0000000 --- a/src/NServiceBus.Router.Tests/InboxPersisterTests.cs +++ /dev/null @@ -1,275 +0,0 @@ -using System.Data.SqlClient; -using System.Threading.Tasks; -using NServiceBus.Logging; -using NServiceBus.Router; -using NServiceBus.Router.Deduplication.Inbox; -using NUnit.Framework; - -[TestFixture] -public class InboxPersisterTests -{ - InboxPersister persister; - InboxInstaller installer; - - [SetUp] - public async Task PrepareTables() - { - LogManager.Use().Level(LogLevel.Debug); - - installer = new InboxInstaller("D"); - persister = new InboxPersister("S", "D", CreateConnection); - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - using (var trans = conn.BeginTransaction()) - { - await installer.Uninstall("S", conn, trans).ConfigureAwait(false); - await installer.Install("S", conn, trans).ConfigureAwait(false); - trans.Commit(); - } - - await persister.Prepare().ConfigureAwait(false); - } - } - - static SqlConnection CreateConnection() - { - return new SqlConnection("data source = (local); initial catalog=test1; integrated security=true"); - } - - [Test] - public async Task It_does_not_advance_if_state_has_not_been_initialized() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - try - { - await persister.Advance(2, 6, 9, conn).ConfigureAwait(false); - Assert.Fail("Expected exception"); - } - catch (ProcessCurrentMessageLaterException e) - { - Assert.AreEqual("Link state for S is not yet initialized. Cannot advance the epoch.", e.Message); - } - } - } - - [Test] - public async Task It_does_not_advance_if_table_has_holes() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - try - { - await persister.Advance(2, 6, 9, conn).ConfigureAwait(false); - Assert.Fail("Expected exception"); - } - catch (ProcessCurrentMessageLaterException e) - { - StringAssert.StartsWith("Inbox table Inbox_S_D_Right seems to have holes in the sequence.", e.Message); - } - } - } - - [Test] - public async Task It_does_not_advance_if_new_epoch_is_higher_then_expected() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - - try - { - await persister.Advance(3, 6, 9, conn).ConfigureAwait(false); - Assert.Fail("Expected exception"); - } - catch (ProcessCurrentMessageLaterException e) - { - Assert.AreEqual("The link state is at epoch 1 and is not ready to transition to epoch 3.", e.Message); - } - } - } - - [Test] - public async Task It_ignores_old_advance_epoch_messages() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - - var linkState = await persister.Advance(1, 3, 6, conn).ConfigureAwait(false); - - Assert.AreEqual(6, linkState.HeadSession.Hi); - Assert.AreEqual(0, linkState.TailSession.Lo); - } - } - - [Test] - public async Task It_does_advance_if_table_does_not_have_holes() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M3", 2, conn, null).ConfigureAwait(false); - - var linkState = await persister.Advance(2, 6, 9, conn).ConfigureAwait(false); - - Assert.AreEqual(9, linkState.HeadSession.Hi); - Assert.AreEqual(3, linkState.TailSession.Lo); - } - } - - [Test] - public async Task It_fails_when_trying_to_deduplicate() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M3", 2, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M4", 3, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M5", 4, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M6", 5, conn, null).ConfigureAwait(false); - - try - { - await persister.Deduplicate("M7", 6, conn, null).ConfigureAwait(false); - } - catch (ProcessCurrentMessageLaterException e) - { - Assert.AreEqual("The message requires advancing epoch. Moving it to the back of the queue.", e.Message); - } - } - } - - [Test] - public async Task It_de_duplicates_messages() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - var result = await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - - Assert.AreEqual(DeduplicationResult.Duplicate, result); - } - } - - [Test] - public async Task It_refreshes_state_if_stale_state_is_detected() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - var slowPersister = new InboxPersister("S", "D", CreateConnection); - await slowPersister.Prepare(); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M3", 2, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M4", 3, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M5", 4, conn, null).ConfigureAwait(false); - - await persister.Advance(2, 6, 9, conn); - - await slowPersister.Deduplicate("M7", 6, conn, null); - } - } - - [Test] - public async Task It_refreshes_state_when_constraint_violation_is_detected() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - var slowPersister = new InboxPersister("S", "D", CreateConnection); - await slowPersister.Prepare(); - - await persister.Deduplicate("M1", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M2", 1, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M3", 2, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M4", 3, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M5", 4, conn, null).ConfigureAwait(false); - - await persister.Advance(2, 6, 9, conn); - - var result = await slowPersister.Deduplicate("M2", 1, conn, null); - - Assert.AreEqual(DeduplicationResult.Duplicate, result); - } - } - - [Test] - public async Task It_uses_refreshed_state_to_detect_duplicates() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - await persister.Initialize(3, 6, 0, 3, conn).ConfigureAwait(false); - - var slowPersister = new InboxPersister("S", "D", CreateConnection); - await slowPersister.Prepare(); - - await persister.Deduplicate("M0", 0, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M0", 1, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M0", 2, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M0", 3, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M0", 4, conn, null).ConfigureAwait(false); - - await persister.Advance(2, 6, 9, conn); - - await persister.Deduplicate("M5", 5, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M6", 6, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M7", 7, conn, null).ConfigureAwait(false); - - await persister.Advance(3, 9, 12, conn); - - await persister.Deduplicate("M8", 8, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M9", 9, conn, null).ConfigureAwait(false); - await persister.Deduplicate("M10", 10, conn, null).ConfigureAwait(false); - - await persister.Advance(4, 12, 15, conn); - - var result = await slowPersister.Deduplicate("M6", 6, conn, null); - - Assert.AreEqual(DeduplicationResult.Duplicate, result); - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.Router.Tests/LinkStateTests.cs b/src/NServiceBus.Router.Tests/LinkStateTests.cs deleted file mode 100644 index ecddf20..0000000 --- a/src/NServiceBus.Router.Tests/LinkStateTests.cs +++ /dev/null @@ -1,63 +0,0 @@ -using NServiceBus.Router.Deduplication.Outbox; -using NUnit.Framework; - -[TestFixture] -class LinkStateTests -{ - [Test] - public void Uninitialized_state_contains_no_head_nor_tails() - { - var state = LinkState.Uninitialized(); - - Assert.IsNull(state.HeadSession); - Assert.IsNull(state.TailSession); - } - - [Test] - public void Epoch_number_is_1_for_freshly_initialized_link_state() - { - var state = LinkState.Uninitialized(); - state = state.Initialize("Head", "Tail", 10); - - Assert.AreEqual(1, state.Epoch); - } - - [Test] - public void Head_table_range_is_initialized() - { - var state = LinkState.Uninitialized(); - state = state.Initialize("Head", "Tail", 10); - - Assert.AreEqual(10, state.HeadSession.Lo); - Assert.AreEqual(20, state.HeadSession.Hi); - Assert.AreEqual("Head", state.HeadSession.Table); - } - - [Test] - public void Tail_table_range_is_initialized() - { - var state = LinkState.Uninitialized(); - state = state.Initialize("Head", "Tail", 10); - - Assert.AreEqual(0, state.TailSession.Lo); - Assert.AreEqual(10, state.TailSession.Hi); - Assert.AreEqual("Tail", state.TailSession.Table); - } - - [Test] - public void Advancing_epoch_switches_head_and_tail_tables() - { - var state = LinkState.Uninitialized(); - state = state.Initialize("Head", "Tail", 10); - - state = state.Advance(15); - - Assert.AreEqual(20, state.HeadSession.Lo); - Assert.AreEqual(35, state.HeadSession.Hi); - Assert.AreEqual("Tail", state.HeadSession.Table); - - Assert.AreEqual(10, state.TailSession.Lo); - Assert.AreEqual(20, state.TailSession.Hi); - Assert.AreEqual("Head", state.TailSession.Table); - } -} diff --git a/src/NServiceBus.Router.Tests/NServiceBus.Router.Tests.csproj b/src/NServiceBus.Router.Tests/NServiceBus.Router.Tests.csproj index 4ec886c..ddc0936 100644 --- a/src/NServiceBus.Router.Tests/NServiceBus.Router.Tests.csproj +++ b/src/NServiceBus.Router.Tests/NServiceBus.Router.Tests.csproj @@ -1,13 +1,12 @@  - net461 + net48 latest - + - \ No newline at end of file diff --git a/src/NServiceBus.Router.Tests/OutboxPersisterTests.cs b/src/NServiceBus.Router.Tests/OutboxPersisterTests.cs deleted file mode 100644 index b57e622..0000000 --- a/src/NServiceBus.Router.Tests/OutboxPersisterTests.cs +++ /dev/null @@ -1,479 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Threading.Tasks; -using NServiceBus.Logging; -using NServiceBus.Router; -using NServiceBus.Router.Deduplication.Outbox; -using NServiceBus.Transport; -using NUnit.Framework; - -[TestFixture] -public class OutboxPersisterTests -{ - OutboxPersister persister; - OutboxInstaller installer; - - [SetUp] - public async Task PrepareTables() - { - LogManager.Use().Level(LogLevel.Debug); - - installer = new OutboxInstaller("S"); - persister = new OutboxPersister(3, "S", "D"); - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - using (var trans = conn.BeginTransaction()) - { - await installer.Uninstall("D", conn, trans).ConfigureAwait(false); - await installer.Install("D", conn, trans).ConfigureAwait(false); - trans.Commit(); - } - } - } - - static SqlConnection CreateConnection() - { - return new SqlConnection("data source = (local); initial catalog=test1; integrated security=true"); - } - - [Test] - public async Task It_stores_messages_in_tables_based_on_sequence_number() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - using (var trans = conn.BeginTransaction()) - { - for (var i = 1; i <= 6; i++) - { - var operation = CreateMessages(Guid.NewGuid().ToString()); - await persister.Store(operation, () => {}, conn, trans).ConfigureAwait(false); - } - - trans.Commit(); - } - } - } - - static CapturedTransportOperation CreateMessages(string messageId) - { - var outgoingMessage = new OutgoingMessage(messageId, new Dictionary(), new byte[3]); - return new CapturedTransportOperation(outgoingMessage, "D"); - } - - [Test] - public async Task Can_advance_without_sending() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - Task Dispatch(OutgoingMessage operation) - { - Console.WriteLine(operation.MessageId); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - await persister.TryAdvance(Dispatch, conn); - await persister.TryAdvance(Dispatch, conn); - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(4, linkState.Epoch); - } - } - - [Test] - public async Task Can_close_non_empty_table() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - Task Dispatch(OutgoingMessage operation) - { - Console.WriteLine(operation.MessageId); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - await persister.Store(CreateMessages("M1"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M2"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M3"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M4"), () => { }, conn, null).ConfigureAwait(false); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - await persister.Store(CreateMessages("M5"), () => { }, conn, null).ConfigureAwait(false); - - Assert.AreEqual(6, linkState.HeadSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - } - } - - [Test] - public async Task It_triggers_advance_when_stale_or_full() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - Task Dispatch(OutgoingMessage operation) - { - Console.WriteLine(operation.MessageId); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - await persister.Store(CreateMessages("M1"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M2"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M3"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M4"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M5"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M6"), () => { }, conn, null).ConfigureAwait(false); - - var advanceTriggered = false; - try - { - await persister.Store(CreateMessages("M7"), () => { advanceTriggered = true; }, conn, null).ConfigureAwait(false); - } - catch (ProcessCurrentMessageLaterException) - { - //Swallow - } - - Assert.IsTrue(advanceTriggered); - } - } - - [Test] - public async Task It_triggers_advance_when_head_table_is_half_full() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - Task Dispatch(OutgoingMessage operation) - { - Console.WriteLine(operation.MessageId); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - var advanceTriggered = false; - void TriggerAdvance() - { - advanceTriggered = true; - } - - await persister.Store(CreateMessages("M1"), TriggerAdvance, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M2"), TriggerAdvance, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M3"), TriggerAdvance, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M4"), TriggerAdvance, conn, null).ConfigureAwait(false); - - //Not yet - Assert.IsFalse(advanceTriggered); - - await persister.Store(CreateMessages("M5"), TriggerAdvance, conn, null).ConfigureAwait(false); - - //Now - Assert.IsTrue(advanceTriggered); - } - } - - [Test] - public async Task It_detects_a_gap_when_it_is_in_the_middle_of_the_epoch() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - void TriggerAdvance() - { - //NOOP - } - - await persister.Store(CreateMessages("M1"), TriggerAdvance, conn, null).ConfigureAwait(false); - await GetNextSequenceValue("S_D", conn, null); - await persister.Store(CreateMessages("M3"), TriggerAdvance, conn, null).ConfigureAwait(false); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(3, linkState.TailSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var plug = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Plug)); - Assert.AreEqual("1", plug.Headers[RouterDeduplicationHeaders.SequenceNumber]); - } - } - - [Test] - public async Task It_detects_a_gap_when_it_is_bigger_than_one_row() - { - - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - await persister.Store(CreateMessages("M1"), () => { }, conn, null); - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(3, linkState.TailSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var plugsSequenceNumbers = dispatchedMessages - .Where(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Plug)) - .Select(m => m.Headers[RouterDeduplicationHeaders.SequenceNumber]) - .ToArray(); - - CollectionAssert.AreEqual(new[] { "1", "2" }, plugsSequenceNumbers); - } - } - - [Test] - public async Task It_detects_a_gap_when_it_is_at_the_beginning_of_the_epoch() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - await GetNextSequenceValue("S_D", conn, null); - - await persister.Store(CreateMessages("M2"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M3"), () => { }, conn, null).ConfigureAwait(false); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(3, linkState.TailSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var plug = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Plug)); - Assert.AreEqual("0", plug.Headers[RouterDeduplicationHeaders.SequenceNumber]); - } - } - - [Test] - public async Task It_detects_a_gap_when_it_is_at_the_end_of_the_epoch() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - await persister.Store(CreateMessages("M1"), () => { }, conn, null).ConfigureAwait(false); - await persister.Store(CreateMessages("M2"), () => { }, conn, null).ConfigureAwait(false); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(3, linkState.TailSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var plug = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Plug)); - Assert.AreEqual("2", plug.Headers[RouterDeduplicationHeaders.SequenceNumber]); - } - } - - [Test] - public async Task It_detects_a_gap_when_the_epoch_is_empty() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(3, linkState.TailSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var plugsSequenceNumbers = dispatchedMessages - .Where(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Plug)) - .Select(m => m.Headers[RouterDeduplicationHeaders.SequenceNumber]) - .ToArray(); - - CollectionAssert.AreEqual(new[] { "0", "1", "2" }, plugsSequenceNumbers); - } - } - - [Test] - public async Task It_sends_announce_message_when_advancing() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(6, linkState.HeadSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var advanceMessage = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Advance)); - - Assert.AreEqual("2", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceEpoch]); - Assert.AreEqual("6", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadLo]); - Assert.AreEqual("9", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadHi]); - } - } - - [Test] - public async Task It_retries_announcing_advance() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - var announceFailed = false; - try - { - await persister.TryAdvance(op => - { - if (op.Headers.ContainsKey(RouterDeduplicationHeaders.Advance)) - { - throw new Exception("Simulated"); - } - return Dispatch(op); - }, conn); - } - catch (Exception) - { - announceFailed = true; - } - - Assert.IsTrue(announceFailed); - - var linkState = await persister.TryAdvance(Dispatch, conn); - - Assert.AreEqual(6, linkState.HeadSession.Lo); - Assert.AreEqual(9, linkState.HeadSession.Hi); - - var advanceMessage = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Advance)); - - Assert.AreEqual("2", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceEpoch]); - Assert.AreEqual("6", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadLo]); - Assert.AreEqual("9", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadHi]); - } - } - - [Test] - public async Task It_retries_announcing_advance_when_initializing() - { - using (var conn = CreateConnection()) - { - await conn.OpenAsync().ConfigureAwait(false); - - var dispatchedMessages = new List(); - Task Dispatch(OutgoingMessage operation) - { - dispatchedMessages.Add(operation); - return Task.CompletedTask; - } - - await persister.Initialize(Dispatch, conn); - - var announceFailed = false; - try - { - await persister.TryAdvance(op => - { - if (op.Headers.ContainsKey(RouterDeduplicationHeaders.Advance)) - { - throw new Exception("Simulated"); - } - return Dispatch(op); - }, conn); - } - catch (Exception) - { - announceFailed = true; - } - - Assert.IsTrue(announceFailed); - - var newPersister = new OutboxPersister(3, "S", "D"); - await newPersister.Initialize(Dispatch, conn); - - var advanceMessage = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Advance)); - - Assert.AreEqual("2", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceEpoch]); - Assert.AreEqual("6", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadLo]); - Assert.AreEqual("9", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadHi]); - } - } - - async Task GetNextSequenceValue(string sequenceKey, SqlConnection conn, SqlTransaction trans) - { - using (var command = new SqlCommand($"select next value for [Sequence_{sequenceKey}]", conn, trans)) - { - var value = (long)await command.ExecuteScalarAsync().ConfigureAwait(false); - return value; - } - } -} diff --git a/src/NServiceBus.Router.sln b/src/NServiceBus.Router.sln index 92b30cf..20653f1 100644 --- a/src/NServiceBus.Router.sln +++ b/src/NServiceBus.Router.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29215.179 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33122.133 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBus.Router", "NServiceBus.Router\NServiceBus.Router.csproj", "{6307EF93-26B0-4E6C-BA94-85B1DCDCFA07}" EndProject @@ -32,26 +32,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoadTests.Receiver.Router", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoadTests.Shared", "LoadTests.Shared\LoadTests.Shared.csproj", "{33DE78E8-D222-4F04-885A-47A5BDD23A4A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBus.Router.SqlServer", "NServiceBus.Router.SqlServer\NServiceBus.Router.SqlServer.csproj", "{EB3B589F-FEC4-452D-A95B-EA513983ABD1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBus.Router.Migrator", "NServiceBus.Router.Migrator\NServiceBus.Router.Migrator.csproj", "{4317A94C-E36C-48AC-A927-6E36BCA68C27}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MigratorSample", "MigratorSample", "{463FEF84-A047-45F2-AB9D-6E3AA36518B5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{83AAE3E1-FE94-4E01-A649-99A2B5938D29}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{58F8E14B-E6F5-4FCD-8BD8-41651F885518}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Billing", "Billing\Billing.csproj", "{093B790B-D506-4F10-9FD7-9084D9F1200A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shipping", "Shipping\Shipping.csproj", "{529D9655-181F-4EF6-897E-4449D08ACCC7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales", "Sales\Sales.csproj", "{2E28DA2A-56E3-414D-B41F-22ADCCB516A0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaymentGateway", "PaymentGateway\PaymentGateway.csproj", "{0187BA47-FE5B-4951-8F22-A65C9A031112}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShippingGateway", "ShippingGateway\ShippingGateway.csproj", "{1E39608E-3A4D-4AE7-A980-B46B5D168B1A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,42 +78,6 @@ Global {33DE78E8-D222-4F04-885A-47A5BDD23A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU {33DE78E8-D222-4F04-885A-47A5BDD23A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU {33DE78E8-D222-4F04-885A-47A5BDD23A4A}.Release|Any CPU.Build.0 = Release|Any CPU - {EB3B589F-FEC4-452D-A95B-EA513983ABD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EB3B589F-FEC4-452D-A95B-EA513983ABD1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EB3B589F-FEC4-452D-A95B-EA513983ABD1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EB3B589F-FEC4-452D-A95B-EA513983ABD1}.Release|Any CPU.Build.0 = Release|Any CPU - {4317A94C-E36C-48AC-A927-6E36BCA68C27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4317A94C-E36C-48AC-A927-6E36BCA68C27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4317A94C-E36C-48AC-A927-6E36BCA68C27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4317A94C-E36C-48AC-A927-6E36BCA68C27}.Release|Any CPU.Build.0 = Release|Any CPU - {83AAE3E1-FE94-4E01-A649-99A2B5938D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83AAE3E1-FE94-4E01-A649-99A2B5938D29}.Debug|Any CPU.Build.0 = Debug|Any CPU - {83AAE3E1-FE94-4E01-A649-99A2B5938D29}.Release|Any CPU.ActiveCfg = Release|Any CPU - {83AAE3E1-FE94-4E01-A649-99A2B5938D29}.Release|Any CPU.Build.0 = Release|Any CPU - {58F8E14B-E6F5-4FCD-8BD8-41651F885518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {58F8E14B-E6F5-4FCD-8BD8-41651F885518}.Debug|Any CPU.Build.0 = Debug|Any CPU - {58F8E14B-E6F5-4FCD-8BD8-41651F885518}.Release|Any CPU.ActiveCfg = Release|Any CPU - {58F8E14B-E6F5-4FCD-8BD8-41651F885518}.Release|Any CPU.Build.0 = Release|Any CPU - {093B790B-D506-4F10-9FD7-9084D9F1200A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {093B790B-D506-4F10-9FD7-9084D9F1200A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {093B790B-D506-4F10-9FD7-9084D9F1200A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {093B790B-D506-4F10-9FD7-9084D9F1200A}.Release|Any CPU.Build.0 = Release|Any CPU - {529D9655-181F-4EF6-897E-4449D08ACCC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {529D9655-181F-4EF6-897E-4449D08ACCC7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {529D9655-181F-4EF6-897E-4449D08ACCC7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {529D9655-181F-4EF6-897E-4449D08ACCC7}.Release|Any CPU.Build.0 = Release|Any CPU - {2E28DA2A-56E3-414D-B41F-22ADCCB516A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E28DA2A-56E3-414D-B41F-22ADCCB516A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E28DA2A-56E3-414D-B41F-22ADCCB516A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E28DA2A-56E3-414D-B41F-22ADCCB516A0}.Release|Any CPU.Build.0 = Release|Any CPU - {0187BA47-FE5B-4951-8F22-A65C9A031112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0187BA47-FE5B-4951-8F22-A65C9A031112}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0187BA47-FE5B-4951-8F22-A65C9A031112}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0187BA47-FE5B-4951-8F22-A65C9A031112}.Release|Any CPU.Build.0 = Release|Any CPU - {1E39608E-3A4D-4AE7-A980-B46B5D168B1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E39608E-3A4D-4AE7-A980-B46B5D168B1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E39608E-3A4D-4AE7-A980-B46B5D168B1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E39608E-3A4D-4AE7-A980-B46B5D168B1A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -147,13 +91,6 @@ Global {82432CCF-502A-423B-871B-B86ABFBAE47B} = {8FAB9D0C-AE8E-4183-A2C5-77464A300549} {6D01212B-3BBC-4C11-A5C7-C608ECE12186} = {8FAB9D0C-AE8E-4183-A2C5-77464A300549} {33DE78E8-D222-4F04-885A-47A5BDD23A4A} = {8FAB9D0C-AE8E-4183-A2C5-77464A300549} - {83AAE3E1-FE94-4E01-A649-99A2B5938D29} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {58F8E14B-E6F5-4FCD-8BD8-41651F885518} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {093B790B-D506-4F10-9FD7-9084D9F1200A} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {529D9655-181F-4EF6-897E-4449D08ACCC7} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {2E28DA2A-56E3-414D-B41F-22ADCCB516A0} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {0187BA47-FE5B-4951-8F22-A65C9A031112} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} - {1E39608E-3A4D-4AE7-A980-B46B5D168B1A} = {463FEF84-A047-45F2-AB9D-6E3AA36518B5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F146A5AC-8618-4967-A758-8FB3980BC90F} diff --git a/src/NServiceBus.Router/IRuleCreationContext.cs b/src/NServiceBus.Router/IRuleCreationContext.cs index eb42711..6262ffb 100644 --- a/src/NServiceBus.Router/IRuleCreationContext.cs +++ b/src/NServiceBus.Router/IRuleCreationContext.cs @@ -36,6 +36,6 @@ public interface IRuleCreationContext /// /// Settings for the interface merged with router-wide settings. /// - ReadOnlySettings Settings { get; } + IReadOnlySettings Settings { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Interface.cs b/src/NServiceBus.Router/Interface.cs index 74c6327..b0f29dc 100644 --- a/src/NServiceBus.Router/Interface.cs +++ b/src/NServiceBus.Router/Interface.cs @@ -1,39 +1,26 @@ using System; using System.Threading.Tasks; -using NServiceBus; using NServiceBus.Router; using NServiceBus.Logging; using NServiceBus.Raw; using NServiceBus.Transport; -interface Interface -{ - string Name { get; } - Task Initialize(InterfaceChains interfaces, RootContext rootContext); - Task StartReceiving(); - Task StopReceiving(); - Task Stop(); -} - -class Interface : Interface where T : TransportDefinition, new() +class Interface { public string Name { get; } - public Interface(string endpointName, string interfaceName, Action> transportCustomization, Func ruleCreationContextFactory, string poisonQueue, int? maximumConcurrency, bool autoCreateQueues, string autoCreateQueuesIdentity, int immediateRetries, int delayedRetries, int circuitBreakerThreshold) + public Interface(string endpointName, string interfaceName, TransportDefinition transport, Func ruleCreationContextFactory, string poisonQueue, int? maximumConcurrency, bool autoCreateQueues, int immediateRetries, int delayedRetries, int circuitBreakerThreshold) { this.ruleCreationContextFactory = ruleCreationContextFactory; Name = interfaceName; - rawConfig = new ThrottlingRawEndpointConfig(endpointName, poisonQueue, ext => - { - transportCustomization?.Invoke(ext); - }, - (context, _) => preroutingChain.Invoke(new RawContext(context, Name, rootContext)), + rawConfig = new ThrottlingRawEndpointConfig(endpointName, poisonQueue, transport, + (context, token, _) => preroutingChain.Invoke(new RawContext(context, Name, rootContext)), (context, dispatcher) => { log.Error("Moving poison message to the error queue", context.Error.Exception); return context.MoveToErrorQueue(poisonQueue); }, maximumConcurrency, - immediateRetries, delayedRetries, circuitBreakerThreshold, autoCreateQueues, autoCreateQueuesIdentity); + immediateRetries, delayedRetries, circuitBreakerThreshold, autoCreateQueues); } public async Task Initialize(InterfaceChains interfaces, RootContext rootContext) @@ -76,7 +63,7 @@ public async Task Stop() IStartableRawEndpoint sender; IStoppableRawEndpoint stoppable; - ThrottlingRawEndpointConfig rawConfig; + ThrottlingRawEndpointConfig rawConfig; IChain preroutingChain; Func ruleCreationContextFactory; RootContext rootContext; diff --git a/src/NServiceBus.Router/InterfaceConfiguration.cs b/src/NServiceBus.Router/InterfaceConfiguration.cs index 665430a..2181e0a 100644 --- a/src/NServiceBus.Router/InterfaceConfiguration.cs +++ b/src/NServiceBus.Router/InterfaceConfiguration.cs @@ -4,18 +4,13 @@ using Raw; using Routing; using Transport; - using Unicast.Subscriptions.MessageDrivenSubscriptions; /// /// Configures the switch port. /// - /// Type of transport. - public class InterfaceConfiguration - where T : TransportDefinition, new() + public class InterfaceConfiguration { - Action> customization; bool? autoCreateQueues; - string autoCreateQueuesIdentity; int? maximumConcurrency; string overriddenEndpointName; @@ -34,10 +29,16 @@ public class InterfaceConfiguration /// public RouterConfiguration RouterConfiguration { get; } - internal InterfaceConfiguration(string name, Action> customization, RouterConfiguration routerConfiguration) + /// + /// Transport used by this interface. + /// + public TransportDefinition Transport { get; } + + + internal InterfaceConfiguration(string name, TransportDefinition transport, RouterConfiguration routerConfiguration) { + this.Transport = transport; Name = name; - this.customization = customization; RouterConfiguration = routerConfiguration; } @@ -60,23 +61,12 @@ public void AddRule(Func constructor, Func - /// Configures the port to use specified subscription persistence. - /// - [Obsolete("Use EnableMessageDrivenPublishSubscribe instead.")] - public void UseSubscriptionPersistence(ISubscriptionStorage subscriptionStorage) - { - this.EnableMessageDrivenPublishSubscribe(subscriptionStorage); - } - /// /// Configures the port to automatically create a queue when starting up. Overrides switch-level setting. /// - /// Identity to use when creating the queue. - public void AutoCreateQueues(string identity = null) + public void AutoCreateQueues() { autoCreateQueues = true; - autoCreateQueuesIdentity = identity; } /// @@ -107,7 +97,7 @@ public void LimitMessageProcessingConcurrencyTo(int maximumConcurrency) /// public EndpointInstances EndpointInstances { get; } = new EndpointInstances(); - internal Interface Create(string endpointName, string poisonQueue, bool? routerAutoCreateQueues, string routerAutoCreateQueuesIdentity, int immediateRetries, int delayedRetries, int circuitBreakerThreshold, RuntimeTypeGenerator typeGenerator, SettingsHolder routerSettings) + internal Interface Create(string endpointName, string poisonQueue, bool? routerAutoCreateQueues, int immediateRetries, int delayedRetries, int circuitBreakerThreshold, RuntimeTypeGenerator typeGenerator, SettingsHolder routerSettings) { IRuleCreationContext ContextFactory(IRawEndpoint e) { @@ -115,7 +105,7 @@ IRuleCreationContext ContextFactory(IRawEndpoint e) return new RuleCreationContext(Name, EndpointInstances, DistributionPolicy, e, typeGenerator, Settings); } - return new Interface(overriddenEndpointName ?? endpointName, Name, customization, ContextFactory, poisonQueue, maximumConcurrency, autoCreateQueues ?? routerAutoCreateQueues ?? false, autoCreateQueuesIdentity ?? routerAutoCreateQueuesIdentity, immediateRetries, delayedRetries, circuitBreakerThreshold); + return new Interface(overriddenEndpointName ?? endpointName, Name, Transport, ContextFactory, poisonQueue, maximumConcurrency, autoCreateQueues ?? routerAutoCreateQueues ?? false, immediateRetries, delayedRetries, circuitBreakerThreshold); } } } diff --git a/src/NServiceBus.Router/MessageDrivenPubSub.cs b/src/NServiceBus.Router/MessageDrivenPubSub.cs index 5d5a121..ec07aab 100644 --- a/src/NServiceBus.Router/MessageDrivenPubSub.cs +++ b/src/NServiceBus.Router/MessageDrivenPubSub.cs @@ -5,7 +5,7 @@ static class MessageDrivenPubSub { - public static OutgoingMessage CreateMessage(string ultimateDestination, string messageType, string localAddress, string localEndpoint, MessageIntentEnum intent) + public static OutgoingMessage CreateMessage(string ultimateDestination, string messageType, string localAddress, string localEndpoint, MessageIntent intent) { var subscriptionMessage = ControlMessageFactory.Create(intent); @@ -16,7 +16,7 @@ public static OutgoingMessage CreateMessage(string ultimateDestination, string m subscriptionMessage.Headers[Headers.SubscriberTransportAddress] = localAddress; } subscriptionMessage.Headers[Headers.SubscriberEndpoint] = localEndpoint; - subscriptionMessage.Headers[Headers.TimeSent] = DateTimeExtensions.ToWireFormattedString(DateTime.UtcNow); + subscriptionMessage.Headers[Headers.TimeSent] = DateTimeOffsetHelper.ToWireFormattedString(DateTimeOffset.UtcNow); subscriptionMessage.Headers[Headers.NServiceBusVersion] = "6.3.1"; //The code has been copied from 6.3.1 if (ultimateDestination != null) diff --git a/src/NServiceBus.Router/MessageDrivenPubSubFeature.cs b/src/NServiceBus.Router/MessageDrivenPubSubFeature.cs index 8d05957..7727cdc 100644 --- a/src/NServiceBus.Router/MessageDrivenPubSubFeature.cs +++ b/src/NServiceBus.Router/MessageDrivenPubSubFeature.cs @@ -35,8 +35,7 @@ static bool IsEnabled(IRuleCreationContext context) { return context.Settings.Get(SettingsKey); } - var transport = context.Endpoint.Settings.Get(); - return transport.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Unicast; + return context.Endpoint.SubscriptionManager == null; } static bool IsExplicitlyDisabled(IRuleCreationContext context) @@ -47,7 +46,7 @@ static bool IsExplicitlyDisabled(IRuleCreationContext context) static bool SendOnly(IRuleCreationContext context) { - return context.Endpoint.Settings.GetOrDefault("Endpoint.SendOnly"); + return context.Endpoint.TransportAddress == null; } class ForwardPublishNullRule : ChainTerminator diff --git a/src/NServiceBus.Router/MessageDrivenSubscriptionExtensions.cs b/src/NServiceBus.Router/MessageDrivenSubscriptionExtensions.cs index ff25f15..18fe839 100644 --- a/src/NServiceBus.Router/MessageDrivenSubscriptionExtensions.cs +++ b/src/NServiceBus.Router/MessageDrivenSubscriptionExtensions.cs @@ -1,6 +1,5 @@ namespace NServiceBus.Router { - using Transport; using Unicast.Subscriptions.MessageDrivenSubscriptions; /// @@ -13,8 +12,7 @@ public static class MessageDrivenSubscriptionExtensions /// /// Interface configuration. /// Subscription storage. - public static void EnableMessageDrivenPublishSubscribe(this InterfaceConfiguration interfaceConfig, ISubscriptionStorage subscriptionStorage) - where T : TransportDefinition, new() + public static void EnableMessageDrivenPublishSubscribe(this InterfaceConfiguration interfaceConfig, ISubscriptionStorage subscriptionStorage) { interfaceConfig.Settings.Set("EnableMessageDrivenPubSub", true); interfaceConfig.Settings.Set(subscriptionStorage); @@ -23,10 +21,8 @@ public static void EnableMessageDrivenPublishSubscribe(this InterfaceConfigur /// /// Disables message-driven storage-based publish/subscribe for a given interface. /// - /// /// - public static void DisableMessageDrivenPublishSubscribe(this InterfaceConfiguration interfaceConfig) - where T : TransportDefinition, new() + public static void DisableMessageDrivenPublishSubscribe(this InterfaceConfiguration interfaceConfig) { interfaceConfig.Settings.Set("EnableMessageDrivenPubSub", false); } @@ -36,8 +32,7 @@ public static void DisableMessageDrivenPublishSubscribe(this InterfaceConfigu /// /// Send-only interface configuration. /// Subscription storage. - public static void EnableMessageDrivenPublishSubscribe(this SendOnlyInterfaceConfiguration interfaceConfig, ISubscriptionStorage subscriptionStorage) - where T : TransportDefinition, new() + public static void EnableMessageDrivenPublishSubscribe(this SendOnlyInterfaceConfiguration interfaceConfig, ISubscriptionStorage subscriptionStorage) { interfaceConfig.Settings.Set("EnableMessageDrivenPubSub", true); interfaceConfig.Settings.Set(subscriptionStorage); @@ -47,8 +42,7 @@ public static void EnableMessageDrivenPublishSubscribe(this SendOnlyInterface /// Disables message-driven storage-based publish/subscribe for a given send-only interface. /// /// Send-only interface configuration. - public static void DisableMessageDrivenPublishSubscribe(this SendOnlyInterfaceConfiguration interfaceConfig) - where T : TransportDefinition, new() + public static void DisableMessageDrivenPublishSubscribe(this SendOnlyInterfaceConfiguration interfaceConfig) { interfaceConfig.Settings.Set("EnableMessageDrivenPubSub", false); } diff --git a/src/NServiceBus.Router/NServiceBus.Router.csproj b/src/NServiceBus.Router/NServiceBus.Router.csproj index 2303fd9..90e65c4 100644 --- a/src/NServiceBus.Router/NServiceBus.Router.csproj +++ b/src/NServiceBus.Router/NServiceBus.Router.csproj @@ -1,6 +1,6 @@  - netstandard2.0 + net48;net6.0 ..\..\binaries false true @@ -29,10 +29,10 @@ - - - + + + diff --git a/src/NServiceBus.Router/NativePubSubFeature.cs b/src/NServiceBus.Router/NativePubSubFeature.cs index 8a26792..bcfaa0e 100644 --- a/src/NServiceBus.Router/NativePubSubFeature.cs +++ b/src/NServiceBus.Router/NativePubSubFeature.cs @@ -18,13 +18,12 @@ static bool EnableNativePubSub(IRuleCreationContext context) { return false; } - var transport = context.Endpoint.Settings.Get(); - return transport.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Multicast; + return context.Endpoint.SubscriptionManager != null; } static bool SendOnly(IRuleCreationContext context) { - return context.Endpoint.Settings.GetOrDefault("Endpoint.SendOnly"); + return context.Endpoint.TransportAddress == null; } class ForwardPublishNullRule : ChainTerminator diff --git a/src/NServiceBus.Router/NativeSubscriptionExtensions.cs b/src/NServiceBus.Router/NativeSubscriptionExtensions.cs index 294df01..af3e323 100644 --- a/src/NServiceBus.Router/NativeSubscriptionExtensions.cs +++ b/src/NServiceBus.Router/NativeSubscriptionExtensions.cs @@ -10,7 +10,7 @@ public static class NativeSubscriptionExtensions /// /// Disables native publish/subscribe handling for a given interface. /// - public static void DisableNativePubSub(this InterfaceConfiguration interfaceConfig) + public static void DisableNativePubSub(this InterfaceConfiguration interfaceConfig) where T : TransportDefinition, new() { interfaceConfig.Settings.Set("NativePubSubDisabled", true); @@ -19,7 +19,7 @@ public static void DisableNativePubSub(this InterfaceConfiguration interfa /// /// Disables native publish/subscribe handling for a given send-only interface. /// - public static void DisableNativePubSub(this SendOnlyInterfaceConfiguration interfaceConfig) + public static void DisableNativePubSub(this SendOnlyInterfaceConfiguration interfaceConfig) where T : TransportDefinition, new() { interfaceConfig.Settings.Set("NativePubSubDisabled", true); diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardPublishContext.cs b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardPublishContext.cs index ce049a0..eaff5a7 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardPublishContext.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardPublishContext.cs @@ -40,7 +40,7 @@ public ForwardPublishContext(string outgoingInterface, Type rootType, PublishPre /// /// The headers associated with the received message. /// - public byte[] ReceivedBody { get; } + public ReadOnlyMemory ReceivedBody { get; } /// /// Mark this message as forwarded. diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardReplyContext.cs b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardReplyContext.cs index 337376f..e313936 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardReplyContext.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardReplyContext.cs @@ -1,5 +1,7 @@ namespace NServiceBus.Router { + using System; + /// /// Defines the context for the forward reply chain. /// @@ -23,6 +25,6 @@ public ForwardReplyContext(string outgoingInterface, ReplyPreroutingContext pare /// /// The headers associated with the received message. /// - public byte[] ReceivedBody { get; } + public ReadOnlyMemory ReceivedBody { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardSendContext.cs b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardSendContext.cs index ae21d3e..7286e2b 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardSendContext.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/1_ForwardSendContext.cs @@ -1,5 +1,6 @@ namespace NServiceBus.Router { + using System; using System.Collections.Generic; /// @@ -31,6 +32,6 @@ public ForwardSendContext(string outgoingInterface, Route[] routes, SendPrerouti /// /// The headers associated with the received message. /// - public byte[] ReceivedBody { get; } + public ReadOnlyMemory ReceivedBody { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeGatewayRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeGatewayRule.cs index 6d51450..de878e6 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeGatewayRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeGatewayRule.cs @@ -19,7 +19,7 @@ protected override async Task Terminate(ForwardSubscribeContext context) var forwardedSubscribes = context.Routes.Where(r => r.Gateway != null); var forkContexts = forwardedSubscribes.Select(r => new AnycastContext(r.Gateway, - MessageDrivenPubSub.CreateMessage(r.Destination, context.MessageType, localAddress, localEndpoint, MessageIntentEnum.Subscribe), + MessageDrivenPubSub.CreateMessage(r.Destination, context.MessageType, localAddress, localEndpoint, MessageIntent.Subscribe), DistributionStrategyScope.Send, context)).ToArray(); diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeMessageDrivenRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeMessageDrivenRule.cs index a29fcc9..59022cd 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeMessageDrivenRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeMessageDrivenRule.cs @@ -19,7 +19,7 @@ protected override async Task Terminate(ForwardSubscribeContext context) var immediateSubscribes = context.Routes.Where(r => r.Gateway == null); var forkContexts = immediateSubscribes.Select(r => new MulticastContext(r.Destination, - MessageDrivenPubSub.CreateMessage(null, context.MessageType, localAddress, localEndpoint, MessageIntentEnum.Subscribe), context)) + MessageDrivenPubSub.CreateMessage(null, context.MessageType, localAddress, localEndpoint, MessageIntent.Subscribe), context)) .ToArray(); if (!forkContexts.Any()) diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeNativeRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeNativeRule.cs index fbf1cc0..95f6a1e 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeNativeRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardSubscribeNativeRule.cs @@ -1,19 +1,20 @@ using System.Threading.Tasks; using NServiceBus.Router; using NServiceBus.Transport; +using NServiceBus.Unicast.Messages; class ForwardSubscribeNativeRule : ChainTerminator { - IManageSubscriptions subscriptionManager; + ISubscriptionManager subscriptionManager; - public ForwardSubscribeNativeRule(IManageSubscriptions subscriptionManager) + public ForwardSubscribeNativeRule(ISubscriptionManager subscriptionManager) { this.subscriptionManager = subscriptionManager; } protected override async Task Terminate(ForwardSubscribeContext context) { - await subscriptionManager.Subscribe(context.MessageRuntimeType, context).ConfigureAwait(false); + await subscriptionManager.SubscribeAll(new[]{new MessageMetadata(context.MessageRuntimeType) }, context).ConfigureAwait(false); return true; } diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeGatewayRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeGatewayRule.cs index 31b89de..3da22dd 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeGatewayRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeGatewayRule.cs @@ -19,7 +19,7 @@ protected override async Task Terminate(ForwardUnsubscribeContext context) var forwardedSubscribes = context.Routes.Where(r => r.Gateway != null); var forkContexts = forwardedSubscribes.Select(r => new AnycastContext(r.Gateway, - MessageDrivenPubSub.CreateMessage(r.Destination, context.MessageType, localAddress, localEndpoint, MessageIntentEnum.Unsubscribe), + MessageDrivenPubSub.CreateMessage(r.Destination, context.MessageType, localAddress, localEndpoint, MessageIntent.Unsubscribe), DistributionStrategyScope.Send, context)).ToArray(); diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeMessageDrivenRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeMessageDrivenRule.cs index 40daad2..44b0049 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeMessageDrivenRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeMessageDrivenRule.cs @@ -19,7 +19,7 @@ protected override async Task Terminate(ForwardUnsubscribeContext context) var immediateSubscribes = context.Routes.Where(r => r.Gateway == null); var forkContexts = immediateSubscribes.Select(r => new MulticastContext(r.Destination, - MessageDrivenPubSub.CreateMessage(null, context.MessageType, localAddress, localEndpoint, MessageIntentEnum.Unsubscribe), context)) + MessageDrivenPubSub.CreateMessage(null, context.MessageType, localAddress, localEndpoint, MessageIntent.Unsubscribe), context)) .ToArray(); if (forkContexts.Any()) diff --git a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeNativeRule.cs b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeNativeRule.cs index 0f8184c..570a008 100644 --- a/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeNativeRule.cs +++ b/src/NServiceBus.Router/Pipeline/Forwarding/ForwardUnsubscribeNativeRule.cs @@ -1,19 +1,20 @@ using System.Threading.Tasks; using NServiceBus.Router; using NServiceBus.Transport; +using NServiceBus.Unicast.Messages; class ForwardUnsubscribeNativeRule : ChainTerminator { - IManageSubscriptions subscriptionManager; + ISubscriptionManager subscriptionManager; - public ForwardUnsubscribeNativeRule(IManageSubscriptions subscriptionManager) + public ForwardUnsubscribeNativeRule(ISubscriptionManager subscriptionManager) { this.subscriptionManager = subscriptionManager; } protected override async Task Terminate(ForwardUnsubscribeContext context) { - await subscriptionManager.Unsubscribe(context.MessageRuntimeType, context).ConfigureAwait(false); + await subscriptionManager.Unsubscribe(new MessageMetadata(context.MessageRuntimeType), context).ConfigureAwait(false); return true; } diff --git a/src/NServiceBus.Router/Pipeline/IRuleContext.cs b/src/NServiceBus.Router/Pipeline/IRuleContext.cs index 92ad255..cb30bf7 100644 --- a/src/NServiceBus.Router/Pipeline/IRuleContext.cs +++ b/src/NServiceBus.Router/Pipeline/IRuleContext.cs @@ -1,5 +1,6 @@ namespace NServiceBus.Router { + using System.Threading; using Extensibility; /// @@ -11,5 +12,10 @@ public interface IRuleContext /// Allows extending the rule context by adding arbitrary values. /// ContextBag Extensions { get; } + + /// + /// Context passed during message processing + /// + CancellationToken CancellationToken { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Postrouting/PostroutingTerminator.cs b/src/NServiceBus.Router/Pipeline/Postrouting/PostroutingTerminator.cs index 35852f4..b01e375 100644 --- a/src/NServiceBus.Router/Pipeline/Postrouting/PostroutingTerminator.cs +++ b/src/NServiceBus.Router/Pipeline/Postrouting/PostroutingTerminator.cs @@ -20,7 +20,7 @@ protected override async Task Terminate(PostroutingContext context) { AddTrace(operation); } - await dispatcher.Dispatch(new TransportOperations(context.Messages), context.Get(), context) + await dispatcher.Dispatch(new TransportOperations(context.Messages), context.Get(), context.CancellationToken) .ConfigureAwait(false); return true; } diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/1_RawContext.cs b/src/NServiceBus.Router/Pipeline/Prerouting/1_RawContext.cs index 7646374..96ddf07 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/1_RawContext.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/1_RawContext.cs @@ -1,5 +1,6 @@ namespace NServiceBus.Router { + using System; using Transport; /// @@ -8,7 +9,7 @@ public class RawContext : BasePreroutingContext { internal RawContext(MessageContext messageContext, string incomingInterface, RootContext root) - : base(root, incomingInterface, new ReceivedMessageHeaders(messageContext.Headers), messageContext.MessageId) + : base(root, incomingInterface, new ReceivedMessageHeaders(messageContext.Headers), messageContext.NativeMessageId) { Set(messageContext.TransportTransaction); @@ -18,6 +19,6 @@ internal RawContext(MessageContext messageContext, string incomingInterface, Roo /// /// The body of the received message. /// - public byte[] Body { get; } + public ReadOnlyMemory Body { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/2_PreroutingContext.cs b/src/NServiceBus.Router/Pipeline/Prerouting/2_PreroutingContext.cs index 2184e88..9cbcd43 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/2_PreroutingContext.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/2_PreroutingContext.cs @@ -18,11 +18,11 @@ internal PreroutingContext(RawContext parent) : base(parent) Body = parent.Body; Intent = GetMessageIntent(parent.Headers); } - static MessageIntentEnum? GetMessageIntent(IReadOnlyDictionary headers) + static MessageIntent? GetMessageIntent(IReadOnlyDictionary headers) { if (headers.TryGetValue(NServiceBus.Headers.MessageIntent, out var messageIntentString)) { - Enum.TryParse(messageIntentString, true, out var messageIntent); + Enum.TryParse(messageIntentString, true, out var messageIntent); return messageIntent; } return null; @@ -31,12 +31,12 @@ internal PreroutingContext(RawContext parent) : base(parent) /// /// Received message intent or null if message intent header was missing. /// - public MessageIntentEnum? Intent { get; } + public MessageIntent? Intent { get; } /// /// The body of the received message. /// - public byte[] Body { get; set; } + public ReadOnlyMemory Body { get; set; } /// /// Mark this message as forwarded. diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/3_PublishPreroutingContext.cs b/src/NServiceBus.Router/Pipeline/Prerouting/3_PublishPreroutingContext.cs index ed8f060..f6d6422 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/3_PublishPreroutingContext.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/3_PublishPreroutingContext.cs @@ -1,5 +1,7 @@ namespace NServiceBus.Router { + using System; + /// /// Defines the context for the third part of the prerouting chain group -- the prerouting chain for publish messages. /// @@ -22,6 +24,6 @@ public PublishPreroutingContext(string[] types, PreroutingContext parent) : base /// /// The body of the received message. /// - public byte[] Body { get; } + public ReadOnlyMemory Body { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/3_ReplyPreroutingContext.cs b/src/NServiceBus.Router/Pipeline/Prerouting/3_ReplyPreroutingContext.cs index 06f0f5b..c428e3c 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/3_ReplyPreroutingContext.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/3_ReplyPreroutingContext.cs @@ -1,5 +1,7 @@ namespace NServiceBus.Router { + using System; + /// /// Defines the context for the third part of the prerouting chain group -- the prerouting chain for reply messages. /// @@ -16,6 +18,6 @@ public ReplyPreroutingContext(PreroutingContext parent) : base(parent) /// /// The body of the received message. /// - public byte[] Body { get; } + public ReadOnlyMemory Body { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/3_SendPreroutingContext.cs b/src/NServiceBus.Router/Pipeline/Prerouting/3_SendPreroutingContext.cs index eda147d..cdff743 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/3_SendPreroutingContext.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/3_SendPreroutingContext.cs @@ -1,5 +1,6 @@ namespace NServiceBus.Router { + using System; using System.Collections.Generic; /// @@ -26,6 +27,6 @@ public SendPreroutingContext(PreroutingContext parent) : base(parent) /// /// The body of the received message. /// - public byte[] Body { get; } + public ReadOnlyMemory Body { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToPublishPreroutingFork.cs b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToPublishPreroutingFork.cs index 8e5ce9a..bbf6274 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToPublishPreroutingFork.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToPublishPreroutingFork.cs @@ -7,7 +7,7 @@ class PreroutingToPublishPreroutingFork : IRule next) { - if (context.Intent == MessageIntentEnum.Publish) + if (context.Intent == MessageIntent.Publish) { if (!context.Headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes)) { diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToReplyPreroutingFork.cs b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToReplyPreroutingFork.cs index dd25ee4..08672ad 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToReplyPreroutingFork.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToReplyPreroutingFork.cs @@ -7,7 +7,7 @@ class PreroutingToReplyPreroutingFork : IRule next) { - if (context.Intent == MessageIntentEnum.Reply) + if (context.Intent == MessageIntent.Reply) { await context.Chains.Get() .Invoke(new ReplyPreroutingContext(context)) diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSendPreroutingFork.cs b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSendPreroutingFork.cs index 5c8656e..d3d0818 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSendPreroutingFork.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSendPreroutingFork.cs @@ -7,7 +7,7 @@ class PreroutingToSendPreroutingFork : IRule next) { - if (context.Intent == MessageIntentEnum.Send) + if (context.Intent == MessageIntent.Send) { await context.Chains.Get() .Invoke(new SendPreroutingContext(context)) diff --git a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSubscribePreroutingFork.cs b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSubscribePreroutingFork.cs index 48af62d..6fb354d 100644 --- a/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSubscribePreroutingFork.cs +++ b/src/NServiceBus.Router/Pipeline/Prerouting/PreroutingToSubscribePreroutingFork.cs @@ -7,8 +7,8 @@ class PreroutingToSubscribePreroutingFork : IRule next) { - if (context.Intent == MessageIntentEnum.Subscribe - || context.Intent == MessageIntentEnum.Unsubscribe) + if (context.Intent == MessageIntent.Subscribe + || context.Intent == MessageIntent.Unsubscribe) { var messageTypeString = GetSubscriptionMessageTypeFrom(context); @@ -29,7 +29,7 @@ public async Task Invoke(PreroutingContext context, Func() .Invoke(new SubscribePreroutingContext(context, messageTypeString, subscriberEndpoint, subscriberAddress)) diff --git a/src/NServiceBus.Router/Pipeline/RootContext.cs b/src/NServiceBus.Router/Pipeline/RootContext.cs index 05c18da..84c2479 100644 --- a/src/NServiceBus.Router/Pipeline/RootContext.cs +++ b/src/NServiceBus.Router/Pipeline/RootContext.cs @@ -2,14 +2,17 @@ namespace NServiceBus.Router { + using System.Threading; + /// /// Root context for the router. /// public class RootContext : ContextBag, IRuleContext { - internal RootContext(IInterfaceChains interfaces, string routerName) + internal RootContext(IInterfaceChains interfaces, string routerName, CancellationToken cancellationToken) { RouterName = routerName; + CancellationToken = cancellationToken; Set(interfaces); } @@ -27,6 +30,11 @@ internal RootContext(IInterfaceChains interfaces, string routerName) /// Allows extending the rule context by adding arbitrary values. /// public ContextBag Extensions => this; + + /// + /// Cancellation token for graceful shutdown + /// + public CancellationToken CancellationToken { get; } } } diff --git a/src/NServiceBus.Router/Pipeline/RuleContext.cs b/src/NServiceBus.Router/Pipeline/RuleContext.cs index 5a936ec..f09267d 100644 --- a/src/NServiceBus.Router/Pipeline/RuleContext.cs +++ b/src/NServiceBus.Router/Pipeline/RuleContext.cs @@ -1,6 +1,7 @@ namespace NServiceBus.Router { using System; + using System.Threading; using Extensibility; /// @@ -15,6 +16,7 @@ protected RuleContext(RuleContext parentContext, string @interface = null) : base(parentContext.Extensions) { Interface = @interface ?? parentContext.Interface ?? throw new Exception("Interface is required."); + CancellationToken = parentContext.CancellationToken; } /// @@ -24,6 +26,7 @@ protected internal RuleContext(RootContext parentContext, string @interface) : base(parentContext?.Extensions) { Interface = @interface; + CancellationToken = parentContext.CancellationToken; } /// @@ -40,5 +43,10 @@ protected internal RuleContext(RootContext parentContext, string @interface) /// Allows extending the rule context by adding arbitrary values. /// public ContextBag Extensions => this; + + /// + /// Cancellation token for the message processing. + /// + public CancellationToken CancellationToken { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.Router/Router.cs b/src/NServiceBus.Router/Router.cs index 67681f7..ec76955 100644 --- a/src/NServiceBus.Router/Router.cs +++ b/src/NServiceBus.Router/Router.cs @@ -2,6 +2,7 @@ namespace NServiceBus.Router { using System; using System.Linq; + using Transport; /// /// Allows creating routers. @@ -76,9 +77,9 @@ public static IRouter Create(RouterConfiguration config) chains.AddRule(c => new ReplyReplyTraceRule(c.Endpoint.TransportAddress, c.Endpoint.EndpointName)); chains.AddChain(cb => cb.Begin().AddSection().Terminate()); - chains.AddRule(c => new AnycastToPostroutingConnector(c.EndpointInstances, c.DistributionPolicy, instance => c.Endpoint.ToTransportAddress(LogicalAddress.CreateRemoteAddress(instance)))); + chains.AddRule(c => new AnycastToPostroutingConnector(c.EndpointInstances, c.DistributionPolicy, instance => c.Endpoint.ToTransportAddress(new QueueAddress(instance.Endpoint, instance.Discriminator, instance.Properties)))); chains.AddChain(cb => cb.Begin().AddSection().Terminate()); - chains.AddRule(c => new MulticastToPostroutingConnector(c.EndpointInstances, instance => c.Endpoint.ToTransportAddress(LogicalAddress.CreateRemoteAddress(instance)))); + chains.AddRule(c => new MulticastToPostroutingConnector(c.EndpointInstances, instance => c.Endpoint.ToTransportAddress(new QueueAddress(instance.Endpoint, instance.Discriminator, instance.Properties)))); chains.AddChain(cb => cb.Begin().Terminate()); chains.AddRule(c => new PostroutingTerminator(c.Endpoint)); diff --git a/src/NServiceBus.Router/RouterConfiguration.cs b/src/NServiceBus.Router/RouterConfiguration.cs index 083e59b..b28304f 100644 --- a/src/NServiceBus.Router/RouterConfiguration.cs +++ b/src/NServiceBus.Router/RouterConfiguration.cs @@ -32,13 +32,11 @@ public RouterConfiguration(string name) /// /// Adds a new interface to the router. /// - /// Transport to use for this interface. /// Name of the interface. - /// A callback for customizing the transport settings. - public InterfaceConfiguration AddInterface(string name, Action> customization) - where T : TransportDefinition, new() + /// Transport to use for this interface. + public InterfaceConfiguration AddInterface(string name, TransportDefinition transport) { - var ifaceConfig = new InterfaceConfiguration(name, customization, this); + var ifaceConfig = new InterfaceConfiguration(name, transport, this); InterfaceFactories.Add(() => CreateInterface(ifaceConfig)); return ifaceConfig; } @@ -46,36 +44,31 @@ public InterfaceConfiguration AddInterface(string name, Action /// Adds a new send-only interface to the router. /// - /// Transport to use for this interface. /// Name of the interface. - /// A callback for customizing the transport settings. - public SendOnlyInterfaceConfiguration AddSendOnlyInterface(string name, Action> customization) - where T : TransportDefinition, new() + /// Transport to use for this interface. + public SendOnlyInterfaceConfiguration AddSendOnlyInterface(string name, TransportDefinition transport) { - var ifaceConfig = new SendOnlyInterfaceConfiguration(name, customization, this); + var ifaceConfig = new SendOnlyInterfaceConfiguration(name, transport, this); SendOnlyInterfaceFactories.Add(() => CreateSendOnlyInterface(ifaceConfig)); return ifaceConfig; } - SendOnlyInterface CreateSendOnlyInterface(SendOnlyInterfaceConfiguration ifaceConfig) - where T : TransportDefinition, new() + SendOnlyInterface CreateSendOnlyInterface(SendOnlyInterfaceConfiguration ifaceConfig) { return ifaceConfig.Create(Name, typeGenerator, Settings); } - Interface CreateInterface(InterfaceConfiguration ifaceConfig) where T : TransportDefinition, new() + Interface CreateInterface(InterfaceConfiguration ifaceConfig) { - return ifaceConfig.Create(Name, PoisonQueueName, autoCreateQueues, autoCreateQueuesIdentity, ImmediateRetries, DelayedRetries, CircuitBreakerThreshold, typeGenerator, Settings); + return ifaceConfig.Create(Name, PoisonQueueName, autoCreateQueues, ImmediateRetries, DelayedRetries, CircuitBreakerThreshold, typeGenerator, Settings); } /// /// Configures the router to automatically create a queue when starting up. /// - /// Identity to use when creating the queue. - public void AutoCreateQueues(string identity = null) + public void AutoCreateQueues() { autoCreateQueues = true; - autoCreateQueuesIdentity = identity; } /// @@ -146,7 +139,6 @@ public void DefineChain(Func> chainDefiniti } bool? autoCreateQueues; - string autoCreateQueuesIdentity; internal List> InterfaceFactories = new List>(); internal List> SendOnlyInterfaceFactories = new List>(); internal List Modules = new List(); diff --git a/src/NServiceBus.Router/RouterImpl.cs b/src/NServiceBus.Router/RouterImpl.cs index 2207128..234154a 100644 --- a/src/NServiceBus.Router/RouterImpl.cs +++ b/src/NServiceBus.Router/RouterImpl.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using NServiceBus.Logging; using NServiceBus.Router; @@ -15,6 +16,7 @@ public RouterImpl(string name, Interface[] interfaces, SendOnlyInterface[] sendO this.interfaceChains = interfaceChains; this.extensibilitySettings = extensibilitySettings; this.interfaces = interfaces; + stopTokenSource = new CancellationTokenSource(); } public async Task Initialize() @@ -24,7 +26,7 @@ public async Task Initialize() throw new Exception("The router has already been initialized."); } - rootContext = new RootContext(interfaceChains, name); + rootContext = new RootContext(interfaceChains, name, stopTokenSource.Token); await routingProtocol.Start(new RouterMetadata(name, interfaces.Select(i => i.Name).ToList())).ConfigureAwait(false); foreach (var iface in sendOnlyInterfaces) @@ -60,6 +62,7 @@ public async Task Start() public async Task Stop() { + stopTokenSource.Cancel(); await Task.WhenAll(interfaces.Select(s => s.StopReceiving())).ConfigureAwait(false); //Stop modules in reverse order @@ -85,4 +88,5 @@ public async Task Stop() SettingsHolder extensibilitySettings; static ILog log = LogManager.GetLogger(); RootContext rootContext; + readonly CancellationTokenSource stopTokenSource; } \ No newline at end of file diff --git a/src/NServiceBus.Router/RuleCreationContext.cs b/src/NServiceBus.Router/RuleCreationContext.cs index 26e5124..afa058f 100644 --- a/src/NServiceBus.Router/RuleCreationContext.cs +++ b/src/NServiceBus.Router/RuleCreationContext.cs @@ -10,9 +10,9 @@ class RuleCreationContext : IRuleCreationContext public RawDistributionPolicy DistributionPolicy { get; } public IRawEndpoint Endpoint { get; } public RuntimeTypeGenerator TypeGenerator { get; } - public ReadOnlySettings Settings { get; } + public IReadOnlySettings Settings { get; } - public RuleCreationContext(string interfaceName, EndpointInstances endpointInstances, RawDistributionPolicy distributionPolicy, IRawEndpoint endpoint, RuntimeTypeGenerator typeGenerator, ReadOnlySettings settings) + public RuleCreationContext(string interfaceName, EndpointInstances endpointInstances, RawDistributionPolicy distributionPolicy, IRawEndpoint endpoint, RuntimeTypeGenerator typeGenerator, IReadOnlySettings settings) { InterfaceName = interfaceName; EndpointInstances = endpointInstances; diff --git a/src/NServiceBus.Router/SendOnlyInterface.cs b/src/NServiceBus.Router/SendOnlyInterface.cs index df1f762..b951026 100644 --- a/src/NServiceBus.Router/SendOnlyInterface.cs +++ b/src/NServiceBus.Router/SendOnlyInterface.cs @@ -1,38 +1,22 @@ using System; using System.Threading.Tasks; -using NServiceBus; using NServiceBus.Router; -using NServiceBus.Configuration.AdvancedExtensibility; using NServiceBus.Raw; using NServiceBus.Transport; -interface SendOnlyInterface -{ - string Name { get; } - Task Initialize(InterfaceChains interfaces); - Task Stop(); -} -class SendOnlyInterface : SendOnlyInterface where T : TransportDefinition, new() +class SendOnlyInterface { - public SendOnlyInterface(string endpointName, string interfaceName, Action> transportCustomization, Func ruleCreationContextFactory) + public SendOnlyInterface(string endpointName, string interfaceName, TransportDefinition transport, Func ruleCreationContextFactory) { this.ruleCreationContextFactory = ruleCreationContextFactory; Name = interfaceName; - config = RawEndpointConfiguration.CreateSendOnly(endpointName); - var transport = config.UseTransport(); - SetTransportSpecificFlags(transport.GetSettings()); - transportCustomization?.Invoke(transport); + config = RawEndpointConfiguration.CreateSendOnly(endpointName, transport); } public string Name { get; } - static void SetTransportSpecificFlags(NServiceBus.Settings.SettingsHolder settings) - { - settings.Set("RabbitMQ.RoutingTopologySupportsDelayedDelivery", true); - } - public async Task Initialize(InterfaceChains interfaces) { var startable = await RawEndpoint.Create(config).ConfigureAwait(false); diff --git a/src/NServiceBus.Router/SendOnlyInterfaceConfiguration.cs b/src/NServiceBus.Router/SendOnlyInterfaceConfiguration.cs index 8dc0634..a81777c 100644 --- a/src/NServiceBus.Router/SendOnlyInterfaceConfiguration.cs +++ b/src/NServiceBus.Router/SendOnlyInterfaceConfiguration.cs @@ -4,16 +4,13 @@ using Raw; using Routing; using Transport; - using Unicast.Subscriptions.MessageDrivenSubscriptions; /// /// Configures the switch port. /// - /// Type of transport. - public class SendOnlyInterfaceConfiguration - where T : TransportDefinition, new() + public class SendOnlyInterfaceConfiguration { - Action> customization; + TransportDefinition transport; string overriddenEndpointName; /// @@ -31,10 +28,10 @@ public class SendOnlyInterfaceConfiguration /// public RouterConfiguration RouterConfiguration { get; } - internal SendOnlyInterfaceConfiguration(string name, Action> customization, RouterConfiguration routerConfiguration) + internal SendOnlyInterfaceConfiguration(string name, TransportDefinition transport, RouterConfiguration routerConfiguration) { + this.transport = transport; Name = name; - this.customization = customization; RouterConfiguration = routerConfiguration; } @@ -57,15 +54,6 @@ public void AddRule(Func constructor, Func - /// Configures the port to use specified subscription persistence. - /// - [Obsolete("Use EnableMessageDrivenPublishSubscribe instead.")] - public void UseSubscriptionPersistence(ISubscriptionStorage subscriptionStorage) - { - this.EnableMessageDrivenPublishSubscribe(subscriptionStorage); - } - /// /// Overrides the interface endpoint name. /// @@ -93,7 +81,7 @@ IRuleCreationContext ContextFactory(IRawEndpoint e) return new RuleCreationContext(Name, EndpointInstances, DistributionPolicy, e, typeGenerator, Settings); } - return new SendOnlyInterface(overriddenEndpointName ?? endpointName, Name, customization, ContextFactory); + return new SendOnlyInterface(overriddenEndpointName ?? endpointName, Name, transport, ContextFactory); } } } diff --git a/src/NServiceBus.Router/SettingsHolder.cs b/src/NServiceBus.Router/SettingsHolder.cs index bb7bbd6..02a9409 100644 --- a/src/NServiceBus.Router/SettingsHolder.cs +++ b/src/NServiceBus.Router/SettingsHolder.cs @@ -8,7 +8,7 @@ /// /// Setting container. /// - public class SettingsHolder : ReadOnlySettings + public class SettingsHolder : IReadOnlySettings { /// /// Gets the given setting by key. diff --git a/src/NServiceBus.Router/SubscriptionStorage/SqlDialect_MsSqlServer.cs b/src/NServiceBus.Router/SubscriptionStorage/SqlDialect_MsSqlServer.cs index 12d3720..d887b33 100644 --- a/src/NServiceBus.Router/SubscriptionStorage/SqlDialect_MsSqlServer.cs +++ b/src/NServiceBus.Router/SubscriptionStorage/SqlDialect_MsSqlServer.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Data.Common; - using System.Data.SqlClient; using System.Text; + using Microsoft.Data.SqlClient; using Unicast.Subscriptions; public partial class SqlDialect diff --git a/src/NServiceBus.Router/SubscriptionStorage/SqlSubscriptionStorage.cs b/src/NServiceBus.Router/SubscriptionStorage/SqlSubscriptionStorage.cs index 8775fb9..265bfee 100644 --- a/src/NServiceBus.Router/SubscriptionStorage/SqlSubscriptionStorage.cs +++ b/src/NServiceBus.Router/SubscriptionStorage/SqlSubscriptionStorage.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; + using System.Threading; using System.Threading.Tasks; using Extensibility; using Logging; @@ -87,7 +88,7 @@ public async Task Uninstall() /// /// Subscribes the given client to messages of a given type. /// - public async Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context) + public async Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context, CancellationToken cancellationToken = default) { await Retry(async () => { @@ -108,7 +109,7 @@ await Retry(async () => /// /// Unsubscribes the given client from messages of given type. /// - public async Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context) + public async Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context, CancellationToken cancellationToken = default) { await Retry(async () => { @@ -127,7 +128,7 @@ await Retry(async () => /// /// Returns a list of addresses for subscribers currently subscribed to the given message type. /// - public Task> GetSubscriberAddressesForMessage(IEnumerable messageHierarchy, ContextBag context) + public Task> GetSubscriberAddressesForMessage(IEnumerable messageHierarchy, ContextBag context, CancellationToken cancellationToken = default) { var types = messageHierarchy.ToList(); diff --git a/src/NServiceBus.Router/ThrottlingRawEndpointConfig.cs b/src/NServiceBus.Router/ThrottlingRawEndpointConfig.cs index ae2c65f..cb91349 100644 --- a/src/NServiceBus.Router/ThrottlingRawEndpointConfig.cs +++ b/src/NServiceBus.Router/ThrottlingRawEndpointConfig.cs @@ -2,22 +2,19 @@ using System.Threading; using System.Threading.Tasks; using NServiceBus; -using NServiceBus.Extensibility; using NServiceBus.Logging; using NServiceBus.Raw; using NServiceBus.Router; using NServiceBus.Routing; -using NServiceBus.Settings; using NServiceBus.Transport; -delegate Task PoisonMessageHandling(IErrorHandlingPolicyContext handlingContext, IDispatchMessages dispatcher); +delegate Task PoisonMessageHandling(IErrorHandlingPolicyContext handlingContext, IMessageDispatcher dispatcher); -class ThrottlingRawEndpointConfig : IStartableRawEndpoint, IReceivingRawEndpoint - where T : TransportDefinition, new() +class ThrottlingRawEndpointConfig : IStartableRawEndpoint, IReceivingRawEndpoint { - public ThrottlingRawEndpointConfig(string queue, string poisonMessageQueueName, Action> transportCustomization, - Func onMessage, PoisonMessageHandling poisonMessageHandling, - int? maximumConcurrency, int immediateRetries, int delayedRetries, int circuitBreakerThreshold, bool autoCreateQueue, string autoCreateQueueIdentity = null) + public ThrottlingRawEndpointConfig(string queue, string poisonMessageQueueName, TransportDefinition transport, + Func onMessage, PoisonMessageHandling poisonMessageHandling, + int? maximumConcurrency, int immediateRetries, int delayedRetries, int circuitBreakerThreshold, bool autoCreateQueue) { if (immediateRetries < 0) { @@ -31,12 +28,17 @@ public ThrottlingRawEndpointConfig(string queue, string poisonMessageQueueName, { throw new ArgumentException("Circuit breaker threshold must not be less than zero.", nameof(circuitBreakerThreshold)); } - config = PrepareConfig(queue, poisonMessageQueueName, transportCustomization, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, delayedRetries, circuitBreakerThreshold, autoCreateQueue, autoCreateQueueIdentity); + + if (transport.TransportTransactionMode == TransportTransactionMode.SendsAtomicWithReceive) + { + throw new Exception("Router cannot operate in SendsAtomicWithReceive transaction mode. Please select other transaction mode."); + } + config = PrepareConfig(queue, poisonMessageQueueName, transport, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, delayedRetries, circuitBreakerThreshold, autoCreateQueue); } - RawEndpointConfiguration PrepareConfig(string inputQueue, string poisonMessageQueueName, Action> transportCustomization, - Func onMessage, PoisonMessageHandling poisonMessageHandling, int? maximumConcurrency, - int immediateRetries, int delayedRetries, int circuitBreakerThreshold, bool autoCreateQueue, string autoCreateQueueIdentity) + RawEndpointConfiguration PrepareConfig(string inputQueue, string poisonMessageQueueName, TransportDefinition transport, + Func onMessage, PoisonMessageHandling poisonMessageHandling, int? maximumConcurrency, + int immediateRetries, int delayedRetries, int circuitBreakerThreshold, bool autoCreateQueue) { var circuitBreaker = new RepeatedFailuresCircuitBreaker(inputQueue, circuitBreakerThreshold, e => { @@ -47,7 +49,7 @@ RawEndpointConfiguration PrepareConfig(string inputQueue, string poisonMessageQu try { var oldEndpoint = endpoint; - var throttledConfig = PrepareThrottledConfig(inputQueue, poisonMessageQueueName, transportCustomization, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, circuitBreakerThreshold, delayedRetries); + var throttledConfig = PrepareThrottledConfig(inputQueue, poisonMessageQueueName, transport, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, circuitBreakerThreshold, delayedRetries); var newEndpoint = await RawEndpoint.Start(throttledConfig).ConfigureAwait(false); endpoint = newEndpoint; await oldEndpoint.Stop().ConfigureAwait(false); @@ -62,26 +64,24 @@ RawEndpointConfiguration PrepareConfig(string inputQueue, string poisonMessageQu } }); }); - var regularConfig = RawEndpointConfiguration.Create(inputQueue, async (context, dispatcher) => + var regularConfig = RawEndpointConfiguration.Create(inputQueue, transport, async (context, dispatcher, token) => { - await onMessage(context, dispatcher).ConfigureAwait(false); + await onMessage(context, dispatcher, token).ConfigureAwait(false); circuitBreaker.Success(); }, poisonMessageQueueName); regularConfig.CustomErrorHandlingPolicy(new RegularModePolicy(inputQueue, circuitBreaker, poisonMessageHandling, immediateRetries, delayedRetries)); - Task onCriticalError(ICriticalErrorContext context) + Task onCriticalError(ICriticalErrorContext context, CancellationToken token) { logger.Fatal($"The receiver for queue {inputQueue} has encountered a severe error that is likely related to the connectivity with the broker or the broker itself."); return Task.CompletedTask; } - regularConfig.Settings.Set("onCriticalErrorAction", (Func)onCriticalError); + regularConfig.CriticalErrorAction(onCriticalError); - var transport = regularConfig.UseTransport(); - transportCustomization(transport); if (autoCreateQueue) { - regularConfig.AutoCreateQueue(autoCreateQueueIdentity); + regularConfig.AutoCreateQueues(); } if (maximumConcurrency.HasValue) { @@ -90,14 +90,14 @@ Task onCriticalError(ICriticalErrorContext context) return regularConfig; } - RawEndpointConfiguration PrepareThrottledConfig(string inputQueue, string poisonMessageQueueName, Action> transportCustomization, - Func onMessage, PoisonMessageHandling poisonMessageHandling, int? maximumConcurrency, + RawEndpointConfiguration PrepareThrottledConfig(string inputQueue, string poisonMessageQueueName, TransportDefinition transport, + Func onMessage, PoisonMessageHandling poisonMessageHandling, int? maximumConcurrency, int immediateRetries, int delayedRetries, int circuitBreakerThreshold) { var switchedBack = false; - var throttledConfig = RawEndpointConfiguration.Create(inputQueue, async (context, dispatcher) => + var throttledConfig = RawEndpointConfiguration.Create(inputQueue, transport, async (context, dispatcher, token) => { - await onMessage(context, dispatcher); + await onMessage(context, dispatcher, token); if (switchedBack) { return; @@ -109,7 +109,7 @@ RawEndpointConfiguration PrepareThrottledConfig(string inputQueue, string poison try { var oldEndpoint = endpoint; - var regularConfig = PrepareConfig(inputQueue, poisonMessageQueueName, transportCustomization, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, delayedRetries, circuitBreakerThreshold, false, null); + var regularConfig = PrepareConfig(inputQueue, poisonMessageQueueName, transport, onMessage, poisonMessageHandling, maximumConcurrency, immediateRetries, delayedRetries, circuitBreakerThreshold, false); var newEndpoint = await RawEndpoint.Start(regularConfig).ConfigureAwait(false); endpoint = newEndpoint; await oldEndpoint.Stop().ConfigureAwait(false); @@ -128,16 +128,14 @@ RawEndpointConfiguration PrepareThrottledConfig(string inputQueue, string poison throttledConfig.CustomErrorHandlingPolicy(new ThrottledModePolicy(inputQueue, immediateRetries)); - Task onCriticalError(ICriticalErrorContext context) + Task onCriticalError(ICriticalErrorContext context, CancellationToken token) { logger.Fatal($"The receiver for queue {inputQueue} has encountered a severe error that is likely related to the connectivity with the broker or the broker itself."); return Task.CompletedTask; } - throttledConfig.Settings.Set("onCriticalErrorAction", (Func)onCriticalError); + throttledConfig.CriticalErrorAction(onCriticalError); - var transport = throttledConfig.UseTransport(); - transportCustomization(transport); throttledConfig.LimitMessageProcessingConcurrencyTo(1); return throttledConfig; } @@ -145,75 +143,62 @@ Task onCriticalError(ICriticalErrorContext context) public async Task Create() { startable = await RawEndpoint.Create(config); - ValidateTransactionMode(startable); config = null; return this; } - static void ValidateTransactionMode(IStartableRawEndpoint startableRawEndpoint) + async Task IStartableRawEndpoint.Start(CancellationToken cancellationToken) { - var infra = startableRawEndpoint.Settings.Get(); - - if (startableRawEndpoint.Settings.TryGet(out var selectedMode)) - { - if (selectedMode == TransportTransactionMode.SendsAtomicWithReceive) - { - throw new Exception("Router cannot operate in SendsAtomicWithReceive transaction mode. Please select other transaction mode."); - } - } - else if (infra.TransactionMode == TransportTransactionMode.SendsAtomicWithReceive) - { - throw new Exception($"{infra.GetType()} defaults to SendsAtomicWithReceive transaction mode. Router cannot operate in that mode. Customize the transport configuration to use SendsAtomicWithReceive mode."); - } - } - - async Task IStartableRawEndpoint.Start() - { - endpoint = await startable.Start().ConfigureAwait(false); + endpoint = await startable.Start(cancellationToken).ConfigureAwait(false); startable = null; return this; } - async Task IReceivingRawEndpoint.StopReceiving() + async Task IReceivingRawEndpoint.StopReceiving(CancellationToken cancellationToken) { - await transitionSemaphore.WaitAsync().ConfigureAwait(false); + await transitionSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); if (endpoint != null) { - stoppable = await endpoint.StopReceiving().ConfigureAwait(false); + stoppable = await endpoint.StopReceiving(cancellationToken).ConfigureAwait(false); endpoint = null; } return this; } - async Task IStoppableRawEndpoint.Stop() + async Task IStoppableRawEndpoint.Stop(CancellationToken cancellationToken) { if (stoppable != null) { - await stoppable.Stop().ConfigureAwait(false); + await stoppable.Stop(cancellationToken).ConfigureAwait(false); stoppable = null; } } - string IRawEndpoint.ToTransportAddress(LogicalAddress logicalAddress) => startable?.ToTransportAddress(logicalAddress) ?? endpoint.ToTransportAddress(logicalAddress); + string IRawEndpoint.ToTransportAddress(QueueAddress queueAddress) => startable?.ToTransportAddress(queueAddress) ?? endpoint.ToTransportAddress(queueAddress); - Task IDispatchMessages.Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context) + Task IMessageDispatcher.Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, CancellationToken cancellationToken) { return endpoint != null - ? endpoint.Dispatch(outgoingMessages, transaction, context) - : startable.Dispatch(outgoingMessages, transaction, context); + ? endpoint.Dispatch(outgoingMessages, transaction, cancellationToken) + : startable.Dispatch(outgoingMessages, transaction, cancellationToken); } string IRawEndpoint.TransportAddress => startable?.TransportAddress ?? endpoint.TransportAddress; string IRawEndpoint.EndpointName => startable?.EndpointName ?? endpoint.EndpointName; - ReadOnlySettings IRawEndpoint.Settings => startable?.Settings ?? endpoint.Settings; - public IManageSubscriptions SubscriptionManager => startable?.SubscriptionManager ?? endpoint.SubscriptionManager; + public ISubscriptionManager SubscriptionManager + { + get + { + return endpoint?.SubscriptionManager ?? startable?.SubscriptionManager; + } + } RawEndpointConfiguration config; IReceivingRawEndpoint endpoint; IStartableRawEndpoint startable; SemaphoreSlim transitionSemaphore = new SemaphoreSlim(1); - static ILog logger = LogManager.GetLogger(typeof(ThrottlingRawEndpointConfig)); + static ILog logger = LogManager.GetLogger(typeof(ThrottlingRawEndpointConfig)); IStoppableRawEndpoint stoppable; class RegularModePolicy : IErrorHandlingPolicy @@ -233,7 +218,7 @@ public RegularModePolicy(string inputQueue, RepeatedFailuresCircuitBreaker circu this.delayedRetries = delayedRetries; } - public async Task OnError(IErrorHandlingPolicyContext handlingContext, IDispatchMessages dispatcher) + public async Task OnError(IErrorHandlingPolicyContext handlingContext, IMessageDispatcher dispatcher, CancellationToken cancellationToken = default) { if (handlingContext.Error.Exception is UnforwardableMessageException) { @@ -264,7 +249,7 @@ public async Task OnError(IErrorHandlingPolicyContext handlin var newDelayedRetriesHeaderValue = handlingContext.Error.DelayedDeliveriesPerformed + 1; incomingMessage.Headers[Headers.DelayedRetries] = newDelayedRetriesHeaderValue.ToString(); } - await dispatcher.Dispatch(new TransportOperations(operation), handlingContext.Error.TransportTransaction, new ContextBag()) + await dispatcher.Dispatch(new TransportOperations(operation), handlingContext.Error.TransportTransaction, cancellationToken) .ConfigureAwait(false); //Notify the circuit breaker @@ -285,7 +270,7 @@ public ThrottledModePolicy(string inputQueue, int immediateRetries) this.immediateRetries = immediateRetries; } - public async Task OnError(IErrorHandlingPolicyContext handlingContext, IDispatchMessages dispatcher) + public async Task OnError(IErrorHandlingPolicyContext handlingContext, IMessageDispatcher dispatcher, CancellationToken cancellationToken = default) { await Task.Delay(1000); if (handlingContext.Error.ImmediateProcessingFailures < immediateRetries) @@ -300,7 +285,7 @@ public async Task OnError(IErrorHandlingPolicyContext handlin var message = new OutgoingMessage(incomingMessage.MessageId, incomingMessage.Headers, incomingMessage.Body); var operation = new TransportOperation(message, new UnicastAddressTag(inputQueue)); - await dispatcher.Dispatch(new TransportOperations(operation), handlingContext.Error.TransportTransaction, new ContextBag()) + await dispatcher.Dispatch(new TransportOperations(operation), handlingContext.Error.TransportTransaction, cancellationToken) .ConfigureAwait(false); return ErrorHandleResult.Handled; diff --git a/src/PaymentGateway/PaymentGateway.csproj b/src/PaymentGateway/PaymentGateway.csproj index 8cb7db6..f30eaf8 100644 --- a/src/PaymentGateway/PaymentGateway.csproj +++ b/src/PaymentGateway/PaymentGateway.csproj @@ -5,8 +5,6 @@ 7.1 - - diff --git a/src/Sales/Sales.csproj b/src/Sales/Sales.csproj index 8cb7db6..f30eaf8 100644 --- a/src/Sales/Sales.csproj +++ b/src/Sales/Sales.csproj @@ -5,8 +5,6 @@ 7.1 - - diff --git a/src/Shipping/Shipping.csproj b/src/Shipping/Shipping.csproj index 8cb7db6..43ba54f 100644 --- a/src/Shipping/Shipping.csproj +++ b/src/Shipping/Shipping.csproj @@ -5,7 +5,6 @@ 7.1 - diff --git a/src/ShippingGateway/ShippingGateway.csproj b/src/ShippingGateway/ShippingGateway.csproj index 8cb7db6..f30eaf8 100644 --- a/src/ShippingGateway/ShippingGateway.csproj +++ b/src/ShippingGateway/ShippingGateway.csproj @@ -5,8 +5,6 @@ 7.1 - -