diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_with_custom_IDataBus.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_with_custom_IDataBus.cs deleted file mode 100644 index 4372d07c2..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_with_custom_IDataBus.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace NServiceBus.AcceptanceTests.DataBus -{ - using System; - using System.IO; - using EndpointTemplates; - using AcceptanceTesting; - using NServiceBus.DataBus; - using NUnit.Framework; - using ScenarioDescriptors; - - public class When_sending_with_custom_IDataBus : NServiceBusAcceptanceTest - { - static byte[] PayloadToSend = new byte[1024 * 10]; - - [Test] - public void Should_receive_the_message_the_correctly() - { - Scenario.Define() - .WithEndpoint(b => b.Given(bus=> bus.Send(new MyMessageWithLargePayload - { - Payload = new DataBusProperty(PayloadToSend) - }))) - .WithEndpoint() - .Done(context => context.ReceivedPayload != null) - .Repeat(r => r.For(Transports.Default)) - .Should(c => Assert.AreEqual(PayloadToSend, c.ReceivedPayload, "The large payload should be marshalled correctly using the databus")) - .Run(); - File.Delete(MyDataBus.GetTempPath()); - } - - public class Context : ScenarioContext - { - public byte[] ReceivedPayload { get; set; } - } - - - public class Sender : EndpointConfigurationBuilder - { - public Sender() - { - EndpointSetup(b => b.RegisterComponents(r => r.RegisterSingleton(new MyDataBus()))) - .AddMapping(typeof(Receiver)); - } - } - - public class Receiver : EndpointConfigurationBuilder - { - public Receiver() - { - EndpointSetup(b => b.RegisterComponents(r => r.RegisterSingleton(new MyDataBus()))); - } - - public class MyMessageHandler : IHandleMessages - { - public Context Context { get; set; } - - public void Handle(MyMessageWithLargePayload messageWithLargePayload) - { - Context.ReceivedPayload = messageWithLargePayload.Payload.Value; - } - } - } - - [Serializable] - public class MyMessageWithLargePayload : ICommand - { - public DataBusProperty Payload { get; set; } - } - } - - public class MyDataBus:IDataBus - { - string tempPath; - - public MyDataBus() - { - tempPath = GetTempPath(); - } - - public static string GetTempPath() - { - return Path.Combine(Path.GetTempPath(), "MyDataBus.txt"); - } - - public Stream Get(string key) - { - return File.OpenRead(tempPath); - } - - public string Put(Stream stream, TimeSpan timeToBeReceived) - { - using (var destination = File.OpenWrite(tempPath)) - { - stream.CopyTo(destination); - } - return "key"; - } - - public void Start() - { - } - } -} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/StackTraceAssert.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/StackTraceAssert.cs deleted file mode 100644 index a6293edae..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/StackTraceAssert.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace NServiceBus.AcceptanceTests.Exceptions -{ - static class StackTraceAssert - { -// ReSharper disable once UnusedParameter.Global - public static void StartsWith(string expected, string actual) - { - if (actual == null) - { - Assert.Fail(); - } - else - { - var cleanStackTrace = CleanStackTrace(actual); - try - { - Assert.IsTrue(cleanStackTrace.Replace("\r\n", "\n").StartsWith(expected.Replace("\r\n", "\n"))); - } - catch (Exception) - { - Trace.WriteLine(cleanStackTrace); - throw; - } - } - } - static string CleanStackTrace(string stackTrace) - { - if (stackTrace== null) - { - return string.Empty; - } - using (var stringReader = new StringReader(stackTrace)) - { - var stringBuilder = new StringBuilder(); - while (true) - { - var line = stringReader.ReadLine(); - if (line == null) - { - break; - } - - stringBuilder.AppendLine(line.Split(new[] - { - " in " - }, StringSplitOptions.RemoveEmptyEntries).First().Trim()); - } - return stringBuilder.ToString().Trim(); - } - } - } -} - diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_and_different_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_and_different_End_throws.cs deleted file mode 100644 index dd749160b..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_and_different_End_throws.cs +++ /dev/null @@ -1,196 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NServiceBus.UnitOfWork; - using NUnit.Framework; - - public class When_Uow_Begin_and_different_End_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_AggregateException_with_both_exceptions() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - - Assert.AreEqual(typeof(BeginException), context.InnerExceptionOneType); - Assert.AreEqual(typeof(EndException), context.InnerExceptionTwoType); - - -#if (!DEBUG) - - StackTraceAssert.StartsWith( -@"at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); - - StackTraceAssert.StartsWith( -string.Format(@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_Begin_and_different_End_throws.Endpoint.{0}.End(Exception ex) -at NServiceBus.UnitOfWorkBehavior.AppendEndExceptionsAndRethrow(Exception initialException)", context.TypeName), context.InnerExceptionTwoStackTrace); - -#endif - - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public Type ExceptionType { get; set; } - public string InnerExceptionOneStackTrace { get; set; } - public string InnerExceptionTwoStackTrace { get; set; } - public Type InnerExceptionOneType { get; set; } - public Type InnerExceptionTwoType { get; set; } - public bool FirstOneExecuted { get; set; } - public string TypeName { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - var aggregateException = (AggregateException)e; - Context.StackTrace = aggregateException.StackTrace; - var innerExceptions = aggregateException.InnerExceptions; - Context.InnerExceptionOneStackTrace = innerExceptions[0].StackTrace; - Context.InnerExceptionTwoStackTrace = innerExceptions[1].StackTrace; - Context.InnerExceptionOneType = innerExceptions[0].GetType(); - Context.InnerExceptionTwoType = innerExceptions[1].GetType(); - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - - } - } - - public class UnitOfWorkThatThrows1 : IManageUnitsOfWork - { - public Context Context { get; set; } - - bool throwAtEnd; - - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - if (Context.FirstOneExecuted) - { - throw new BeginException(); - } - - Context.FirstOneExecuted = throwAtEnd = true; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - if (throwAtEnd) - { - Context.TypeName = GetType().Name; - - throw new EndException(); - } - } - } - public class UnitOfWorkThatThrows2 : IManageUnitsOfWork - { - public Context Context { get; set; } - - bool throwAtEnd; - - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - if (Context.FirstOneExecuted) - { - throw new BeginException(); - } - - Context.FirstOneExecuted = throwAtEnd = true; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - if (throwAtEnd) - { - Context.TypeName = GetType().Name; - - throw new EndException(); - } - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - } - } - - } - - [Serializable] - public class Message : IMessage - { - } - public class BeginException : Exception - { - public BeginException() - : base("BeginException") - { - - } - } - public class EndException : Exception - { - public EndException() - : base("EndException") - { - - } - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_throws.cs deleted file mode 100644 index 9b6ca1fec..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_Begin_throws.cs +++ /dev/null @@ -1,123 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NServiceBus.UnitOfWork; - using NUnit.Framework; - - public class When_Uow_Begin_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_exception_thrown_from_begin() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - - Assert.AreEqual(typeof(BeginException), context.ExceptionType); -#if (!DEBUG) - StackTraceAssert.StartsWith( -@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_Begin_throws.Endpoint.UnitOfWorkThatThrowsInBegin.Begin() -at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); -#endif - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public Type ExceptionType { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - Context.ExceptionType = e.GetType(); - Context.StackTrace = e.StackTrace; - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - - } - } - - public class UnitOfWorkThatThrowsInBegin : IManageUnitsOfWork - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - throw new BeginException(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - } - } - } - - [Serializable] - public class Message : IMessage - { - } - public class BeginException : Exception - { - public BeginException() - : base("BeginException") - { - - } - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_End_throws.cs deleted file mode 100644 index 237f520a0..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_Uow_End_throws.cs +++ /dev/null @@ -1,122 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NServiceBus.UnitOfWork; - using NUnit.Framework; - - public class When_Uow_End_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_exception_thrown_from_end() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - - Assert.AreEqual(typeof(EndException), context.ExceptionType); -#if(!DEBUG) - StackTraceAssert.StartsWith( -@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_End_throws.Endpoint.UnitOfWorkThatThrowsInEnd.End(Exception ex) -at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); -#endif - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public Type ExceptionType { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - Context.ExceptionType = e.GetType(); - Context.StackTrace = e.StackTrace; - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - - } - } - - class UnitOfWorkThatThrowsInEnd : IManageUnitsOfWork - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - throw new EndException(); - } - } - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - } - } - } - - [Serializable] - public class Message : IMessage - { - } - public class EndException : Exception - { - public EndException() - : base("EndException") - { - - } - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_and_Uow_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_and_Uow_End_throws.cs deleted file mode 100644 index 582d9903d..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_and_Uow_End_throws.cs +++ /dev/null @@ -1,209 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NServiceBus.UnitOfWork; - using NUnit.Framework; - - public class When_handler_and_Uow_End_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_AggregateException_with_both_exceptions() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - - Assert.AreEqual(typeof(HandlerException), context.InnerExceptionOneType); - Assert.AreEqual(typeof(EndException), context.InnerExceptionTwoType); - -#if (!DEBUG) - StackTraceAssert.StartsWith( -@"at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); - - StackTraceAssert.StartsWith( -@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_and_Uow_End_throws.Endpoint.Handler.Handle(Message message) -at NServiceBus.Unicast.MessageHandlerRegistry.Invoke(Object handler, Object message, Dictionary`2 dictionary) -at NServiceBus.InvokeHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SetCurrentMessageBeingHandledBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.LoadHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Transports.SQLServer.ReadIncomingCallbackAddressBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ExecuteLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.DeserializeLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.CallbackInvocationBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SubscriptionReceiverBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next)", context.InnerExceptionOneStackTrace); - - StackTraceAssert.StartsWith( -string.Format(@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_and_Uow_End_throws.Endpoint.{0}.End(Exception ex) -at NServiceBus.UnitOfWorkBehavior.AppendEndExceptionsAndRethrow(Exception initialException)", context.TypeName), context.InnerExceptionTwoStackTrace); - -#endif - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public string InnerExceptionOneStackTrace { get; set; } - public string InnerExceptionTwoStackTrace { get; set; } - public Type InnerExceptionOneType { get; set; } - public Type InnerExceptionTwoType { get; set; } - public bool FirstOneExecuted { get; set; } - public string TypeName { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - c.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - var aggregateException = (AggregateException)e; - Context.StackTrace = aggregateException.StackTrace; - var exceptions = aggregateException.InnerExceptions; - Context.InnerExceptionOneStackTrace = exceptions[0].StackTrace; - Context.InnerExceptionTwoStackTrace = exceptions[1].StackTrace; - Context.InnerExceptionOneType = exceptions[0].GetType(); - Context.InnerExceptionTwoType = exceptions[1].GetType(); - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - - } - } - - public class UnitOfWorkThatThrows1 : IManageUnitsOfWork - { - public Context Context { get; set; } - - bool executedInSecondPlace; - - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - if (Context.FirstOneExecuted) - { - executedInSecondPlace = true; - } - - Context.FirstOneExecuted = true; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - if (executedInSecondPlace) - { - Context.TypeName = GetType().Name; - - throw new EndException(); - } - } - } - - public class UnitOfWorkThatThrows2 : IManageUnitsOfWork - { - public Context Context { get; set; } - - bool executedInSecondPlace; - - [MethodImpl(MethodImplOptions.NoInlining)] - public void Begin() - { - if (Context.FirstOneExecuted) - { - executedInSecondPlace = true; - } - - Context.FirstOneExecuted = true; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void End(Exception ex = null) - { - if (executedInSecondPlace) - { - Context.TypeName = GetType().Name; - - throw new EndException(); - } - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - throw new HandlerException(); - } - } - - } - - [Serializable] - public class Message : IMessage - { - } - public class HandlerException : Exception - { - public HandlerException() - : base("HandlerException") - { - - } - } - public class EndException : Exception - { - public EndException() - : base("EndException") - { - - } - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws.cs deleted file mode 100644 index 348de530a..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws.cs +++ /dev/null @@ -1,114 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NUnit.Framework; - - public class When_handler_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_exception_from_handler() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - Assert.AreEqual(typeof(HandlerException), context.ExceptionType); -#if (!DEBUG) - StackTraceAssert.StartsWith( -@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws.Endpoint.Handler.Handle(Message message) -at NServiceBus.Unicast.MessageHandlerRegistry.Invoke(Object handler, Object message, Dictionary`2 dictionary) -at NServiceBus.InvokeHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SetCurrentMessageBeingHandledBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.LoadHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Transports.SQLServer.ReadIncomingCallbackAddressBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ExecuteLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.DeserializeLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.CallbackInvocationBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SubscriptionReceiverBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); -#endif - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public Type ExceptionType { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => c.ConfigureComponent(DependencyLifecycle.SingleInstance)); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - Context.ExceptionType = e.GetType(); - Context.StackTrace = e.StackTrace; - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - throw new HandlerException(); - } - } - } - - [Serializable] - public class Message : IMessage - { - } - public class HandlerException : Exception - { - public HandlerException() - : base("HandlerException") - { - - } - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws_AggregateException.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws_AggregateException.cs deleted file mode 100644 index bc42755e0..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_handler_throws_AggregateException.cs +++ /dev/null @@ -1,140 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NUnit.Framework; - - public class When_handler_throws_AggregateException : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_exact_AggregateException_exception_from_handler() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - Assert.AreEqual(typeof(AggregateException), context.ExceptionType); - Assert.AreEqual(typeof(Exception), context.InnerExceptionType); - Assert.AreEqual("My Exception", context.ExceptionMessage); - Assert.AreEqual("My Inner Exception", context.InnerExceptionMessage); - -#if (!DEBUG) - StackTraceAssert.StartsWith( - @"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.Handle(Message message) -at NServiceBus.Unicast.MessageHandlerRegistry.Invoke(Object handler, Object message, Dictionary`2 dictionary) -at NServiceBus.InvokeHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SetCurrentMessageBeingHandledBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.LoadHandlersBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Transports.SQLServer.ReadIncomingCallbackAddressBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ExecuteLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.DeserializeLogicalMessagesBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.CallbackInvocationBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.SubscriptionReceiverBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.UnitOfWorkBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ChildContainerBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.ProcessingStatisticsBehavior.Invoke(IncomingContext context, Action next) -at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) -at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) -at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace); - - StackTraceAssert.StartsWith( - @"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.MethodThatThrows() -at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.Handle(Message message)", context.InnerStackTrace); -#endif - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public string InnerStackTrace { get; set; } - public Type InnerExceptionType { get; set; } - public string ExceptionMessage { get; set; } - public string InnerExceptionMessage { get; set; } - public Type ExceptionType { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - Context.ExceptionMessage = e.Message; - Context.StackTrace = e.StackTrace; - Context.ExceptionType = e.GetType(); - if (e.InnerException != null) - { - Context.InnerExceptionMessage = e.InnerException.Message; - Context.InnerExceptionType = e.InnerException.GetType(); - Context.InnerStackTrace = e.InnerException.StackTrace; - } - Context.ExceptionReceived = true; - } - - public void Init(Address address) - { - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - try - { - MethodThatThrows(); - } - catch (Exception exception) - { - throw new AggregateException("My Exception", exception); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - void MethodThatThrows() - { - throw new Exception("My Inner Exception"); - } - } - } - - [Serializable] - public class Message : IMessage - { - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_serialization_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_serialization_throws.cs deleted file mode 100644 index 92cb7f117..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Exceptions/When_serialization_throws.cs +++ /dev/null @@ -1,113 +0,0 @@ -namespace NServiceBus.AcceptanceTests.Exceptions -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.Serialization; - using NServiceBus.AcceptanceTesting; - using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.Config; - using NServiceBus.Faults; - using NServiceBus.Features; - using NServiceBus.MessageMutator; - using NServiceBus.Unicast.Messages; - using NUnit.Framework; - - public class When_serialization_throws : NServiceBusAcceptanceTest - { - [Test] - public void Should_receive_SerializationException() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message()))) - .AllowExceptions() - .Done(c => c.ExceptionReceived) - .Run(); - - Assert.AreEqual(typeof(SerializationException), context.ExceptionType); - } - - public class Context : ScenarioContext - { - public bool ExceptionReceived { get; set; } - public string StackTrace { get; set; } - public Type ExceptionType { get; set; } - public string InnerExceptionStackTrace { get; set; } - public Type InnerExceptionType { get; set; } - } - - public class Endpoint : EndpointConfigurationBuilder - { - public Endpoint() - { - EndpointSetup(b => - { - b.RegisterComponents(c => - { - c.ConfigureComponent(DependencyLifecycle.SingleInstance); - c.ConfigureComponent(DependencyLifecycle.InstancePerCall); - }); - b.DisableFeature(); - }) - .WithConfig(c => - { - c.MaxRetries = 0; - }); - } - - class CustomFaultManager : IManageMessageFailures - { - public Context Context { get; set; } - - public void SerializationFailedForMessage(TransportMessage message, Exception e) - { - Context.ExceptionType = e.GetType(); - Context.StackTrace = e.StackTrace; - if (e.InnerException != null) - { - Context.InnerExceptionType = e.InnerException.GetType(); - Context.InnerExceptionStackTrace = e.InnerException.StackTrace; - } - Context.ExceptionReceived = true; - } - - public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) - { - } - - public void Init(Address address) - { - } - } - - class CorruptionMutator : IMutateTransportMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void MutateIncoming(TransportMessage transportMessage) - { - transportMessage.Body[1]++; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void MutateOutgoing(LogicalMessage logicalMessage, TransportMessage transportMessage) - { - } - } - - class Handler : IHandleMessages - { - [MethodImpl(MethodImplOptions.NoInlining)] - public void Handle(Message message) - { - } - } - } - - [Serializable] - public class Message : IMessage - { - } - } - -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NServiceBusAcceptanceTest.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NServiceBusAcceptanceTest.cs deleted file mode 100644 index 60fbe360e..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NServiceBusAcceptanceTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace NServiceBus.AcceptanceTests -{ - using AcceptanceTesting.Customization; - using NUnit.Framework; - - /// - /// Base class for all the NSB test that sets up our conventions - /// - [TestFixture] -// ReSharper disable once PartialTypeWithSinglePart - public abstract partial class NServiceBusAcceptanceTest - { - [SetUp] - public void SetUp() - { - Conventions.EndpointNamingConvention= t => - { - var baseNs = typeof (NServiceBusAcceptanceTest).Namespace; - var testName = GetType().Name; - return t.FullName.Replace(baseNs + ".", "").Replace(testName + "+", "") - + "." + System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(testName).Replace("_", ""); - }; - - Conventions.DefaultRunDescriptor = () => ScenarioDescriptors.Transports.Default; - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllSerializers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllSerializers.cs deleted file mode 100644 index f786b878e..000000000 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllSerializers.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NServiceBus.AcceptanceTests.ScenarioDescriptors -{ - using AcceptanceTesting.Support; - - public class AllSerializers : ScenarioDescriptor - { - public AllSerializers() - { - Add(Serializers.Bson); - Add(Serializers.Json); - Add(Serializers.Xml); - Add(Serializers.Binary); - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_ForwardReceivedMessagesTo_is_set.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_ForwardReceivedMessagesTo_is_set.cs new file mode 100644 index 000000000..f7ad7e855 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_ForwardReceivedMessagesTo_is_set.cs @@ -0,0 +1,72 @@ +namespace NServiceBus.AcceptanceTests.Audit +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using NServiceBus.Config; + using NUnit.Framework; + + public class When_ForwardReceivedMessagesTo_is_set : NServiceBusAcceptanceTest + { + [Test] + public void Should_forward_message() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => + { + bus.SendLocal(new MessageToForward()); + })) + .WithEndpoint() + .Done(c => c.GotForwardedMessage) + .Run(); + + Assert.IsTrue(context.GotForwardedMessage); + } + + public class Context : ScenarioContext + { + public bool GotForwardedMessage { get; set; } + } + + public class ForwardReceiver : EndpointConfigurationBuilder + { + public ForwardReceiver() + { + EndpointSetup(c => c.EndpointName("forward_receiver")); + } + + public class MessageToForwardHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MessageToForward message) + { + Context.GotForwardedMessage = true; + } + } + } + + public class EndpointThatForwards : EndpointConfigurationBuilder + { + public EndpointThatForwards() + { + EndpointSetup() + .WithConfig(c => c.ForwardReceivedMessagesTo = "forward_receiver"); + } + + public class MessageToForwardHandler : IHandleMessages + { + public void Handle(MessageToForward message) + { + } + } + } + + [Serializable] + public class MessageToForward : IMessage + { + } + } + } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_a_message_is_audited.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_a_message_is_audited.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_a_message_is_audited.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_a_message_is_audited.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_a_replymessage_is_audited.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_a_replymessage_is_audited.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_a_replymessage_is_audited.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_a_replymessage_is_audited.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_using_auditing_as_a_feature.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_auditing.cs similarity index 93% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_using_auditing_as_a_feature.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_auditing.cs index e40b70479..c26f3d634 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_using_auditing_as_a_feature.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_auditing.cs @@ -6,10 +6,10 @@ namespace NServiceBus.AcceptanceTests.Audit using AcceptanceTesting; using NUnit.Framework; - public class When_using_auditing_as_a_feature : NServiceBusAcceptanceTest + public class When_auditing : NServiceBusAcceptanceTest { [Test] - public void Message_should_not_be_forwarded_to_auditQueue_when_auditing_is_disabled() + public void Should_not_be_forwarded_to_auditQueue_when_auditing_is_disabled() { var context = new Context(); Scenario.Define(context) @@ -22,7 +22,7 @@ public void Message_should_not_be_forwarded_to_auditQueue_when_auditing_is_disab } [Test] - public void Message_should_be_forwarded_to_auditQueue_when_auditing_is_enabled() + public void Should_be_forwarded_to_auditQueue_when_auditing_is_enabled() { var context = new Context(); Scenario.Define(context) diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_using_audit_message_is_received.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_using_audit_message_is_received.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Audit/When_using_audit_message_is_received.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Audit/When_using_audit_message_is_received.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_Deferring_a_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_Deferring_a_message.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_Deferring_a_message.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_Deferring_a_message.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_TimeToBeReceived_has_expired.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_TimeToBeReceived_has_expired.cs similarity index 83% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_TimeToBeReceived_has_expired.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_TimeToBeReceived_has_expired.cs index 2e5b14759..0f01c3ea6 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_TimeToBeReceived_has_expired.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_TimeToBeReceived_has_expired.cs @@ -7,12 +7,12 @@ public class When_TimeToBeReceived_has_expired : NServiceBusAcceptanceTest { - [Test, Ignore("The TTL will only be started at the moment the timeoutmanager sends the message back, still giving the test a second to receive it")] + [Test] public void Message_should_not_be_received() { var context = new Context(); Scenario.Define(context) - .WithEndpoint(b => b.Given((bus, c) => bus.Defer(TimeSpan.FromSeconds(5), new MyMessage()))) + .WithEndpoint(b => b.Given((bus, c) => bus.SendLocal(new MyMessage()))) .Run(TimeSpan.FromSeconds(10)); Assert.IsFalse(context.WasCalled); } @@ -41,7 +41,7 @@ public void Handle(MyMessage message) } [Serializable] - [TimeToBeReceived("00:00:01")] + [TimeToBeReceived("00:00:00")] public class MyMessage : IMessage { } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_TimeToBeReceived_has_not_expired.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_TimeToBeReceived_has_not_expired.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_TimeToBeReceived_has_not_expired.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_TimeToBeReceived_has_not_expired.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_a_callback_for_local_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_a_callback_for_local_message.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_a_callback_for_local_message.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_a_callback_for_local_message.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_aborting_the_behavior_chain.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_aborting_the_behavior_chain.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_aborting_the_behavior_chain.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_aborting_the_behavior_chain.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_callback_from_a_send_only.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_callback_from_a_send_only.cs new file mode 100644 index 000000000..a9b8c090c --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_callback_from_a_send_only.cs @@ -0,0 +1,52 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_callback_from_a_send_only : NServiceBusAcceptanceTest + { + [Test] + public void Should_throw() + { + Scenario.Define() + .WithEndpoint(b => b.Given((bus, c) => + { + var exception = Assert.Throws(() => bus.Send(new MyMessage()).Register(result => { })); + Assert.AreEqual("Callbacks are invalid in a sendonly endpoint.", exception.Message); + + })) + .WithEndpoint() + .Run(); + } + + public class Context : ScenarioContext + { + } + + public class SendOnlyEndpoint : EndpointConfigurationBuilder + { + public SendOnlyEndpoint() + { + EndpointSetup() + .SendOnly() + .AddMapping(typeof(Receiver)); + } + + } + public class Receiver : EndpointConfigurationBuilder + { + public Receiver() + { + EndpointSetup(); + } + } + + [Serializable] + public class MyMessage : ICommand + { + } + + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_handling_current_message_later.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_handling_current_message_later.cs similarity index 81% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_handling_current_message_later.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_handling_current_message_later.cs index 0559fff7d..51c46427e 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_handling_current_message_later.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_handling_current_message_later.cs @@ -3,26 +3,15 @@ using System; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Config; + using NServiceBus.Features; using NServiceBus.UnitOfWork; using NUnit.Framework; public class When_handling_current_message_later : NServiceBusAcceptanceTest { [Test] - public void Should_commit_unit_of_work() - { - var context = new Context(); - - Scenario.Define(context) - .WithEndpoint(b => b.Given(bus => bus.SendLocal(new SomeMessage()))) - .Done(c => c.Done) - .Run(TimeSpan.FromSeconds(10)); - - Assert.True(context.UoWCommited); - } - - [Test] - public void Should_not_execute_subsequent_handlers() + public void Should_commit_unit_of_work_and_execute_subsequent_handlers() { var context = new Context(); @@ -31,6 +20,7 @@ public void Should_not_execute_subsequent_handlers() .Done(c => c.Done) .Run(); + Assert.True(context.UoWCommited); Assert.That(context.FirstHandlerInvocationCount, Is.EqualTo(2)); Assert.That(context.SecondHandlerInvocationCount, Is.EqualTo(1)); } @@ -38,9 +28,7 @@ public void Should_not_execute_subsequent_handlers() public class Context : ScenarioContext { public bool Done { get; set; } - public int FirstHandlerInvocationCount { get; set; } - public int SecondHandlerInvocationCount { get; set; } public bool UoWCommited { get; set; } } @@ -49,7 +37,16 @@ public class MyEndpoint : EndpointConfigurationBuilder { public MyEndpoint() { - EndpointSetup(b => b.RegisterComponents(r => r.ConfigureComponent(DependencyLifecycle.InstancePerCall))); + EndpointSetup(b => + { + b.RegisterComponents(r => r.ConfigureComponent(DependencyLifecycle.InstancePerCall)); + b.DisableFeature(); + b.DisableFeature(); + }) + .WithConfig(c => + { + c.MaxRetries = 0; + }); } class EnsureOrdering : ISpecifyMessageHandlerOrdering @@ -66,7 +63,6 @@ class CheckUnitOfWorkOutcome : IManageUnitsOfWork public void Begin() { - } public void End(Exception ex = null) @@ -104,7 +100,6 @@ public void Handle(SomeMessage message) [Serializable] public class SomeMessage : IMessage { } - } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_incoming_headers_should_be_shared.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_incoming_headers_should_be_shared.cs similarity index 99% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_incoming_headers_should_be_shared.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_incoming_headers_should_be_shared.cs index 612fc5091..2746b0b15 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_incoming_headers_should_be_shared.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_incoming_headers_should_be_shared.cs @@ -5,7 +5,6 @@ using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; - [Explicit] public class When_incoming_headers_should_be_shared : NServiceBusAcceptanceTest { [Test] @@ -61,8 +60,8 @@ class SecondHandler : IHandleMessages public void Handle(Message message) { var header = Bus.GetMessageHeader(message, "Key"); - Context.GotMessage = true; Context.SecondHandlerCanReadHeaderSetByFirstHandler = header == "Value"; + Context.GotMessage = true; } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_injecting_handler_props.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_injecting_handler_props.cs new file mode 100644 index 000000000..19d0347ac --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_injecting_handler_props.cs @@ -0,0 +1,67 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_injecting_handler_props : NServiceBusAcceptanceTest + { + [Test] + public void Run() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(c=>c.When(b=>b.SendLocal(new MyMessage()))) + .Done(c => c.WasCalled) + .Run(); + + Assert.AreEqual(10, context.Number); + Assert.AreEqual("Foo", context.Name); + } + + public class Context : ScenarioContext + { + public bool WasCalled { get; set; } + public string Name { get; set; } + public int Number { get; set; } + } + + public class Receiver : EndpointConfigurationBuilder + { + public Receiver() + { + EndpointSetup(c => + { + c.InitializeHandlerProperty("Number", 10); + c.InitializeHandlerProperty("Name", "Foo"); + }); + + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public IBus Bus { get; set; } + + public string Name { get; set; } + + public int Number { get; set; } + + public void Handle(MyMessage message) + { + Context.Number = Number; + Context.Name = Name; + Context.WasCalled = true; + } + } + } + + [Serializable] + public class MyMessage : ICommand + { + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_multiple_mappings_exists.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_multiple_mappings_exists.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_multiple_mappings_exists.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_multiple_mappings_exists.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_registering_custom_serializer.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_registering_custom_serializer.cs new file mode 100644 index 000000000..2312663a7 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_registering_custom_serializer.cs @@ -0,0 +1,148 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Runtime.Serialization.Formatters.Binary; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Features; + using NServiceBus.MessageInterfaces.MessageMapper.Reflection; + using NServiceBus.Serialization; + using NUnit.Framework; + + public class When_registering_custom_serializer : NServiceBusAcceptanceTest + { + [Test] + public void Should_register_via_type() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given( + (bus, c) => bus.SendLocal(new MyRequest()))) + .Done(c => c.HandlerGotTheRequest) + .Run(); + + Assert.IsTrue(context.SerializeCalled); + Assert.IsTrue(context.DeserializeCalled); + } + + [Test] + public void Should_register_via_definition() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given( + (bus, c) => bus.SendLocal(new MyRequest()))) + .Done(c => c.HandlerGotTheRequest) + .Run(); + + Assert.IsTrue(context.SerializeCalled); + Assert.IsTrue(context.DeserializeCalled); + } + + public class Context : ScenarioContext + { + public bool HandlerGotTheRequest { get; set; } + public bool SerializeCalled { get; set; } + public bool DeserializeCalled { get; set; } + } + + public class EndpointViaType : EndpointConfigurationBuilder + { + public EndpointViaType() + { + EndpointSetup(c => c.UseSerialization(typeof(MyCustomSerializer))); + } + + public class MyRequestHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyRequest request) + { + Context.HandlerGotTheRequest = true; + } + } + } + + public class EndpointViaDefinition : EndpointConfigurationBuilder + { + public EndpointViaDefinition() + { + EndpointSetup(c => c.UseSerialization(typeof(MySuperSerializer))); + } + + public class MyRequestHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyRequest request) + { + Context.HandlerGotTheRequest = true; + } + } + } + + [Serializable] + public class MyRequest : IMessage + { + } + + class MySuperSerializer : SerializationDefinition + { + protected override Type ProvidedByFeature() + { + return typeof(MySuperSerializerFeature); + } + } + + class MySuperSerializerFeature : Feature + { + public MySuperSerializerFeature() + { + EnableByDefault(); + } + + protected override void Setup(FeatureConfigurationContext context) + { + context.Container.ConfigureComponent(DependencyLifecycle.SingleInstance); + context.Container.ConfigureComponent(DependencyLifecycle.SingleInstance); + } + } + + class MyCustomSerializer : IMessageSerializer + { + public Context Context { get; set; } + + public void Serialize(object message, Stream stream) + { + var serializer = new BinaryFormatter(); + serializer.Serialize(stream, message); + + Context.SerializeCalled = true; + } + + public object[] Deserialize(Stream stream, IList messageTypes = null) + { + var serializer = new BinaryFormatter(); + + Context.DeserializeCalled = true; + stream.Position = 0; + var msg = serializer.Deserialize(stream); + + return new[] + { + msg + }; + } + + public string ContentType + { + get { return "MyCustomSerializer"; } + } + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_ensure_proper_headers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_ensure_proper_headers.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_ensure_proper_headers.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_ensure_proper_headers.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_from_a_send_only.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_from_a_send_only.cs similarity index 63% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_from_a_send_only.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_from_a_send_only.cs index 0c58790d1..9d4ae9542 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_from_a_send_only.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_from_a_send_only.cs @@ -3,6 +3,7 @@ using System; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Config; using NUnit.Framework; public class When_sending_from_a_send_only : NServiceBusAcceptanceTest @@ -26,13 +27,49 @@ public void Should_receive_the_message() Assert.True(context.WasCalled, "The message handler should be called"); } + [Test] + public void Should_not_need_audit_or_fault_forwarding_config_to_start() + { + var context = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.SendOnlyEndpointWasStarted) + .Run(); + + Assert.True(context.SendOnlyEndpointWasStarted, "The endpoint should have started without any errors"); + } + public class Context : ScenarioContext { public bool WasCalled { get; set; } - public Guid Id { get; set; } + + public bool SendOnlyEndpointWasStarted { get; set; } + } + + public class SendOnlyEndpoint : EndpointConfigurationBuilder + { + public SendOnlyEndpoint() + { + EndpointSetup() + .SendOnly(); + } + + public class Bootstrapper : IWantToRunWhenConfigurationIsComplete + { + public Context Context { get; set; } + + public void Run(Configure config) + { + Context.SendOnlyEndpointWasStarted = true; + } + } } + public class Sender : EndpointConfigurationBuilder { public Sender() diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_to_another_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_to_another_endpoint.cs similarity index 53% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_to_another_endpoint.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_to_another_endpoint.cs index a99fa110a..f50ef2732 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_to_another_endpoint.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_to_another_endpoint.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.AcceptanceTests.ScenarioDescriptors; using NUnit.Framework; public class When_sending_to_another_endpoint : NServiceBusAcceptanceTest @@ -12,27 +11,30 @@ public class When_sending_to_another_endpoint : NServiceBusAcceptanceTest [Test] public void Should_receive_the_message() { - Scenario.Define(() => new Context { Id = Guid.NewGuid() }) - .WithEndpoint(b => b.Given((bus, context) => + var context = new Context + { + Id = Guid.NewGuid() + }; + + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => { bus.OutgoingHeaders["MyStaticHeader"] = "StaticHeaderValue"; bus.Send(m=> { - m.Id = context.Id; + m.Id = c.Id; bus.SetMessageHeader(m, "MyHeader", "MyHeaderValue"); }); })) .WithEndpoint() .Done(c => c.WasCalled) - .Repeat(r =>r.For(Serializers.Binary)) - .Should(c => - { - Assert.True(c.WasCalled, "The message handler should be called"); - Assert.AreEqual(1, c.TimesCalled, "The message handler should only be invoked once"); - Assert.AreEqual("StaticHeaderValue",c.ReceivedHeaders["MyStaticHeader"], "Static headers should be attached to outgoing messages"); - Assert.AreEqual("MyHeaderValue", c.MyHeader, "Static headers should be attached to outgoing messages"); - }) .Run(); + + Assert.True(context.WasCalled, "The message handler should be called"); + Assert.AreEqual(1, context.TimesCalled, "The message handler should only be invoked once"); + Assert.AreEqual("StaticHeaderValue", context.ReceivedHeaders["MyStaticHeader"], "Static headers should be attached to outgoing messages"); + Assert.AreEqual("MyHeaderValue", context.MyHeader, "Static headers should be attached to outgoing messages"); + } public class Context : ScenarioContext @@ -63,33 +65,32 @@ public Receiver() { EndpointSetup(); } - } - - [Serializable] - public class MyMessage : ICommand - { - public Guid Id { get; set; } - } - public class MyMessageHandler : IHandleMessages - { - public Context Context { get; set; } + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } - public IBus Bus { get; set; } + public IBus Bus { get; set; } - public void Handle(MyMessage message) - { - if (Context.Id != message.Id) - return; + public void Handle(MyMessage message) + { + if (Context.Id != message.Id) + return; - Context.TimesCalled++; + Context.TimesCalled++; - Context.MyHeader = Bus.GetMessageHeader(message, "MyHeader"); + Context.MyHeader = Bus.GetMessageHeader(message, "MyHeader"); - Context.ReceivedHeaders = Bus.CurrentMessageContext.Headers; + Context.ReceivedHeaders = Bus.CurrentMessageContext.Headers; - Context.WasCalled = true; + Context.WasCalled = true; + } } } + + public class MyMessage : IMessage + { + public Guid Id { get; set; } + } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_with_conventions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_with_conventions.cs new file mode 100644 index 000000000..13bea0e8f --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_with_conventions.cs @@ -0,0 +1,56 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_sending_with_conventions : NServiceBusAcceptanceTest + { + [Test] + public void Should_receive_the_message() + { + Scenario.Define(() => new Context { Id = Guid.NewGuid() }) + .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MyMessage + { + Id = context.Id + }))) + .Done(c => c.WasCalled) + .Run(); + } + + public class Context : ScenarioContext + { + public bool WasCalled { get; set; } + public Guid Id { get; set; } + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(b => b.Conventions().DefiningMessagesAs(type => type == typeof(MyMessage))); + } + } + + [Serializable] + public class MyMessage + { + public Guid Id { get; set; } + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + + public void Handle(MyMessage message) + { + if (Context.Id != message.Id) + return; + + Context.WasCalled = true; + } + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_with_no_correlation_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_with_no_correlation_id.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_sending_with_no_correlation_id.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_sending_with_no_correlation_id.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_a_custom_correlation_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_a_custom_correlation_id.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_a_custom_correlation_id.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_a_custom_correlation_id.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_a_greedy_convention.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_a_greedy_convention.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_a_greedy_convention.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_a_greedy_convention.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callback_to_get_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callback_to_get_message.cs new file mode 100644 index 000000000..b973a07e7 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callback_to_get_message.cs @@ -0,0 +1,59 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using System.Linq; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_using_callback_to_get_message : NServiceBusAcceptanceTest + { + [Test] + public void Should_receive_message() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given( + (bus, c) => bus.SendLocal(new MyRequest()).Register(r => + { + c.Reply = (MyReply)r.Messages.Single(); + c.CallbackFired = true; + }))) + .Done(c => c.CallbackFired) + .Run(); + + Assert.IsNotNull(context.Reply); + } + + public class Context : ScenarioContext + { + public bool CallbackFired { get; set; } + public MyReply Reply { get; set; } + } + + public class EndpointWithLocalCallback : EndpointConfigurationBuilder + { + public EndpointWithLocalCallback() + { + EndpointSetup(); + } + + public class MyRequestHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public void Handle(MyRequest request) + { + Bus.Reply(new MyReply()); + } + } + } + + [Serializable] + public class MyRequest : IMessage { } + + [Serializable] + public class MyReply : IMessage { } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_callbacks_from_older_versions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_from_older_versions.cs similarity index 97% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_callbacks_from_older_versions.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_from_older_versions.cs index 37fb6668a..ce893674d 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_callbacks_from_older_versions.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_from_older_versions.cs @@ -64,6 +64,7 @@ public void MutateIncoming(TransportMessage transportMessage) { //early versions of did not have a Reply MessageIntent when Bus.Return is called transportMessage.MessageIntent = MessageIntentEnum.Send; + transportMessage.Headers[Headers.NServiceBusVersion] = "3.3.0"; } public void Customize(BusConfiguration configuration) diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_callbacks_in_a_scaleout.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_in_a_scaleout.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Basic/When_using_callbacks_in_a_scaleout.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_in_a_scaleout.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_with_messageid_eq_cid_.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_with_messageid_eq_cid_.cs new file mode 100644 index 000000000..2a8cdcaaa --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_callbacks_with_messageid_eq_cid_.cs @@ -0,0 +1,73 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.MessageMutator; + using NServiceBus.Unicast.Messages; + using NUnit.Framework; + + public class When_using_callbacks_with_messageid_eq_cid_ : NServiceBusAcceptanceTest + { + [Test] + public void Should_trigger_the_callback() + { + var context = Scenario.Define() + .WithEndpoint(b=>b.Given( + (bus,c)=>bus.SendLocal(new MyRequest()).Register(r => + { + c.CallbackFired = true; + }))) + .Done(c => c.CallbackFired) + .Run(); + + Assert.True(context.CallbackFired); + } + + public class Context : ScenarioContext + { + public bool CallbackFired { get; set; } + } + + public class EndpointWithLocalCallback : EndpointConfigurationBuilder + { + public EndpointWithLocalCallback() + { + EndpointSetup(); + } + + public class MyRequestHandler : IHandleMessages + { + public Context Context { get; set; } + + public IBus Bus { get; set; } + + public void Handle(MyRequest request) + { + Assert.False(Context.CallbackFired); + + Bus.Return(1); + } + } + } + + class BodyMutator : IMutateOutgoingTransportMessages, INeedInitialization + { + public void MutateOutgoing(LogicalMessage logicalMessage, TransportMessage transportMessage) + { + //to simulate native interop cases where MessageId == CorrelationId + transportMessage.Headers[Headers.MessageId] = transportMessage.Headers[Headers.CorrelationId]; + } + + public void Customize(BusConfiguration configuration) + { + configuration.RegisterComponents(c => c.ConfigureComponent(DependencyLifecycle.InstancePerCall)); + } + + + } + + [Serializable] + public class MyRequest : IMessage{} + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_ineedinitialization.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_ineedinitialization.cs new file mode 100644 index 000000000..cd28866b4 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Basic/When_using_ineedinitialization.cs @@ -0,0 +1,101 @@ +namespace NServiceBus.AcceptanceTests.Basic +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_using_ineedinitialization : NServiceBusAcceptanceTest + { + [Test] + public void Should_be_able_to_set_endpoint_name() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .WithEndpoint() + .Done(c => c.WasCalled) + .Run(); + + Assert.True(context.WasCalled, "The message handler should be called"); + } + + public class Context : ScenarioContext + { + public bool WasCalled { get; set; } + } + + public class Sender : EndpointConfigurationBuilder + { + public Sender() + { + EndpointSetup(); + } + } + + public class Receiver : EndpointConfigurationBuilder + { + public Receiver() + { + EndpointSetup() + .AddMapping(typeof(Sender)); + } + + public class SetEndpointName : INeedInitialization + { + public void Customize(BusConfiguration config) + { + config.EndpointName("ineedinitialization_receiver"); + } + } + + public class SendMessageToSender: IWantToRunWhenBusStartsAndStops + { + public IBus Bus { get; set; } + + public void Start() + { + Bus.Send(new SendMessage()); + } + + public void Stop() + { + } + } + } + + [Serializable] + public class SendMessage : ICommand + { + } + + [Serializable] + public class MyMessage : ICommand + { + public Guid Id { get; set; } + } + + public class SendMessageHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public void Handle(SendMessage message) + { + Bus.Send("ineedinitialization_receiver", new MyMessage()); + } + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public IBus Bus { get; set; } + + public void Handle(MyMessage message) + { + Context.WasCalled = true; + } + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs similarity index 92% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs index 12221c8fe..897f2e888 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When_IWantToRunWhenBusStartsAndStops_Start_throws.cs @@ -5,7 +5,7 @@ using NServiceBus.AcceptanceTests.EndpointTemplates; using NUnit.Framework; - public class When_IWantToRunWhenBusStartsAndStops_Start_throws : NServiceBusAcceptanceTest + public class When_Start_throws : NServiceBusAcceptanceTest { [Test] public void Should_shutdown_bus_cleanly() diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When__startup_is_complete.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When__startup_is_complete.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When__startup_is_complete.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When__startup_is_complete.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When_a_config_override_is_found.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When_a_config_override_is_found.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Config/When_a_config_override_is_found.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Config/When_a_config_override_is_found.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/CriticalError/When_registering_a_custom_criticalErrorHandler.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/CriticalError/When_registering_a_custom_criticalErrorHandler.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/CriticalError/When_registering_a_custom_criticalErrorHandler.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/CriticalError/When_registering_a_custom_criticalErrorHandler.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_databus_properties.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_sending_databus_properties.cs similarity index 81% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_databus_properties.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_sending_databus_properties.cs index b13fd2f5f..e5197b50f 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/DataBus/When_sending_databus_properties.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_sending_databus_properties.cs @@ -4,7 +4,6 @@ using EndpointTemplates; using AcceptanceTesting; using NUnit.Framework; - using ScenarioDescriptors; public class When_sending_databus_properties:NServiceBusAcceptanceTest { @@ -13,16 +12,16 @@ public class When_sending_databus_properties:NServiceBusAcceptanceTest [Test] public void Should_receive_the_message_the_largeproperty_correctly() { - Scenario.Define() + var context = Scenario.Define() .WithEndpoint(b => b.Given(bus=> bus.Send(new MyMessageWithLargePayload { Payload = new DataBusProperty(PayloadToSend) }))) .WithEndpoint() - .Done(context => context.ReceivedPayload != null) - .Repeat(r => r.For()) - .Should(c => Assert.AreEqual(PayloadToSend, c.ReceivedPayload, "The large payload should be marshalled correctly using the databus")) + .Done(c => c.ReceivedPayload != null) .Run(); + + Assert.AreEqual(PayloadToSend, context.ReceivedPayload, "The large payload should be marshalled correctly using the databus"); } public class Context : ScenarioContext @@ -35,7 +34,7 @@ public class Sender : EndpointConfigurationBuilder { public Sender() { - EndpointSetup(builder => builder.FileShareDataBus(@".\databus\sender")) + EndpointSetup(builder => builder.UseDataBus().BasePath(@".\databus\sender")) .AddMapping(typeof (Receiver)); } } @@ -44,7 +43,7 @@ public class Receiver : EndpointConfigurationBuilder { public Receiver() { - EndpointSetup(builder => builder.FileShareDataBus(@".\databus\sender")); + EndpointSetup(builder => builder.UseDataBus().BasePath(@".\databus\sender")); } public class MyMessageHandler : IHandleMessages diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_using_custom_IDataBus.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_using_custom_IDataBus.cs new file mode 100644 index 000000000..a38446fb3 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DataBus/When_using_custom_IDataBus.cs @@ -0,0 +1,145 @@ +namespace NServiceBus.AcceptanceTests.DataBus +{ + using System; + using System.IO; + using EndpointTemplates; + using AcceptanceTesting; + using NServiceBus.DataBus; + using NUnit.Framework; + + public class When_using_custom_IDataBus : NServiceBusAcceptanceTest + { + static byte[] PayloadToSend = new byte[1024 * 10]; + + [Test] + public void Should_be_able_to_register_via_fluent() + { + var context = new Context + { + TempPath = Path.GetTempFileName() + }; + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => bus.Send(new MyMessageWithLargePayload + { + Payload = new DataBusProperty(PayloadToSend) + }))) + .WithEndpoint() + .Done(c => c.ReceivedPayload != null) + .Run(); + + Assert.AreEqual(PayloadToSend, context.ReceivedPayload, "The large payload should be marshalled correctly using the databus"); + } + + [Test] + public void Should_be_able_to_register_via_container() + { + var context = new Context + { + TempPath = Path.GetTempFileName() + }; + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus=> bus.Send(new MyMessageWithLargePayload + { + Payload = new DataBusProperty(PayloadToSend) + }))) + .WithEndpoint() + .Done(c => c.ReceivedPayload != null) + .Run(); + + Assert.AreEqual(PayloadToSend, context.ReceivedPayload, "The large payload should be marshalled correctly using the databus"); + } + + public class Context : ScenarioContext + { + public string TempPath { get; set; } + public byte[] ReceivedPayload { get; set; } + } + + public class Sender : EndpointConfigurationBuilder + { + public Sender() + { + EndpointSetup(b => b.RegisterComponents(r => r.RegisterSingleton(new MyDataBus()))) + .AddMapping(typeof(Receiver)); + } + } + + public class Receiver : EndpointConfigurationBuilder + { + public Receiver() + { + EndpointSetup(b => b.RegisterComponents(r => r.RegisterSingleton(new MyDataBus()))); + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyMessageWithLargePayload messageWithLargePayload) + { + Context.ReceivedPayload = messageWithLargePayload.Payload.Value; + } + } + } + + public class SenderViaFluent : EndpointConfigurationBuilder + { + public SenderViaFluent() + { + EndpointSetup(b => b.UseDataBus(typeof(MyDataBus))) + .AddMapping(typeof(ReceiverViaFluent)); + } + } + + public class ReceiverViaFluent : EndpointConfigurationBuilder + { + public ReceiverViaFluent() + { + EndpointSetup(b => b.UseDataBus(typeof(MyDataBus))); + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyMessageWithLargePayload messageWithLargePayload) + { + Context.ReceivedPayload = messageWithLargePayload.Payload.Value; + } + } + } + + public class MyDataBus : IDataBus + { + public Context Context { get; set; } + + public Stream Get(string key) + { + return File.OpenRead(Context.TempPath); + } + + public string Put(Stream stream, TimeSpan timeToBeReceived) + { + using (var destination = File.OpenWrite(Context.TempPath)) + { + stream.CopyTo(destination); + } + return "key"; + } + + public void Start() + { + } + } + + [Serializable] + public class MyMessageWithLargePayload : ICommand + { + public DataBusProperty Payload { get; set; } + } + } + + +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DeterministicGuid.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DeterministicGuid.cs new file mode 100644 index 000000000..e062b2b9a --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/DeterministicGuid.cs @@ -0,0 +1,21 @@ +namespace NServiceBus.Utils +{ + using System; + using System.Security.Cryptography; + using System.Text; + + 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()) + { + var inputBytes = Encoding.Default.GetBytes(String.Concat(data)); + var hashBytes = provider.ComputeHash(inputBytes); + // generate a guid from the hash: + return new Guid(hashBytes); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_config.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_config.cs similarity index 82% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_config.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_config.cs index add0c26fd..57ca91a4c 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_config.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_config.cs @@ -7,15 +7,14 @@ using NServiceBus.Config; using NServiceBus.Config.ConfigurationSource; using NUnit.Framework; - using ScenarioDescriptors; public class When_using_Rijndael_with_config : NServiceBusAcceptanceTest { [Test] public void Should_receive_decrypted_message() { - Scenario.Define() - .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MessageWithSecretData + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageWithSecretData { Secret = "betcha can't guess my secret", SubProperty = new MySecretSubProperty {Secret = "My sub secret"}, @@ -33,20 +32,17 @@ public void Should_receive_decrypted_message() } } }))) - .Done(c => c.Done) - .Repeat(r => r.For()) - .Should(c => - { - Assert.AreEqual("betcha can't guess my secret", c.Secret); - Assert.AreEqual("My sub secret", c.SubPropertySecret); - CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, c.CreditCards); - }) + .Done(c => c.GotTheMessage) .Run(); + + Assert.AreEqual("betcha can't guess my secret", context.Secret); + Assert.AreEqual("My sub secret", context.SubPropertySecret); + CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, context.CreditCards); } public class Context : ScenarioContext { - public bool Done { get; set; } + public bool GotTheMessage { get; set; } public string Secret { get; set; } @@ -78,7 +74,7 @@ public void Handle(MessageWithSecretData message) message.CreditCards[1].Number.Value }; - Context.Done = true; + Context.GotTheMessage = true; } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_custom.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_custom.cs similarity index 80% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_custom.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_custom.cs index 18898e0ff..486ef9749 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_custom.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_custom.cs @@ -5,15 +5,14 @@ using EndpointTemplates; using AcceptanceTesting; using NUnit.Framework; - using ScenarioDescriptors; public class When_using_Rijndael_with_custom : NServiceBusAcceptanceTest { [Test] public void Should_receive_decrypted_message() { - Scenario.Define() - .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MessageWithSecretData + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageWithSecretData { Secret = "betcha can't guess my secret", SubProperty = new MySecretSubProperty {Secret = "My sub secret"}, @@ -31,20 +30,17 @@ public void Should_receive_decrypted_message() } } }))) - .Done(c => c.Done) - .Repeat(r => r.For()) - .Should(c => - { - Assert.AreEqual("betcha can't guess my secret", c.Secret); - Assert.AreEqual("My sub secret", c.SubPropertySecret); - CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, c.CreditCards); - }) + .Done(c => c.GetTheMessage) .Run(); + + Assert.AreEqual("betcha can't guess my secret", context.Secret); + Assert.AreEqual("My sub secret", context.SubPropertySecret); + CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, context.CreditCards); } public class Context : ScenarioContext { - public bool Done { get; set; } + public bool GetTheMessage { get; set; } public string Secret { get; set; } @@ -76,7 +72,7 @@ public void Handle(MessageWithSecretData message) message.CreditCards[1].Number.Value }; - Context.Done = true; + Context.GetTheMessage = true; } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_multikey.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_multikey.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_Rijndael_with_multikey.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_Rijndael_with_multikey.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_encryption_with_custom_service.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_encryption_with_custom_service.cs similarity index 82% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_encryption_with_custom_service.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_encryption_with_custom_service.cs index f77774a9f..65a9dc0e5 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Encryption/When_using_encryption_with_custom_service.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Encryption/When_using_encryption_with_custom_service.cs @@ -7,15 +7,14 @@ using AcceptanceTesting; using NServiceBus.Encryption; using NUnit.Framework; - using ScenarioDescriptors; public class When_using_encryption_with_custom_service : NServiceBusAcceptanceTest { [Test] public void Should_receive_decrypted_message() { - Scenario.Define() - .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MessageWithSecretData + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageWithSecretData { Secret = "betcha can't guess my secret", SubProperty = new MySecretSubProperty {Secret = "My sub secret"}, @@ -33,20 +32,17 @@ public void Should_receive_decrypted_message() } } }))) - .Done(c => c.Done) - .Repeat(r => r.For()) - .Should(c => - { - Assert.AreEqual("betcha can't guess my secret", c.Secret); - Assert.AreEqual("My sub secret", c.SubPropertySecret); - CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, c.CreditCards); - }) + .Done(c => c.GotTheMessage) .Run(); + + Assert.AreEqual("betcha can't guess my secret", context.Secret); + Assert.AreEqual("My sub secret", context.SubPropertySecret); + CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, context.CreditCards); } public class Context : ScenarioContext { - public bool Done { get; set; } + public bool GotTheMessage { get; set; } public string Secret { get; set; } @@ -78,7 +74,7 @@ public void Handle(MessageWithSecretData message) message.CreditCards[1].Number.Value }; - Context.Done = true; + Context.GotTheMessage = true; } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/EndpointTemplates/ConfigureExtensions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/EndpointTemplates/ConfigureExtensions.cs similarity index 95% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/EndpointTemplates/ConfigureExtensions.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/EndpointTemplates/ConfigureExtensions.cs index 383d19025..6fde4375b 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/EndpointTemplates/ConfigureExtensions.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/EndpointTemplates/ConfigureExtensions.cs @@ -25,7 +25,11 @@ public static void DefineTransport(this BusConfiguration builder, IDictionary { diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/HostInformation/When_a_message_is_received.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_a_message_is_received.cs similarity index 96% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/HostInformation/When_a_message_is_received.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_a_message_is_received.cs index ee2efedec..afb123d85 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/HostInformation/When_a_message_is_received.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_a_message_is_received.cs @@ -11,7 +11,6 @@ public class When_a_message_is_received : NServiceBusAcceptanceTest { static Guid hostId = new Guid("39365055-daf2-439e-b84d-acbef8fd803d"); const string displayName = "FooBar"; - const string displayInstanceIdentifier = "FooBar is great!"; [Test] public void Host_information_should_be_available_in_headers() @@ -65,11 +64,10 @@ class OverrideHostInformation : IWantToRunWhenConfigurationIsComplete public void Run(Configure config) { -#pragma warning disable 618 var hostInformation = new Hosting.HostInformation(hostId, displayName); -#pragma warning restore 618 - +#pragma warning disable 618 UnicastBus.HostInformation = hostInformation; +#pragma warning restore 618 } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_customising_hostinfo.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_customising_hostinfo.cs new file mode 100644 index 000000000..5f25fa2e3 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_customising_hostinfo.cs @@ -0,0 +1,81 @@ +namespace NServiceBus.AcceptanceTests.HostInformation +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Utils; + using NUnit.Framework; + + public class When_customising_hostinfo : NServiceBusAcceptanceTest + { + static Guid hostId = new Guid("6c0f50de-dac9-4693-b138-6d1033c15ed6"); + static string instanceName = "Foo"; + static string hostName = "Bar"; + + [Test] + public void UsingCustomIdentifier() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(e => e.Given(b => b.SendLocal(new MyMessage()))) + .Done(c => c.HostId != Guid.Empty) + .Run(); + + Assert.AreEqual(hostId, context.HostId); + } + + [Test] + public void UsingNames() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(e => e.Given(b => b.SendLocal(new MyMessage()))) + .Done(c => c.HostId != Guid.Empty) + .Run(); + + Assert.AreEqual(DeterministicGuid.Create(instanceName, hostName), context.HostId); + } + + public class UsingNames_Endpoint : EndpointConfigurationBuilder + { + public UsingNames_Endpoint() + { + EndpointSetup(b => b.UniquelyIdentifyRunningInstance().UsingNames(instanceName, hostName)); + } + } + + public class UsingCustomIdentifier_Endpoint : EndpointConfigurationBuilder + { + public UsingCustomIdentifier_Endpoint() + { + EndpointSetup(b => b.UniquelyIdentifyRunningInstance().UsingCustomIdentifier(hostId)); + } + } + + public class MyMessageHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public Context Context { get; set; } + + public void Handle(MyMessage message) + { + Context.HostDisplayName = Bus.GetMessageHeader(message, Headers.HostDisplayName); + Context.HostId = new Guid(Bus.GetMessageHeader(message, Headers.HostId)); + } + } + + public class Context : ScenarioContext + { + public Guid HostId { get; set; } + public string HostDisplayName { get; set; } + } + + [Serializable] + public class MyMessage : ICommand + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostid.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostid.cs new file mode 100644 index 000000000..81cff1312 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostid.cs @@ -0,0 +1,87 @@ +namespace NServiceBus.AcceptanceTests.HostInformation +{ + using System; + using System.Collections.Concurrent; + using System.Reflection; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Features; + using NUnit.Framework; + + public class When_feature_overrides_hostid : NServiceBusAcceptanceTest + { + + [Test] + public void MD5_should_not_be_used() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(e => e.Given(b => b.SendLocal(new MyMessage()))) + .Done(c => c.Done) + .Run(); + + Assert.IsTrue(context.NotSet); + } + + public class MyEndpoint : EndpointConfigurationBuilder + { + public MyEndpoint() + { + EndpointSetup(c => c.UniquelyIdentifyRunningInstance().UsingCustomIdentifier(Guid.NewGuid())); + } + } + + public class MyFeatureThatOverridesHostInformationDefaults : Feature + { + bool notSet; + + public MyFeatureThatOverridesHostInformationDefaults() + { + EnableByDefault(); + DependsOn("UnicastBus"); + Defaults(s => + { + // remove the override, we need to hack it via reflection! + var fieldInfo = s.GetType().GetField("Overrides", BindingFlags.Instance | BindingFlags.NonPublic); + var dictionary = (ConcurrentDictionary)fieldInfo.GetValue(s); + object s2; + dictionary.TryRemove("NServiceBus.HostInformation.HostId", out s2); + + // Try to get value, setting should not exist + notSet = !s.HasSetting("NServiceBus.HostInformation.HostId"); + + // Set override again so we have something + s.Set("NServiceBus.HostInformation.HostId", Guid.NewGuid()); + + }); + } + + protected override void Setup(FeatureConfigurationContext context) + { + context.Container.ConfigureProperty(c => c.NotSet, notSet); + } + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyMessage message) + { + Context.Done = true; + } + } + + public class Context : ScenarioContext + { + public bool NotSet { get; set; } + public bool Done { get; set; } + } + + [Serializable] + public class MyMessage : ICommand + { + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostinfo.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostinfo.cs new file mode 100644 index 000000000..3b28f9b92 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/HostInformation/When_feature_overrides_hostinfo.cs @@ -0,0 +1,84 @@ +namespace NServiceBus.AcceptanceTests.HostInformation +{ + using System; + using System.Collections.Generic; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Features; + using NUnit.Framework; + + public class When_feature_overrides_hostinfo : NServiceBusAcceptanceTest + { + static Guid hostId = new Guid("6c0f50de-dac9-4693-b138-6d1033c15ed6"); + static string instanceName = "Foo"; + + [Test] + public void HostInfo_is_changed() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(e => e.Given(b => b.SendLocal(new MyMessage()))) + .Done(c => c.HostId != Guid.Empty) + .Run(); + + Assert.AreEqual(hostId, context.HostId); + Assert.AreEqual(instanceName, context.HostDisplayName); + } + + public class MyEndpoint : EndpointConfigurationBuilder + { + public MyEndpoint() + { + EndpointSetup(); + } + } + + public class MyFeatureThatOverridesHostInformationDefaults : Feature + { + public MyFeatureThatOverridesHostInformationDefaults() + { + EnableByDefault(); + DependsOn("UnicastBus"); + Defaults(s => + { + s.SetDefault("NServiceBus.HostInformation.HostId", hostId); + s.SetDefault("NServiceBus.HostInformation.DisplayName", instanceName); + s.SetDefault("NServiceBus.HostInformation.Properties", new Dictionary + { + {"RoleName", "My role name"}, + {"RoleInstanceId", "the role instance id"}, + }); + }); + } + + protected override void Setup(FeatureConfigurationContext context) + { + } + } + + public class MyMessageHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public Context Context { get; set; } + + public void Handle(MyMessage message) + { + Context.HostDisplayName = Bus.GetMessageHeader(message, Headers.HostDisplayName); + Context.HostId = new Guid(Bus.GetMessageHeader(message, Headers.HostId)); + } + } + + public class Context : ScenarioContext + { + public Guid HostId { get; set; } + public string HostDisplayName { get; set; } + } + + [Serializable] + public class MyMessage : ICommand + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/Issue_1980.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/Issue_1980.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/Issue_1980.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/Issue_1980.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/When_defining_outgoing_message_mutators.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/When_defining_outgoing_message_mutators.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/When_defining_outgoing_message_mutators.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/When_defining_outgoing_message_mutators.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/When_outgoing_mutator_replaces_instance.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/When_outgoing_mutator_replaces_instance.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Mutators/When_outgoing_mutator_replaces_instance.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Mutators/When_outgoing_mutator_replaces_instance.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NServiceBusAcceptanceTest.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NServiceBusAcceptanceTest.cs new file mode 100644 index 000000000..543d1ec39 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NServiceBusAcceptanceTest.cs @@ -0,0 +1,40 @@ +namespace NServiceBus.AcceptanceTests +{ + using System.Linq; + using AcceptanceTesting.Customization; + using NUnit.Framework; + + /// + /// Base class for all the NSB test that sets up our conventions + /// + [TestFixture] + // ReSharper disable once PartialTypeWithSinglePart + public abstract partial class NServiceBusAcceptanceTest + { + [SetUp] + public void SetUp() + { + Conventions.EndpointNamingConvention = t => + { + var classAndEndpoint = t.FullName.Split('.').Last(); + + var testName = classAndEndpoint.Split('+').First(); + + testName = testName.Replace("When_", ""); + + var endpointBuilder = classAndEndpoint.Split('+').Last(); + + + testName = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(testName); + + testName = testName.Replace("_", ""); + + + + return testName +"."+ endpointBuilder; + }; + + Conventions.DefaultRunDescriptor = () => ScenarioDescriptors.Transports.Default; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_blowing_up_just_after_dispatch.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_blowing_up_just_after_dispatch.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_blowing_up_just_after_dispatch.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_blowing_up_just_after_dispatch.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_outbox_with_auditing.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_outbox_with_auditing.cs new file mode 100644 index 000000000..90919363e --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_outbox_with_auditing.cs @@ -0,0 +1,81 @@ +namespace NServiceBus.AcceptanceTests.NonDTC +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using NServiceBus.AcceptanceTests.ScenarioDescriptors; + using NServiceBus.Configuration.AdvanceExtensibility; + using NUnit.Framework; + + public class When_outbox_with_auditing : NServiceBusAcceptanceTest + { + [Test] + public void Should_be_forwarded_to_auditQueue() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeAudited()))) + .WithEndpoint() + .Done(c => c.IsMessageHandlingComplete && context.IsMessageHandledByTheAuditEndpoint) + .Repeat(r => r.For()) + .Run(); + + Assert.IsTrue(context.IsMessageHandledByTheAuditEndpoint); + } + + public class Context : ScenarioContext + { + public bool IsMessageHandlingComplete { get; set; } + public bool IsMessageHandledByTheAuditEndpoint { get; set; } + } + + public class EndpointWithOutboxAndAuditOn : EndpointConfigurationBuilder + { + + public EndpointWithOutboxAndAuditOn() + { + EndpointSetup( + b => + { + b.GetSettings().Set("DisableOutboxTransportCheck", true); + b.EnableOutbox(); + }) + .AuditTo(); + } + + class MessageToBeAuditedHandler : IHandleMessages + { + public Context MyContext { get; set; } + + public void Handle(MessageToBeAudited message) + { + MyContext.IsMessageHandlingComplete = true; + } + } + } + + public class EndpointThatHandlesAuditMessages : EndpointConfigurationBuilder + { + + public EndpointThatHandlesAuditMessages() + { + EndpointSetup(); + } + + class AuditMessageHandler : IHandleMessages + { + public Context MyContext { get; set; } + + public void Handle(MessageToBeAudited message) + { + MyContext.IsMessageHandledByTheAuditEndpoint = true; + } + } + } + + [Serializable] + public class MessageToBeAudited : IMessage + { + } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_receiving_a_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_receiving_a_message.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_receiving_a_message.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_receiving_a_message.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_sending_from_a_non_dtc_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_sending_from_a_non_dtc_endpoint.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonDTC/When_sending_from_a_non_dtc_endpoint.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonDTC/When_sending_from_a_non_dtc_endpoint.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonTx/When_sending_inside_ambient_tx.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonTx/When_sending_inside_ambient_tx.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/NonTx/When_sending_inside_ambient_tx.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/NonTx/When_sending_inside_ambient_tx.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_CriticalTime_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_CriticalTime_enabled.cs similarity index 93% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_CriticalTime_enabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_CriticalTime_enabled.cs index 864e0c2fd..c94eb15a2 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_CriticalTime_enabled.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_CriticalTime_enabled.cs @@ -15,7 +15,7 @@ public class When_CriticalTime_enabled : NServiceBusAcceptanceTest [Explicit("Since perf counters need to be enabled with powershell")] public void Should_have_perf_counter_set() { - using (var counter = new PerformanceCounter("NServiceBus", "Critical Time", "PerformanceMonitoring.Endpoint.WhenSendingWithCriticalTimeEnabled." + Transports.Default.Key, true)) + using (var counter = new PerformanceCounter("NServiceBus", "Critical Time", "CriticaltimeEnabled.Endpoint", false)) using (new Timer(state => CheckPerfCounter(counter), null, 0, 100)) { var context = new Context(); @@ -32,7 +32,7 @@ public void Should_have_perf_counter_set() void CheckPerfCounter(PerformanceCounter counter) { float rawValue = counter.RawValue; - if (rawValue >0) + if (rawValue > 0) { counterValue = rawValue; } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_deferring_a_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_deferring_a_message.cs new file mode 100644 index 000000000..fcc33db49 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_deferring_a_message.cs @@ -0,0 +1,71 @@ +namespace NServiceBus.AcceptanceTests.PerfMon.CriticalTime +{ + using System; + using System.Diagnostics; + using System.Threading; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.AcceptanceTests.ScenarioDescriptors; + using NUnit.Framework; + + public class When_deferring_a_message : NServiceBusAcceptanceTest + { + float counterValue; + + [Test] + [Explicit("Since perf counters need to be enabled with powershell")] + public void Critical_time_should_not_include_the_time_message_was_waiting_in_the_timeout_store() + { + using (var counter = new PerformanceCounter("NServiceBus", "Critical Time", "DeferringAMessage.Endpoint", false)) + using (new Timer(state => CheckPerfCounter(counter), null, 0, 100)) + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => bus.Defer(TimeSpan.FromSeconds(5), new MyMessage()))) + .Done(c => c.WasCalled) + .Repeat(r => r.For(Transports.Default)) + .Should(c => Assert.True(c.WasCalled, "The message handler should be called")) + .Run(); + } + Assert.Greater(counterValue, 0, "Critical time has not been recorded"); + Assert.Less(counterValue, 2); + } + + void CheckPerfCounter(PerformanceCounter counter) + { + float rawValue = counter.RawValue; + if (rawValue > 0) + { + counterValue = rawValue; + } + } + + public class Context : ScenarioContext + { + public bool WasCalled { get; set; } + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(builder => builder.EnableCriticalTimePerformanceCounter()) + .AddMapping(typeof(Endpoint)); + } + } + + public class MyMessage : IMessage + { + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyMessage message) + { + Context.WasCalled = true; + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs similarity index 94% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs index 30f0aec6b..2031cbe87 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/CriticalTime/When_slow_with_CriticalTime_enabled.cs @@ -15,7 +15,7 @@ public class When_slow_with_CriticalTime_enabled : NServiceBusAcceptanceTest [Explicit("Since perf counters need to be enabled with powershell")] public void Should_have_perf_counter_set() { - using (var counter = new PerformanceCounter("NServiceBus", "Critical Time", "PerformanceMonitoring.Endpoint.WhenSendingSlowWithCriticalTimeEnabled." + Transports.Default.Key, true)) + using (var counter = new PerformanceCounter("NServiceBus", "Critical Time", "SlowWithCriticaltimeEnabled.Endpoint", true)) using (new Timer(state => CheckPerfCounter(counter), null, 0, 100)) { var context = new Context(); diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/SLA/When_sending_slow_with_SLA_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/SLA/When_sending_slow_with_SLA_enabled.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/SLA/When_sending_slow_with_SLA_enabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/SLA/When_sending_slow_with_SLA_enabled.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/SLA/When_sending_with_SLA_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/SLA/When_sending_with_SLA_enabled.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PerfMon/SLA/When_sending_with_SLA_enabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PerfMon/SLA/When_sending_with_SLA_enabled.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/FilteringWhatGetsAudited.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/FilteringWhatGetsAudited.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/FilteringWhatGetsAudited.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/FilteringWhatGetsAudited.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/MutingHandlerExceptions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/MutingHandlerExceptions.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/MutingHandlerExceptions.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/MutingHandlerExceptions.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/SkipDeserialization.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/SkipDeserialization.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PipelineExt/SkipDeserialization.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PipelineExt/SkipDeserialization.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/SubscriptionBehavior.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/SubscriptionBehavior.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/SubscriptionBehavior.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/SubscriptionBehavior.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/SubscriptionEventArgs.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/SubscriptionEventArgs.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/SubscriptionEventArgs.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/SubscriptionEventArgs.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_base_event_from_2_publishers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_base_event_from_2_publishers.cs similarity index 96% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_base_event_from_2_publishers.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_base_event_from_2_publishers.cs index c24fe7b29..8acefcb00 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_base_event_from_2_publishers.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_base_event_from_2_publishers.cs @@ -3,7 +3,6 @@ using System; using EndpointTemplates; using AcceptanceTesting; - using Features; using NUnit.Framework; public class When_base_event_from_2_publishers : NServiceBusAcceptanceTest @@ -22,6 +21,9 @@ public void Should_receive_events_from_all_publishers() ) .WithEndpoint(b => b.Given((bus, context) => { + bus.Subscribe(); + bus.Subscribe(); + if (context.HasNativePubSubSupport) { context.SubscribedToPublisher1 = true; @@ -79,7 +81,7 @@ public class Subscriber1 : EndpointConfigurationBuilder { public Subscriber1() { - EndpointSetup(c => c.EnableFeature()) + EndpointSetup() .AddMapping(typeof(Publisher1)) .AddMapping(typeof(Publisher2)); } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_multi_subscribing_to_a_polymorphic_event.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_multi_subscribing_to_a_polymorphic_event.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_multi_subscribing_to_a_polymorphic_event.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_multi_subscribing_to_a_polymorphic_event.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishin.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishin.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishin.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishin.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_an_event_implementing_two_unrelated_interfaces.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_an_event_implementing_two_unrelated_interfaces.cs new file mode 100644 index 000000000..026ae55a9 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_an_event_implementing_two_unrelated_interfaces.cs @@ -0,0 +1,142 @@ +namespace NServiceBus.AcceptanceTests.PubSub +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using Features; + using NUnit.Framework; + using ScenarioDescriptors; + + public class When_publishing_an_event_implementing_two_unrelated_interfaces : NServiceBusAcceptanceTest + { + [Test] + public void Event_should_be_published_using_instance_type() + { + Scenario.Define(() => new Context { Id = Guid.NewGuid() }) + .WithEndpoint(b => + b.When(c => c.EventASubscribed && c.EventBSubscribed, (bus, ctx) => + { + var message = new CompositeEvent + { + ContextId = ctx.Id + }; + bus.Publish(message); + })) + .WithEndpoint(b => b.Given((bus, context) => + { + bus.Subscribe(); + bus.Subscribe(); + + if (context.HasNativePubSubSupport) + { + context.EventASubscribed = true; + context.EventBSubscribed = true; + } + })) + .Done(c => c.GotEventA && c.GotEventB) + .Repeat(r => r.For(Serializers.Xml)) + .Should(c => + { + Assert.True(c.GotEventA); + Assert.True(c.GotEventB); + }) + .Run(TimeSpan.FromSeconds(20)); + } + + public class Context : ScenarioContext + { + public Guid Id { get; set; } + public bool EventASubscribed { get; set; } + public bool EventBSubscribed { get; set; } + public bool GotEventA { get; set; } + public bool GotEventB { get; set; } + } + + public class Publisher : EndpointConfigurationBuilder + { + public Publisher() + { + EndpointSetup(b => b.OnEndpointSubscribed((s, context) => + { + if (s.SubscriberReturnAddress.Queue.Contains("Subscriber")) + { + if (s.MessageType == typeof(IEventA).AssemblyQualifiedName) + { + context.EventASubscribed = true; + } + if (s.MessageType == typeof(IEventB).AssemblyQualifiedName) + { + context.EventBSubscribed = true; + } + } + })); + } + } + + public class Subscriber : EndpointConfigurationBuilder + { + public Subscriber() + { + EndpointSetup(c => + { + c.Conventions().DefiningMessagesAs(t => t != typeof(CompositeEvent) && typeof(IMessage).IsAssignableFrom(t) && + typeof(IMessage) != t && + typeof(IEvent) != t && + typeof(ICommand) != t); + + c.Conventions().DefiningEventsAs(t => t != typeof(CompositeEvent) && typeof(IEvent).IsAssignableFrom(t) && typeof(IEvent) != t); + c.DisableFeature(); + }) + .AddMapping(typeof(Publisher)) + .AddMapping(typeof(Publisher)); + } + + public class EventAHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(IEventA evnt) + { + if (evnt.ContextId != Context.Id) + { + return; + } + Context.GotEventA = true; + } + } + + public class EventBHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(IEventB evnt) + { + if (evnt.ContextId != Context.Id) + { + return; + } + Context.GotEventB = true; + } + } + } + + class CompositeEvent : IEventA, IEventB + { + public Guid ContextId { get; set; } + public int IntProperty { get; set; } + public string StringProperty { get; set; } + } + + public interface IEventA : IEvent + { + Guid ContextId { get; set; } + string StringProperty { get; set; } + } + + public interface IEventB : IEvent + { + Guid ContextId { get; set; } + int IntProperty { get; set; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_from_sendonly.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_from_sendonly.cs new file mode 100644 index 000000000..0add91ec3 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_from_sendonly.cs @@ -0,0 +1,110 @@ +namespace NServiceBus.AcceptanceTests.PubSub +{ + using System; + using System.Collections.Generic; + using EndpointTemplates; + using AcceptanceTesting; + using Features; + using NServiceBus.AcceptanceTests.ScenarioDescriptors; + using NServiceBus.Persistence; + using NServiceBus.Unicast.Subscriptions; + using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; + using NUnit.Framework; + + public class When_publishing_from_sendonly : NServiceBusAcceptanceTest + { + [Test] + public void Should_be_delivered_to_all_subscribers() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => bus.Publish(new MyEvent()))) + .WithEndpoint() + .Done(c => c.SubscriberGotTheEvent) + .Repeat(r => r.For()) + .Should(ctx => Assert.True(ctx.SubscriberGotTheEvent)) + .Run(); + } + + public class Context : ScenarioContext + { + public bool SubscriberGotTheEvent { get; set; } + } + + public class SendOnlyPublisher : EndpointConfigurationBuilder + { + public SendOnlyPublisher() + { + EndpointSetup(b => + { + b.UsePersistence(typeof(HardCodedPersistence)); + b.DisableFeature(); + }).SendOnly(); + } + } + + public class Subscriber : EndpointConfigurationBuilder + { + public Subscriber() + { + EndpointSetup(c => c.DisableFeature()) + .AddMapping(typeof(SendOnlyPublisher)); + } + + public class MyEventHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyEvent messageThatIsEnlisted) + { + Context.SubscriberGotTheEvent = true; + } + } + } + + [Serializable] + public class MyEvent : IEvent + { + } + + public class HardCodedPersistence : PersistenceDefinition + { + internal HardCodedPersistence() + { + Supports(s => s.EnableFeatureByDefault()); + } + } + + public class HardCodedPersistenceFeature:Feature + { + protected override void Setup(FeatureConfigurationContext context) + { + context.Container.ConfigureComponent(DependencyLifecycle.SingleInstance); + } + } + + public class HardCodedPersistenceImpl : ISubscriptionStorage + { + public void Subscribe(Address client, IEnumerable messageTypes) + { + } + + public void Unsubscribe(Address client, IEnumerable messageTypes) + { + } + + public IEnumerable
GetSubscriberAddressesForMessage(IEnumerable messageTypes) + { + return new[] + { + Address.Parse("publishingfromsendonly.subscriber") + }; + } + + public void Init() + { + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_on_brokers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_on_brokers.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_on_brokers.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_on_brokers.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_using_root_type.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_using_root_type.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_using_root_type.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_using_root_type.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_with_only_local_messagehandlers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_with_only_local_messagehandlers.cs similarity index 82% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_with_only_local_messagehandlers.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_with_only_local_messagehandlers.cs index fef1bc00f..b9aaea671 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_with_only_local_messagehandlers.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_with_only_local_messagehandlers.cs @@ -24,11 +24,15 @@ public void Should_trigger_the_catch_all_handler_for_message_driven_subscription public void Should_trigger_the_catch_all_handler_for_publishers_with_centralized_pubsub() { Scenario.Define() - .WithEndpoint(b => b.When(c => c.EndpointsStarted, (bus, context) => bus.Publish(new EventHandledByLocalEndpoint()))) - .Done(c => c.CatchAllHandlerGotTheMessage) - .Repeat(r => r.For()) - .Should(c => Assert.True(c.CatchAllHandlerGotTheMessage)) - .Run(); + .WithEndpoint(b => + { + b.Given(bus => bus.Subscribe()); + b.When(c => c.EndpointsStarted, (bus, context) => bus.Publish(new EventHandledByLocalEndpoint())); + }) + .Done(c => c.CatchAllHandlerGotTheMessage) + .Repeat(r => r.For()) + .Should(c => Assert.True(c.CatchAllHandlerGotTheMessage)) + .Run(); } public class Context : ScenarioContext @@ -70,7 +74,7 @@ public class CentralizedStoragePublisher : EndpointConfigurationBuilder { public CentralizedStoragePublisher() { - EndpointSetup(builder => builder.AutoSubscribe().DoNotRequireExplicitRouting()); + EndpointSetup(); } class CatchAllHandler : IHandleMessages diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_with_overridden_local_address.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_with_overridden_local_address.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_publishing_with_overridden_local_address.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_publishing_with_overridden_local_address.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_subscribing_to_a_polymorphic_event.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_subscribing_to_a_polymorphic_event.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/PubSub/When_subscribing_to_a_polymorphic_event.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/PubSub/When_subscribing_to_a_polymorphic_event.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_Subscribing_to_errors.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_Subscribing_to_errors.cs new file mode 100644 index 000000000..4f4bf613c --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_Subscribing_to_errors.cs @@ -0,0 +1,140 @@ +namespace NServiceBus.AcceptanceTests.Retries +{ + using System; + using System.Collections.Generic; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Config; + using NUnit.Framework; + + public class When_Subscribing_to_errors : NServiceBusAcceptanceTest + { + [Test] + public void Should_contain_exception_details() + { + var context = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => bus.SendLocal(new MessageToBeRetried + { + Id = c.Id + }))) + .AllowExceptions(e => e.Message.Contains("Simulated exception")) + .Done(c => c.MessageSentToError) + .Run(TimeSpan.FromMinutes(5)); + + Assert.IsInstanceOf(context.MessageSentToErrorException); + } + + [Test] + public void Should_receive_notifications() + { + var context = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(context) + .WithEndpoint() + .AllowExceptions(e => e.Message.Contains("Simulated exception")) + .Done(c => c.MessageSentToError) + .Run(TimeSpan.FromMinutes(5)); + + Assert.AreEqual(3*3, context.TotalNumberOfFLRTimesInvokedInHandler); + Assert.AreEqual(3*3, context.TotalNumberOfFLRTimesInvoked); + Assert.AreEqual(2, context.NumberOfSLRRetriesPerformed); + } + + public class Context : ScenarioContext + { + public Guid Id { get; set; } + public int TotalNumberOfFLRTimesInvoked { get; set; } + public int TotalNumberOfFLRTimesInvokedInHandler { get; set; } + public int NumberOfSLRRetriesPerformed { get; set; } + public bool MessageSentToError { get; set; } + public Exception MessageSentToErrorException { get; set; } + } + + public class SLREndpoint : EndpointConfigurationBuilder + { + public SLREndpoint() + { + EndpointSetup() + .WithConfig(c => { c.MaxRetries = 3; }) + .WithConfig(c => + { + c.NumberOfRetries = 2; + c.TimeIncrease = TimeSpan.FromSeconds(1); + }); + } + + + class MessageToBeRetriedHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MessageToBeRetried message) + { + if (message.Id != Context.Id) + { + return; // ignore messages from previous test runs + } + + Context.TotalNumberOfFLRTimesInvokedInHandler++; + + throw new MySpecialException(); + } + } + } + + public class MySpecialException : Exception + { + public MySpecialException() + : base("Simulated exception") + { + } + } + + [Serializable] + public class MessageToBeRetried : IMessage + { + public Guid Id { get; set; } + } + + public class MyErrorSubscriber : IWantToRunWhenBusStartsAndStops + { + public Context Context { get; set; } + + public BusNotifications Notifications { get; set; } + + public IBus Bus { get; set; } + + public void Start() + { + unsubscribeStreams.Add(Notifications.Errors.MessageSentToErrorQueue.Subscribe(message => + { + Context.MessageSentToErrorException = message.Exception; + Context.MessageSentToError = true; + })); + unsubscribeStreams.Add(Notifications.Errors.MessageHasFailedAFirstLevelRetryAttempt.Subscribe(message => Context.TotalNumberOfFLRTimesInvoked++)); + unsubscribeStreams.Add(Notifications.Errors.MessageHasBeenSentToSecondLevelRetries.Subscribe(message => Context.NumberOfSLRRetriesPerformed++)); + + Bus.SendLocal(new MessageToBeRetried + { + Id = Context.Id + }); + } + + public void Stop() + { + foreach (var unsubscribeStream in unsubscribeStreams) + { + unsubscribeStream.Dispose(); + } + } + + List unsubscribeStreams = new List(); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_default_settings.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_default_settings.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_default_settings.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_default_settings.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_dtc_on.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_dtc_on.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_dtc_on.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_dtc_on.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_native_transactions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_native_transactions.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_doing_flr_with_native_transactions.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_doing_flr_with_native_transactions.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_fails_flr.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_fails_flr.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_fails_flr.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_fails_flr.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_fails_with_retries_set_to_0.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_fails_with_retries_set_to_0.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_fails_with_retries_set_to_0.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_fails_with_retries_set_to_0.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_sending_to_slr.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_sending_to_slr.cs similarity index 73% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_sending_to_slr.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_sending_to_slr.cs index 668f68d85..861721e64 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Retries/When_sending_to_slr.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Retries/When_sending_to_slr.cs @@ -7,6 +7,8 @@ using AcceptanceTesting; using MessageMutator; using NServiceBus.Config; + using NServiceBus.Unicast; + using NServiceBus.Unicast.Transport; using NUnit.Framework; using Unicast.Messages; @@ -26,6 +28,22 @@ public void Should_preserve_the_original_body_for_regular_exceptions() Assert.AreEqual(context.OriginalBodyChecksum, context.SlrChecksum, "The body of the message sent to slr should be the same as the original message coming off the queue"); } + + [Test] + public void Should_raise_FinishedMessageProcessing_event() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeRetried()))) + .AllowExceptions() + .Done(c => c.FinishedMessageProcessingCalledAfterFaultManagerInvoked) + .Run(); + + Assert.IsTrue(context.FinishedMessageProcessingCalledAfterFaultManagerInvoked); + + } + [Test] public void Should_preserve_the_original_body_for_serialization_exceptions() { @@ -46,6 +64,9 @@ public void Should_preserve_the_original_body_for_serialization_exceptions() public class Context : ScenarioContext { + public bool FinishedMessageProcessingCalledAfterFaultManagerInvoked { get; set; } + public bool FaultManagerInvoked { get; set; } + public byte OriginalBodyChecksum { get; set; } public byte SlrChecksum { get; set; } @@ -65,6 +86,33 @@ public RetryEndpoint() }); } + class FinishedProcessingListener : IWantToRunWhenBusStartsAndStops + { + readonly Context context; + + public FinishedProcessingListener(UnicastBus bus, Context context) + { + this.context = context; + bus.Transport.FinishedMessageProcessing += Transport_FinishedMessageProcessing; + } + + void Transport_FinishedMessageProcessing(object sender, FinishedMessageProcessingEventArgs e) + { + if (context.FaultManagerInvoked) + { + context.FinishedMessageProcessingCalledAfterFaultManagerInvoked = true; + } + } + + public void Start() + { + } + + public void Stop() + { + } + } + class BodyMutator : IMutateTransportMessages, INeedInitialization { public Context Context { get; set; } @@ -107,11 +155,13 @@ class CustomFaultManager : IManageMessageFailures public void SerializationFailedForMessage(TransportMessage message, Exception e) { + Context.FaultManagerInvoked = true; Context.SlrChecksum = Checksum(message.Body); } public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) { + Context.FaultManagerInvoked = true; Context.SlrChecksum = Checksum(message.Body); } @@ -141,4 +191,4 @@ public class MessageToBeRetried : IMessage { } } -} \ No newline at end of file +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/Issue_1819.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/Issue_1819.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/Issue_1819.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/Issue_1819.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/Issue_2044.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/Issue_2044.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/Issue_2044.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/Issue_2044.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_base_class_message_hits_a_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_base_class_message_hits_a_saga.cs new file mode 100644 index 000000000..8e59d9d01 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_base_class_message_hits_a_saga.cs @@ -0,0 +1,90 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Saga; + using NUnit.Framework; + + [TestFixture] + public class When_a_base_class_message_hits_a_saga + { + [Test] + public void Should_find_existing_instance() + { + var correlationId = Guid.NewGuid(); + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => + { + bus.SendLocal(new StartSagaMessage + { + SomeId = correlationId + }); + bus.SendLocal(new StartSagaMessage + { + SomeId = correlationId + }); + })) + .Done(c => c.SecondMessageFoundExistingSaga) + .Run(TimeSpan.FromSeconds(20)); + + Assert.True(context.SecondMessageFoundExistingSaga); + } + + public class Context : ScenarioContext + { + public bool SecondMessageFoundExistingSaga { get; set; } + } + + public class SagaEndpoint : EndpointConfigurationBuilder + { + public SagaEndpoint() + { + EndpointSetup(); + } + + + + public class TestSaga : Saga, IAmStartedByMessages + { + public Context Context { get; set; } + + public void Handle(StartSagaMessageBase message) + { + if (Data.SomeId != Guid.Empty) + { + Context.SecondMessageFoundExistingSaga = true; + } + else + { + Data.SomeId = message.SomeId; + } + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + mapper.ConfigureMapping(m => m.SomeId) + .ToSaga(s => s.SomeId); + } + + public class SagaData : ContainSagaData + { + [Unique] + public Guid SomeId { get; set; } + } + } + + } + + + public class StartSagaMessage : StartSagaMessageBase + { + } + public class StartSagaMessageBase : IMessage + { + public Guid SomeId { get; set; } + } + + + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_a_existing_saga_instance_exists.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_existing_saga_instance_exists.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_a_existing_saga_instance_exists.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_existing_saga_instance_exists.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_finder_exists.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_finder_exists.cs new file mode 100644 index 000000000..564ffe1ad --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_finder_exists.cs @@ -0,0 +1,67 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Saga; + using NUnit.Framework; + + [TestFixture] + public class When_a_finder_exists + { + [Test] + public void Should_use_it_to_find_saga() + { + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new StartSagaMessage()))) + .Done(c => c.FinderUsed) + .Run(); + + Assert.True(context.FinderUsed); + } + + public class Context : ScenarioContext + { + public bool FinderUsed { get; set; } + } + + public class SagaEndpoint : EndpointConfigurationBuilder + { + public SagaEndpoint() + { + EndpointSetup(); + } + + class CustomFinder : IFindSagas.Using + { + public Context Context { get; set; } + public TestSaga.SagaData FindBy(StartSagaMessage message) + { + Context.FinderUsed = true; + return null; + } + } + + public class TestSaga : Saga, IAmStartedByMessages + { + public Context Context { get; set; } + + public void Handle(StartSagaMessage message) + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + + public class SagaData : ContainSagaData + { + } + } + + } + + public class StartSagaMessage : IMessage + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_a_saga_message_goes_through_the_slr.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_saga_message_goes_through_the_slr.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_a_saga_message_goes_through_the_slr.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_a_saga_message_goes_through_the_slr.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_an_endpoint_replies_to_a_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_an_endpoint_replies_to_a_saga.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_an_endpoint_replies_to_a_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_an_endpoint_replies_to_a_saga.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_doing_request_response_between_sagas.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_doing_request_response_between_sagas.cs similarity index 86% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_doing_request_response_between_sagas.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_doing_request_response_between_sagas.cs index ccdec6832..1f7db5cee 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_doing_request_response_between_sagas.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_doing_request_response_between_sagas.cs @@ -79,11 +79,11 @@ public class RequestingSaga : Saga, public void Handle(InitiateRequestingSaga message) { - Data.CorrelationIdSoThatResponseCanFindTheCorrectInstance = Guid.NewGuid(); //wont be needed in the future + Data.CorrIdForResponse = Guid.NewGuid(); //wont be needed in the future Bus.SendLocal(new RequestToRespondingSaga { - SomeIdThatTheResponseSagaCanCorrelateBackToUs = Data.CorrelationIdSoThatResponseCanFindTheCorrectInstance //wont be needed in the future + SomeIdThatTheResponseSagaCanCorrelateBackToUs = Data.CorrIdForResponse //wont be needed in the future }); } @@ -97,11 +97,12 @@ protected override void ConfigureHowToFindSaga(SagaPropertyMapper(m => m.SomeCorrelationId).ToSaga(s => s.CorrelationIdSoThatResponseCanFindTheCorrectInstance); + mapper.ConfigureMapping(m => m.SomeCorrelationId).ToSaga(s => s.CorrIdForResponse); } public class RequestingSagaData : ContainSagaData { - public virtual Guid CorrelationIdSoThatResponseCanFindTheCorrectInstance { get; set; } //wont be needed in the future + [Unique] + public virtual Guid CorrIdForResponse { get; set; } //wont be needed in the future } } @@ -117,14 +118,14 @@ public void Handle(RequestToRespondingSaga message) { if (Context.ReplyFromNonInitiatingHandler) { - Data.CorrelationIdFromRequestingSaga = message.SomeIdThatTheResponseSagaCanCorrelateBackToUs; //wont be needed in the future - Bus.SendLocal(new SendReplyFromNonInitiatingHandler{SagaIdSoWeCanCorrelate = Data.Id}); + Data.CorrIdForRequest = message.SomeIdThatTheResponseSagaCanCorrelateBackToUs; //wont be needed in the future + Bus.SendLocal(new SendReplyFromNonInitiatingHandler { SagaIdSoWeCanCorrelate = Data.Id }); return; } if (Context.ReplyFromTimeout) { - Data.CorrelationIdFromRequestingSaga = message.SomeIdThatTheResponseSagaCanCorrelateBackToUs; //wont be needed in the future + Data.CorrIdForRequest = message.SomeIdThatTheResponseSagaCanCorrelateBackToUs; //wont be needed in the future RequestTimeout(TimeSpan.FromSeconds(1)); return; } @@ -138,12 +139,13 @@ public void Handle(RequestToRespondingSaga message) protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) { //this line is just needed so we can test the non initiating handler case - mapper.ConfigureMapping(m=>m.SagaIdSoWeCanCorrelate).ToSaga(s=>s.Id); + mapper.ConfigureMapping(m => m.SagaIdSoWeCanCorrelate).ToSaga(s => s.Id); } public class RespondingSagaData : ContainSagaData { - public virtual Guid CorrelationIdFromRequestingSaga { get; set; } + [Unique] + public virtual Guid CorrIdForRequest { get; set; } } @@ -164,7 +166,7 @@ void SendReply() //reply to originator must be used here since the sender of the incoming message the timeoutmanager and not the requesting saga ReplyToOriginator(new ResponseFromOtherSaga //change this line to Bus.Reply(new ResponseFromOtherSaga and see it fail { - SomeCorrelationId = Data.CorrelationIdFromRequestingSaga //wont be needed in the future + SomeCorrelationId = Data.CorrIdForRequest //wont be needed in the future }); } } @@ -182,7 +184,8 @@ public class ResponseFromOtherSaga : IMessage public Guid SomeCorrelationId { get; set; } } - public class SendReplyFromNonInitiatingHandler : ICommand { + public class SendReplyFromNonInitiatingHandler : ICommand + { public Guid SagaIdSoWeCanCorrelate { get; set; } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_message_has_a_saga_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_message_has_a_saga_id.cs new file mode 100644 index 000000000..41ea600e0 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_message_has_a_saga_id.cs @@ -0,0 +1,104 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Saga; + using NUnit.Framework; + + public class When_message_has_a_saga_id : NServiceBusAcceptanceTest + { + [Test] + public void Should_not_start_a_new_saga_if_not_found() + { + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => + { + var message = new MessageWithSagaId(); + + bus.SetMessageHeader(message, Headers.SagaId, Guid.NewGuid().ToString()); + bus.SetMessageHeader(message, Headers.SagaType, typeof(MySaga).AssemblyQualifiedName); + + bus.SendLocal(message); + })) + .Done(c => c.OtherSagaStarted) + .Run(); + + Assert.False(context.NotFoundHandlerCalled); + Assert.True(context.OtherSagaStarted); + Assert.False(context.MessageHandlerCalled); + Assert.False(context.TimeoutHandlerCalled); + } + + class MySaga : Saga, IAmStartedByMessages, + IHandleTimeouts, + IHandleSagaNotFound + { + public Context Context { get; set; } + + public class SagaData : ContainSagaData + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + + } + + public void Handle(MessageWithSagaId message) + { + Context.MessageHandlerCalled = true; + } + + public void Handle(object message) + { + Context.NotFoundHandlerCalled = true; + } + + public void Timeout(MessageWithSagaId state) + { + Context.TimeoutHandlerCalled = true; + } + } + + class MyOtherSaga : Saga, IAmStartedByMessages + { + public Context Context { get; set; } + + public void Handle(MessageWithSagaId message) + { + Context.OtherSagaStarted = true; + } + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + + } + + public class SagaData : ContainSagaData + { + } + + } + + + class Context : ScenarioContext + { + public bool NotFoundHandlerCalled { get; set; } + public bool MessageHandlerCalled { get; set; } + public bool TimeoutHandlerCalled { get; set; } + public bool OtherSagaStarted { get; set; } + } + + public class SagaEndpoint : EndpointConfigurationBuilder + { + public SagaEndpoint() + { + EndpointSetup(); + } + } + + public class MessageWithSagaId : IMessage + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_receiving_that_completes_the_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_receiving_that_completes_the_saga.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_receiving_that_completes_the_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_receiving_that_completes_the_saga.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_receiving_that_should_start_a_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_receiving_that_should_start_a_saga.cs similarity index 88% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_receiving_that_should_start_a_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_receiving_that_should_start_a_saga.cs index e9ac43d02..dcfac9314 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_receiving_that_should_start_a_saga.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_receiving_that_should_start_a_saga.cs @@ -58,7 +58,7 @@ public SagaEndpoint() EndpointSetup(b => b.LoadMessageHandlers>()); } - public class TestSaga : Saga, IAmStartedByMessages + public class TestSaga : Saga, IAmStartedByMessages { public SagaEndpointContext Context { get; set; } public void Handle(StartSagaMessage message) @@ -68,16 +68,17 @@ public void Handle(StartSagaMessage message) protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) { + mapper.ConfigureMapping(m=>m.SomeId) + .ToSaga(s=>s.SomeId); } - } - public class TestSagaData : IContainSagaData - { - public virtual Guid Id { get; set; } - public virtual string Originator { get; set; } - public virtual string OriginalMessageId { get; set; } + public class TestSagaData : ContainSagaData + { + public string SomeId { get; set; } + } } + public class InterceptingHandler : IHandleMessages { public SagaEndpointContext Context { get; set; } @@ -97,6 +98,7 @@ public void Handle(StartSagaMessage message) [Serializable] public class StartSagaMessage : ICommand { + public string SomeId { get; set; } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_replies_to_message_published_by_a_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_replies_to_message_published_by_a_saga.cs similarity index 87% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_replies_to_message_published_by_a_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_replies_to_message_published_by_a_saga.cs index fe6c139e9..7f0412cf8 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_replies_to_message_published_by_a_saga.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_replies_to_message_published_by_a_saga.cs @@ -16,13 +16,13 @@ public class When_replies_to_message_published_by_a_saga : NServiceBusAcceptance public void Should_reply_to_a_message_published_by_a_saga() { Scenario.Define() - .WithEndpoint + .WithEndpoint (b => b.When(c => c.Subscribed, bus => bus.SendLocal(new StartSaga { DataId = Guid.NewGuid() })) ) - .WithEndpoint(b => b.Given((bus, context) => + .WithEndpoint(b => b.Given((bus, context) => { bus.Subscribe(); if (context.HasNativePubSubSupport) @@ -42,12 +42,12 @@ public class Context : ScenarioContext public bool Subscribed { get; set; } } - public class EndpointThatHandlesAMessageFromSagaAndReplies : EndpointConfigurationBuilder + public class ReplyEndpoint : EndpointConfigurationBuilder { - public EndpointThatHandlesAMessageFromSagaAndReplies() + public ReplyEndpoint() { EndpointSetup(b => b.DisableFeature()) - .AddMapping(typeof(EndpointThatHostsASaga)) + .AddMapping(typeof(SagaEndpoint)) .WithConfig(c => { c.MaxRetries = 0; @@ -69,9 +69,9 @@ public void Handle(DidSomething message) } } - public class EndpointThatHostsASaga : EndpointConfigurationBuilder + public class SagaEndpoint : EndpointConfigurationBuilder { - public EndpointThatHostsASaga() + public SagaEndpoint() { EndpointSetup(b => b.OnEndpointSubscribed((s, context) => { diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_reply_from_a_finder.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_reply_from_a_finder.cs new file mode 100644 index 000000000..9232564ca --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_reply_from_a_finder.cs @@ -0,0 +1,102 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Saga; + using NUnit.Framework; + + [TestFixture] + public class When_reply_from_a_finder + { + [Test] + public void Should_be_received_by_handler() + { + var context = new Context + { + Id = Guid.NewGuid() + }; + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new StartSagaMessage + { + Id = context.Id + }))) + .Done(c => c.HandlerFired) + .Run(); + + Assert.True(context.HandlerFired); + } + + public class Context : ScenarioContext + { + public bool HandlerFired { get; set; } + public Guid Id { get; set; } + } + + public class SagaEndpoint : EndpointConfigurationBuilder + { + public SagaEndpoint() + { + EndpointSetup(); + } + + class CustomFinder : IFindSagas.Using + { + public IBus Bus { get; set; } + public Context Context { get; set; } + + public TestSaga.SagaData FindBy(StartSagaMessage message) + { + Bus.Reply(new SagaNotFoundMessage + { + Id = Context.Id + }); + return null; + } + } + + public class TestSaga : Saga, + IAmStartedByMessages + { + public Context Context { get; set; } + + public void Handle(StartSagaMessage message) + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + + public class SagaData : ContainSagaData + { + } + } + + public class Handler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(SagaNotFoundMessage message) + { + if (Context.Id != message.Id) + { + return; + } + Context.HandlerFired = true; + } + } + } + + public class SagaNotFoundMessage : IMessage + { + public Guid Id { get; set; } + } + + public class StartSagaMessage : IMessage + { + public Guid Id { get; set; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_saga_has_a_non_empty_constructor.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_has_a_non_empty_constructor.cs similarity index 93% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_saga_has_a_non_empty_constructor.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_has_a_non_empty_constructor.cs index 27eebb20b..95f2d8ec9 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_saga_has_a_non_empty_constructor.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_has_a_non_empty_constructor.cs @@ -43,13 +43,14 @@ public SagaEndpoint() public class TestSaga : Saga, IAmStartedByMessages, IHandleMessages { + Context context; // ReSharper disable once UnusedParameter.Local - public TestSaga(IBus bus) + public TestSaga(IBus bus,Context context) { - + this.context = context; } - public Context Context { get; set; } + public void Handle(StartSagaMessage message) { Data.SomeId = message.SomeId; @@ -63,7 +64,7 @@ protected override void ConfigureHowToFindSaga(SagaPropertyMapper public void Handle(OtherMessage message) { - Context.SecondMessageReceived = true; + context.SecondMessageReceived = true; } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_id_changed.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_id_changed.cs new file mode 100644 index 000000000..220cf9c72 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_id_changed.cs @@ -0,0 +1,104 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using System.Diagnostics; + using EndpointTemplates; + using AcceptanceTesting; + using NServiceBus.Config; + using NServiceBus.Faults; + using NServiceBus.Features; + using NUnit.Framework; + using Saga; + using ScenarioDescriptors; + + public class When_saga_id_changed : NServiceBusAcceptanceTest + { + [Test] + public void Should_throw() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint( + b => b.Given(bus => bus.SendLocal(new StartSaga + { + DataId = Guid.NewGuid() + }))) + .AllowExceptions() + .Done(c => c.ExceptionReceived) + .Repeat(r => r.For(Transports.Default)) + .Run(); + + Debug.WriteLine(context.ExceptionMessage, "A modification of IContainSagaData.Id has been detected. This property is for infrastructure purposes only and should not be modified. SagaType: " + typeof(Endpoint.MySaga)); + } + + public class Context : ScenarioContext + { + public bool ExceptionReceived { get; set; } + public string ExceptionMessage { get; set; } + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(b => + { + b.RegisterComponents(c => c.ConfigureComponent(DependencyLifecycle.SingleInstance)); + b.DisableFeature(); + }) + .WithConfig(c => + { + c.MaxRetries = 0; + }); + } + + public class MySaga : Saga, + IAmStartedByMessages + { + public Context Context { get; set; } + + public void Handle(StartSaga message) + { + Data.DataId = message.DataId; + Data.Id = Guid.NewGuid(); + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + mapper.ConfigureMapping(m => m.DataId).ToSaga(s => s.DataId); + } + + public class MySagaData : ContainSagaData + { + [Unique] + public virtual Guid DataId { get; set; } + } + + } + class CustomFaultManager : IManageMessageFailures + { + public Context Context { get; set; } + + public void SerializationFailedForMessage(TransportMessage message, Exception e) + { + } + + public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e) + { + Context.ExceptionMessage = e.Message; + Context.ExceptionReceived = true; + } + + public void Init(Address address) + { + } + } + } + + [Serializable] + public class StartSaga : ICommand + { + public Guid DataId { get; set; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_saga_is_mapped_to_complex_expression.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_is_mapped_to_complex_expression.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_saga_is_mapped_to_complex_expression.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_saga_is_mapped_to_complex_expression.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sagas_cant_be_found.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sagas_cant_be_found.cs new file mode 100644 index 000000000..4b613d32a --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sagas_cant_be_found.cs @@ -0,0 +1,221 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using NUnit.Framework; + using Saga; + + public class When_sagas_cant_be_found : NServiceBusAcceptanceTest + { + [Test] + public void IHandleSagaNotFound_only_called_once() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => bus.SendLocal(new MessageToSaga()))) + .Done(c => c.Done) + .Run(); + + Assert.AreEqual(1, context.TimesFired); + } + + [Test] + public void IHandleSagaNotFound_not_called_if_second_saga_is_executed() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given((bus, c) => bus.SendLocal(new MessageToSaga()))) + .Done(c => c.Done) + .Run(); + + Assert.AreEqual(0, context.TimesFired); + } + + public class Context : ScenarioContext + { + public int TimesFired { get; set; } + public bool Done { get; set; } + } + + public class ReceiverWithSagas : EndpointConfigurationBuilder + { + public ReceiverWithSagas() + { + EndpointSetup(); + } + + public class MessageToSagaHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public void Handle(MessageToSaga message) + { + Bus.Defer(TimeSpan.FromSeconds(10), new FinishMessage()); + } + } + + public class FinishHandler: IHandleMessages + { + public Context Context { get; set; } + + public void Handle(FinishMessage message) + { + Context.Done = true; + } + } + + public class Saga1 : Saga, IAmStartedByMessages, IHandleMessages + { + + public void Handle(StartSaga message) + { + } + + public void Handle(MessageToSaga message) + { + } + + public class Saga1Data : ContainSagaData + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + } + + public class Saga2 : Saga, IAmStartedByMessages, IHandleMessages + { + + public void Handle(StartSaga message) + { + } + + public void Handle(MessageToSaga message) + { + } + + public class Saga2Data : ContainSagaData + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + } + + public class SagaNotFound : IHandleSagaNotFound + { + public Context Context { get; set; } + + public void Handle(object message) + { + Context.TimesFired++; + } + } + } + + public class ReceiverWithOrderedSagas : EndpointConfigurationBuilder + { + public ReceiverWithOrderedSagas() + { + EndpointSetup(); + } + + class EnsureOrdering : ISpecifyMessageHandlerOrdering + { + public void SpecifyOrder(Order order) + { + order.Specify(First.Then()); + } + } + + public class MessageToSagaHandler : IHandleMessages + { + public IBus Bus { get; set; } + + public void Handle(MessageToSaga message) + { + Bus.Defer(TimeSpan.FromSeconds(10), new FinishMessage()); + } + } + + public class FinishHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(FinishMessage message) + { + Context.Done = true; + } + } + + public class Saga1 : Saga, IAmStartedByMessages, IHandleMessages + { + + public void Handle(StartSaga message) + { + } + + public void Handle(MessageToSaga message) + { + } + + public class Saga1Data : ContainSagaData + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + } + + public class Saga2 : Saga, IHandleMessages, IAmStartedByMessages + { + + public void Handle(StartSaga message) + { + } + + public void Handle(MessageToSaga message) + { + } + + public class Saga2Data : ContainSagaData + { + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + } + + public class SagaNotFound : IHandleSagaNotFound + { + public Context Context { get; set; } + + public void Handle(object message) + { + Context.TimesFired++; + } + } + } + [Serializable] + public class StartSaga : ICommand + { + } + + [Serializable] + public class FinishMessage : ICommand + { + } + + [Serializable] + public class MessageToSaga : ICommand + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_sending_from_a_saga_handle.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sending_from_a_saga_handle.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_sending_from_a_saga_handle.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sending_from_a_saga_handle.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_sending_from_a_saga_timeout.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sending_from_a_saga_timeout.cs similarity index 99% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_sending_from_a_saga_timeout.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sending_from_a_saga_timeout.cs index 388f2e04f..15182783e 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_sending_from_a_saga_timeout.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_sending_from_a_saga_timeout.cs @@ -91,5 +91,4 @@ public class Saga1Timeout : IMessage { } } - } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_started_by_base_event_from_other_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_started_by_base_event_from_other_saga.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_started_by_base_event_from_other_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_started_by_base_event_from_other_saga.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_started_by_event_from_another_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_started_by_event_from_another_saga.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_started_by_event_from_another_saga.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_started_by_event_from_another_saga.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_timeout_hit_not_found_saga.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_timeout_hit_not_found_saga.cs new file mode 100644 index 000000000..5b19f2a14 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_timeout_hit_not_found_saga.cs @@ -0,0 +1,94 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using NUnit.Framework; + using Saga; + + public class When_timeout_hit_not_found_saga : NServiceBusAcceptanceTest + { + [Test] + public void Should_not_fire_notfound_for_tm() + { + var context = Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new StartSaga()))) + .Done(c => c.NotFoundHandlerCalledForRegularMessage) + .Run(); + + + Assert.False(context.NotFoundHandlerCalledForTimeout); + + } + + public class Context : ScenarioContext + { + public bool NotFoundHandlerCalledForRegularMessage { get; set; } + public bool NotFoundHandlerCalledForTimeout { get; set; } + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(); + } + + public class MySaga : Saga, + IAmStartedByMessages, IHandleSagaNotFound, + IHandleTimeouts, + IHandleMessages + { + public Context Context { get; set; } + + public void Handle(StartSaga message) + { + //this will cause the message to be delivered right away + RequestTimeout(TimeSpan.Zero); + Bus.SendLocal(new SomeOtherMessage()); + + MarkAsComplete(); + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + } + + public class MySagaData : ContainSagaData + { + public virtual Guid DataId { get; set; } + } + + public class MyTimeout { } + + public void Handle(object message) + { + if (message is SomeOtherMessage) + { + Context.NotFoundHandlerCalledForRegularMessage = true; + } + + + if (message is MyTimeout) + { + Context.NotFoundHandlerCalledForTimeout = true; + } + + } + + public void Handle(SomeOtherMessage message) + { + + } + + public void Timeout(MyTimeout state) + { + + } + } + } + + public class StartSaga : IMessage { } + public class SomeOtherMessage : IMessage { } + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_two_sagas_subscribe_to_the_same_event.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_two_sagas_subscribe_to_the_same_event.cs similarity index 89% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_two_sagas_subscribe_to_the_same_event.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_two_sagas_subscribe_to_the_same_event.cs index 53fc87d82..31a666fd3 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_two_sagas_subscribe_to_the_same_event.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_two_sagas_subscribe_to_the_same_event.cs @@ -16,13 +16,13 @@ public class When_two_sagas_subscribe_to_the_same_event : NServiceBusAcceptanceT public void Should_invoke_all_handlers_on_all_sagas() { Scenario.Define() - .WithEndpoint(b => + .WithEndpoint(b => b.When(c => c.Subscribed, bus => bus.SendLocal(new StartSaga2 { DataId = Guid.NewGuid() })) ) - .WithEndpoint(b => b.Given((bus, context) => + .WithEndpoint(b => b.Given((bus, context) => { if (context.HasNativePubSubSupport) { @@ -43,9 +43,9 @@ public class Context : ScenarioContext public bool DidSaga2EventHandlerGetInvoked { get; set; } } - public class EndpointThatHandlesAMessageAndPublishesEvent : EndpointConfigurationBuilder + public class Publisher : EndpointConfigurationBuilder { - public EndpointThatHandlesAMessageAndPublishesEvent() + public Publisher() { EndpointSetup(b => b.OnEndpointSubscribed((s, context) => { @@ -65,13 +65,13 @@ public void Handle(OpenGroupCommand message) } } - public class EndpointThatHostsTwoSagas : EndpointConfigurationBuilder + public class SagaEndpoint : EndpointConfigurationBuilder { - public EndpointThatHostsTwoSagas() + public SagaEndpoint() { EndpointSetup() - .AddMapping(typeof(EndpointThatHandlesAMessageAndPublishesEvent)) - .AddMapping(typeof(EndpointThatHandlesAMessageAndPublishesEvent)); + .AddMapping(typeof(Publisher)) + .AddMapping(typeof(Publisher)); } public class Saga1 : Saga, IAmStartedByMessages, IHandleMessages diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_ReplyToOriginator.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_ReplyToOriginator.cs new file mode 100644 index 000000000..922fe691c --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_ReplyToOriginator.cs @@ -0,0 +1,97 @@ +namespace NServiceBus.AcceptanceTests.Sagas +{ + using System; + using EndpointTemplates; + using AcceptanceTesting; + using NUnit.Framework; + using Saga; + + public class When_using_ReplyToOriginator : NServiceBusAcceptanceTest + { + [Test] + public void Should_set_Reply_as_messageintent() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new InitiateRequestingSaga()))) + .Done(c => c.Done) + .Run(); + + Assert.AreEqual(MessageIntentEnum.Reply, context.Intent); + } + + public class Context : ScenarioContext + { + public MessageIntentEnum Intent { get; set; } + public bool Done { get; set; } + } + + public class Endpoint : EndpointConfigurationBuilder + { + + public Endpoint() + { + EndpointSetup(); + } + + public class RequestingSaga : Saga, + IAmStartedByMessages, + IHandleMessages + { + public Context Context { get; set; } + + public void Handle(InitiateRequestingSaga message) + { + Data.CorrIdForResponse = Guid.NewGuid(); //wont be needed in the future + + Bus.SendLocal(new AnotherRequest + { + SomeCorrelationId = Data.CorrIdForResponse //wont be needed in the future + }); + } + + public void Handle(AnotherRequest message) + { + ReplyToOriginator(new MyReplyToOriginator()); + MarkAsComplete(); + } + + protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) + { + //if this line is un-commented the timeout and secondary handler tests will start to fail + // for more info and discussion see TBD + mapper.ConfigureMapping(m => m.SomeCorrelationId).ToSaga(s => s.CorrIdForResponse); + } + public class RequestingSagaData : ContainSagaData + { + public virtual Guid CorrIdForResponse { get; set; } //wont be needed in the future + } + } + + class MyReplyToOriginatorHandler : IHandleMessages + { + public Context Context { get; set; } + public IBus Bus { get; set; } + + public void Handle(MyReplyToOriginator message) + { + Context.Intent = (MessageIntentEnum)Enum.Parse(typeof(MessageIntentEnum), Bus.CurrentMessageContext.Headers[Headers.MessageIntent]); + Context.Done = true; + } + } + } + + public class InitiateRequestingSaga : ICommand { } + + public class AnotherRequest : ICommand + { + public Guid SomeCorrelationId { get; set; } + } + + public class MyReplyToOriginator : IMessage + { + public Guid SomeCorrelationId { get; set; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_using_a_received_message_for_timeout.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_a_received_message_for_timeout.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_using_a_received_message_for_timeout.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_a_received_message_for_timeout.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_using_contain_saga_data.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_contain_saga_data.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Sagas/When_using_contain_saga_data.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Sagas/When_using_contain_saga_data.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled.cs new file mode 100644 index 000000000..b60c817d8 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled.cs @@ -0,0 +1,54 @@ +namespace NServiceBus.AcceptanceTests.ScaleOut +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_individualization_is_enabled : NServiceBusAcceptanceTest + { + const string discriminator = "-something"; + + + [Test][Ignore("SQL Server transport does not support scaling out with individualized queues.")] + public void Should_use_the_configured_differentiator() + { + var context = Scenario.Define() + .WithEndpoint().Done(c =>c.EndpointsStarted) + .Run(); + + + Assert.True(context.Address.Contains("-something"),context.Address + " should contain the discriminator " + discriminator); + + } + + public class Context : ScenarioContext + { + public string Address { get; set; } + } + + public class IndividualizedEndpoint : EndpointConfigurationBuilder + { + + public IndividualizedEndpoint() + { + EndpointSetup(c=>c.ScaleOut().UniqueQueuePerEndpointInstance(discriminator)); + } + + class AddressSpy : IWantToRunWhenBusStartsAndStops + { + public Context Context { get; set; } + + public Configure Configure { get; set; } + + public void Start() + { + Context.Address = Configure.LocalAddress.ToString(); + } + + public void Stop() + { + } + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled_for_msmq.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled_for_msmq.cs new file mode 100644 index 000000000..4dab94258 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_individualization_is_enabled_for_msmq.cs @@ -0,0 +1,56 @@ +namespace NServiceBus.AcceptanceTests.ScaleOut +{ + using System.Linq; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.AcceptanceTests.ScenarioDescriptors; + using NServiceBus.Settings; + using NUnit.Framework; + + public class When_individualization_is_enabled_for_msmq : NServiceBusAcceptanceTest + { + [Test] + public void Should_be_a_no_op_discriminator() + { + Scenario.Define() + .WithEndpoint().Done(c =>c.EndpointsStarted) + .Repeat(r => r.For()) + .Should(c=>Assert.AreEqual(c.EndpointName,c.Address.Split('@').First())) + .Run(); + } + + public class Context : ScenarioContext + { + public string Address { get; set; } + public string EndpointName { get; set; } + } + + public class IndividualizedEndpoint : EndpointConfigurationBuilder + { + + public IndividualizedEndpoint() + { + EndpointSetup(c=>c.ScaleOut().UniqueQueuePerEndpointInstance()); + } + + class AddressSpy : IWantToRunWhenBusStartsAndStops + { + public Context Context { get; set; } + + public Configure Configure { get; set; } + + public ReadOnlySettings ReadOnlySettings { get; set; } + + public void Start() + { + Context.Address = Configure.LocalAddress.ToString(); + Context.EndpointName = ReadOnlySettings.EndpointName(); + } + + public void Stop() + { + } + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_no_discriminator_is_available.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_no_discriminator_is_available.cs new file mode 100644 index 000000000..d07ae69fb --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScaleOut/When_no_discriminator_is_available.cs @@ -0,0 +1,68 @@ +namespace NServiceBus.AcceptanceTests.ScaleOut +{ + using System; + using System.Linq; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Features; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_no_discriminator_is_available : NServiceBusAcceptanceTest + { + [Test] + public void Should_blow_up() + { + var ex = Assert.Throws(()=> Scenario.Define() + .WithEndpoint().Done(c =>c.EndpointsStarted) + .AllowExceptions() + .Run()); + + var configEx = ex.InnerExceptions.First() + .InnerException; + + Assert.True(configEx.Message.StartsWith("No endpoint instance discriminator found")); + + } + + public class Context : ScenarioContext + { + } + + public class IndividualizedEndpoint : EndpointConfigurationBuilder + { + + public IndividualizedEndpoint() + { + EndpointSetup(c => + { + c.ScaleOut().UniqueQueuePerEndpointInstance(); + c.UseTransport(); + }); + } + } + + public class TransportThatDoesntSetADefaultDiscriminator:TransportDefinition + { + protected override void Configure(BusConfiguration config) + { + config.EnableFeature(); + } + } + + public class TransportThatDoesntSetADefaultDiscriminatorConfigurator : ConfigureTransport + { + protected override void Configure(FeatureConfigurationContext context, string connectionString) + { + + } + + protected override string ExampleConnectionStringForErrorMessage + { + get { return ""; } + } + } + } + + +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllOutboxCapableStorages.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllOutboxCapableStorages.cs similarity index 90% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllOutboxCapableStorages.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllOutboxCapableStorages.cs index d54ab1ce7..222b7a50e 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllOutboxCapableStorages.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllOutboxCapableStorages.cs @@ -13,8 +13,7 @@ public AllOutboxCapableStorages() var definitionType = Type.GetType(defaultStorage.Settings["Persistence"]); var definition = (PersistenceDefinition)Activator.CreateInstance(definitionType, true); - - if (definition.HasSupportFor(Storage.Outbox)) + if (definition.HasSupportFor()) { Add(defaultStorage); } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllTransactionSettings.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllTransactionSettings.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllTransactionSettings.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllTransactionSettings.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllTransports.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllTransports.cs similarity index 93% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllTransports.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllTransports.cs index 8cdf38c17..53b1daebf 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/AllTransports.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/AllTransports.cs @@ -68,6 +68,17 @@ public AllTransportsWithMessageDrivenPubSub() } } + public class MsmqOnly : ScenarioDescriptor + { + public MsmqOnly() + { + if (Transports.Default == Transports.Msmq) + { + Add(Transports.Msmq); + } + } + } + public class TypeScanner { diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Builders.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Builders.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Builders.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Builders.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Persistence.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Persistence.cs similarity index 66% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Persistence.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Persistence.cs index af0d6cd9a..4eef9fbce 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Persistence.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Persistence.cs @@ -15,14 +15,18 @@ public static RunDescriptor Default var specificPersistence = Environment.GetEnvironmentVariable("Persistence.UseSpecific"); if (!string.IsNullOrEmpty(specificPersistence)) + { return AllAvailable.Single(r => r.Key == specificPersistence); + } - var nonCorePersisters = AllAvailable.Where(t => t != InMemory && t.Key != "MsmqPersistence").ToList(); + var nonCorePersister = AllAvailable.FirstOrDefault(); - if (nonCorePersisters.Count() == 1) - return nonCorePersisters.First(); + if (nonCorePersister != null) + { + return nonCorePersister; + } - return InMemory; + return InMemoryPersistenceDescriptor; } } @@ -39,16 +43,24 @@ static IEnumerable AllAvailable } } - static RunDescriptor InMemory + static Type InMemoryPersistenceType = typeof(InMemoryPersistence); + + static RunDescriptor InMemoryPersistenceDescriptor = new RunDescriptor { - get { return AllAvailable.SingleOrDefault(r => r.Key == "InMemoryPersistence"); } - } + Key = InMemoryPersistenceType.Name, + Settings = + new Dictionary + { + {"Persistence", InMemoryPersistenceType.AssemblyQualifiedName} + } + }; static IEnumerable GetAllAvailable() { - var foundDefinitions = TypeScanner.GetAllTypesAssignableTo(); + var foundDefinitions = TypeScanner.GetAllTypesAssignableTo() + .Where(t => t.Assembly != InMemoryPersistenceType.Assembly && + t.Assembly != typeof(Persistence).Assembly); - foreach (var definition in foundDefinitions) { var key = definition.Name; diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Serializers.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Serializers.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Serializers.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Serializers.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/TransactionSettings.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/TransactionSettings.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/TransactionSettings.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/TransactionSettings.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Transports.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Transports.cs similarity index 92% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Transports.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Transports.cs index a82aeeec3..5040676e0 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/ScenarioDescriptors/Transports.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/ScenarioDescriptors/Transports.cs @@ -19,6 +19,7 @@ internal static IEnumerable AllAvailable availableTransports = GetAllAvailable().ToList(); } } + return availableTransports; } } @@ -33,7 +34,7 @@ public static RunDescriptor Default if (!string.IsNullOrEmpty(specificTransport)) return AllAvailable.Single(r => r.Key == specificTransport); - var transportsOtherThanMsmq = AllAvailable.Where(t => t != Msmq).ToList(); + var transportsOtherThanMsmq = AllAvailable.Where(t => t != Msmq); if (transportsOtherThanMsmq.Count() == 1) return transportsOtherThanMsmq.First(); @@ -42,7 +43,7 @@ public static RunDescriptor Default } } - static RunDescriptor Msmq + public static RunDescriptor Msmq { get { return AllAvailable.SingleOrDefault(r => r.Key == "MsmqTransport"); } } @@ -77,10 +78,6 @@ static IEnumerable GetAllAvailable() runDescriptor.Settings.Add("Transport.ConnectionString", connectionString); yield return runDescriptor; } - else - { - Console.Out.WriteLine("No connection string found for transport: {0}, test will not be executed for this transport", key); - } } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Scheduling/When_scheduling_a_recurring_task.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Scheduling/When_scheduling_a_recurring_task.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Scheduling/When_scheduling_a_recurring_task.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Scheduling/When_scheduling_a_recurring_task.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/FakePromotableResourceManager.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/FakePromotableResourceManager.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/FakePromotableResourceManager.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/FakePromotableResourceManager.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/Issue_2481.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/Issue_2481.cs new file mode 100644 index 000000000..0678b2511 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/Issue_2481.cs @@ -0,0 +1,58 @@ +namespace NServiceBus.AcceptanceTests.Tx +{ + using System; + using System.Transactions; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.AcceptanceTests.ScenarioDescriptors; + using NUnit.Framework; + + public class Issue_2481 : NServiceBusAcceptanceTest + { + [Test] + public void Should_enlist_the_receive_in_the_dtc_tx() + { + Scenario.Define() + .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MyMessage()))) + .Done(c => c.HandlerInvoked) + .Repeat(r => r.For()) + .Should(c => Assert.False(c.CanEnlistPromotable, "There should exists a DTC tx")) + .Run(); + } + + + public class Context : ScenarioContext + { + public bool HandlerInvoked { get; set; } + + public bool CanEnlistPromotable { get; set; } + } + + public class DTCEndpoint : EndpointConfigurationBuilder + { + public DTCEndpoint() + { + EndpointSetup(c=>c.Transactions().Enable()); + } + + public class MyMessageHandler : IHandleMessages + { + public Context Context { get; set; } + + public void Handle(MyMessage messageThatIsEnlisted) + { + Context.CanEnlistPromotable = Transaction.Current.EnlistPromotableSinglePhase(new FakePromotableResourceManager()); + Context.HandlerInvoked = true; + } + } + } + + [Serializable] + public class MyMessage : ICommand + { + } + + + + } +} diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_dtc_disabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_dtc_disabled.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_dtc_disabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_dtc_disabled.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_dtc_enabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_dtc_enabled.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_dtc_enabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_dtc_enabled.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_the_default_settings.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_the_default_settings.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_the_default_settings.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_the_default_settings.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_transactions_disabled.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_transactions_disabled.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_receiving_with_transactions_disabled.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_receiving_with_transactions_disabled.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_sending_within_an_ambient_transaction.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_sending_within_an_ambient_transaction.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Tx/When_sending_within_an_ambient_transaction.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Tx/When_sending_within_an_ambient_transaction.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Versioning/When_multiple_versions_of_a_message_is_published.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Versioning/When_multiple_versions_of_a_message_is_published.cs similarity index 100% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Versioning/When_multiple_versions_of_a_message_is_published.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Versioning/When_multiple_versions_of_a_message_is_published.cs diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Volatile/When_sending_to_non_durable_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Volatile/When_sending_to_non_durable_endpoint.cs similarity index 97% rename from src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Volatile/When_sending_to_non_durable_endpoint.cs rename to src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Volatile/When_sending_to_non_durable_endpoint.cs index 0e674201e..4f414e187 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.0.0/Volatile/When_sending_to_non_durable_endpoint.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/App_Packages/NSB.AcceptanceTests.5.2.6/Volatile/When_sending_to_non_durable_endpoint.cs @@ -32,7 +32,7 @@ public Sender() EndpointSetup(builder => { builder.DisableDurableMessages(); - builder.DiscardFailedMessagesInsteadOfSendingToErrorQueue(); // to avoid creating the error q, it might blow up for brokers (rabbitmq) + builder.DiscardFailedMessagesInsteadOfSendingToErrorQueue(); // to avoid creating the error q, it might blow up for brokers (RabbitMQ) }) .AddMapping(typeof(Receiver)); } @@ -45,7 +45,7 @@ public Receiver() EndpointSetup(builder => { builder.DisableDurableMessages(); - builder.DiscardFailedMessagesInsteadOfSendingToErrorQueue(); // to avoid creating the error q, it might blow up for brokers (rabbitmq) + builder.DiscardFailedMessagesInsteadOfSendingToErrorQueue(); // to avoid creating the error q, it might blow up for brokers (RabbitMQ) }); } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/NServiceBus.SqlServer.AcceptanceTests.csproj b/src/NServiceBus.SqlServer.AcceptanceTests/NServiceBus.SqlServer.AcceptanceTests.csproj index bb76491f4..57d5346c7 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/NServiceBus.SqlServer.AcceptanceTests.csproj +++ b/src/NServiceBus.SqlServer.AcceptanceTests/NServiceBus.SqlServer.AcceptanceTests.csproj @@ -39,11 +39,11 @@ False - ..\packages\NServiceBus.AcceptanceTesting.5.0.0\lib\net45\NServiceBus.AcceptanceTesting.dll + ..\packages\NServiceBus.AcceptanceTesting.5.2.6\lib\net45\NServiceBus.AcceptanceTesting.dll False - ..\packages\NServiceBus.5.0.0\lib\net45\NServiceBus.Core.dll + ..\packages\NServiceBus.5.2.6\lib\net45\NServiceBus.Core.dll ..\packages\NUnit.2.6.3\lib\nunit.framework.dll @@ -53,6 +53,18 @@ + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + @@ -63,119 +75,140 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/When_in_native_transaction_mode.cs b/src/NServiceBus.SqlServer.AcceptanceTests/When_in_native_transaction_mode.cs new file mode 100644 index 000000000..bb13f8c94 --- /dev/null +++ b/src/NServiceBus.SqlServer.AcceptanceTests/When_in_native_transaction_mode.cs @@ -0,0 +1,111 @@ +namespace NServiceBus.SqlServer.AcceptanceTests +{ + using System.Configuration; + using System.Reflection; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Transports.SQLServer; + using NUnit.Framework; + + public class When_in_native_transaction_mode + { + const string OtherDatabaseConnectionString = @"Server=localhost\sqlexpress;Database=other;Trusted_Connection=True"; + const string OtherSchemaConnectionString = @"Server=localhost\sqlexpress;Database=nservicebus;Trusted_Connection=True;Queue Schema=other"; + const string ExceptionText = "The transport is running in native SQL Server transactions mode without an outbox"; + + [Test] + public void When_multi_db_via_configuration_it_fails_to_start() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.CustomConfig(c => AddConnectionString("NServiceBus/Transport/OtherEndpoint", OtherDatabaseConnectionString))) + .Done(c => true) + .Run(); + + Assert.IsTrue(context.Exceptions.Contains(ExceptionText)); + } + + [Test] + public void When_multi_db_via_code_it_fails_to_start() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.CustomConfig(c => c.UseTransport().UseSpecificConnectionInformation( + EndpointConnectionInfo.For("A").UseConnectionString(OtherDatabaseConnectionString) + ))) + .Done(c => true) + .Run(); + + Assert.IsTrue(context.Exceptions.Contains(ExceptionText)); + } + + [Test] + public void When_multi_db_via_callback_it_fails_to_start_even_when_not_using_other_database() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.CustomConfig(c => c.UseTransport().UseSpecificConnectionInformation( + e => ConnectionInfo.Create().UseSchema("nsb") + ))) + .Done(c => true) + .Run(); + + Assert.IsTrue(context.Exceptions.Contains(ExceptionText)); + } + + [Test] + public void When_multi_schema_via_configuration_it_starts() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.CustomConfig(c => AddConnectionString("NServiceBus/Transport/OtherEndpoint", OtherSchemaConnectionString))) + .Done(c => true) + .Run(); + + Assert.IsNull(context.Exceptions); + } + + [Test] + public void When_multi_schema_via_code_it_starts() + { + var context = new Context(); + Scenario.Define(context) + .WithEndpoint(b => b.CustomConfig(c => c.UseTransport().UseSpecificConnectionInformation( + EndpointConnectionInfo.For("A").UseSchema("A"), + EndpointConnectionInfo.For("B").UseSchema("B") + ))) + .Done(c => true) + .Run(); + + Assert.IsNull(context.Exceptions); + } + + class Context : ScenarioContext + { + } + + static void AddConnectionString(string name, string value) + { + ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, value)); + } + + [SetUp] + [TearDown] + public void ClearConnectionStrings() + { + var connectionStrings = ConfigurationManager.ConnectionStrings; + //Setting the read only field to false via reflection in order to modify the connection strings + var readOnlyField = typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); + readOnlyField.SetValue(connectionStrings, false); + connectionStrings.Clear(); + } + + public class Receiver : EndpointConfigurationBuilder + { + public Receiver() + { + EndpointSetup(b => b.Transactions().DisableDistributedTransactions()); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/When_receiving_a_poison_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/When_receiving_a_poison_message.cs index 506ca8737..505786c6b 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/When_receiving_a_poison_message.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/When_receiving_a_poison_message.cs @@ -5,69 +5,113 @@ using System.Data.SqlClient; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTests.EndpointTemplates; - using NServiceBus.AcceptanceTests.ScenarioDescriptors; using NUnit.Framework; - public class When_receiving_a_poison_message: NServiceBusAcceptanceTest + public class When_receiving_a_poison_message : NServiceBusAcceptanceTest { const string ConnectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=nservicebus;Integrated Security=True"; - const string InsertPoisonMessageCommand = "INSERT [dbo].[Basic.Receiver.WhenReceivingAPoisonMessage] ([Id], [CorrelationId], [ReplyToAddress], [Recoverable], [Expires], [Headers], [Body]) VALUES (N'{0}', NULL, N'InvalidType', 1, NULL, N'', 0x0)"; + const string InsertPoisonMessageCommand = "INSERT [dbo].[Basic.Receiver.WhenReceivingAPoisonMessage.{1}] ([Id], [CorrelationId], [ReplyToAddress], [Recoverable], [Expires], [Headers], [Body]) VALUES (N'{0}', NULL, N'InvalidType', 1, NULL, N'', 0x0)"; const string CheckDlqMessageCountCommand = "SELECT COUNT(*) FROM [dbo].[Error] WHERE [Id] = '{0}'"; - const string CheckInputQueueMessageCountCommand = "SELECT COUNT(*) FROM [dbo].[Basic.Receiver.WhenReceivingAPoisonMessage] WHERE [Id] = '{0}'"; + const string CheckInputQueueMessageCountCommand = "SELECT COUNT(*) FROM [dbo].[Basic.Receiver.WhenReceivingAPoisonMessage.{1}] WHERE [Id] = '{0}'"; [Test] - public void Should_move_the_message_to_error_queue() + public void Should_move_the_message_to_error_queue_DTC() { - Scenario.Define(() => new Context { Id = Guid.NewGuid() }) - - .WithEndpoint(x => x.Given((b, c) => - { - using (var conn = new SqlConnection(ConnectionString)) - { - conn.Open(); - using (var cmd = new SqlCommand(string.Format(InsertPoisonMessageCommand, c.Id), conn) - { - CommandType = CommandType.Text - }) - { - cmd.ExecuteNonQuery(); - } - } - })) - .Done(c => - { - using (var conn = new SqlConnection(ConnectionString)) - { - conn.Open(); - using (var cmd = new SqlCommand(string.Format(CheckDlqMessageCountCommand, c.Id), conn) - { - CommandType = CommandType.Text - }) - { - var count = (int)cmd.ExecuteScalar(); - return count == 1; - } - } - }) - .AllowExceptions() - .Repeat(r => r.For()) - .Should(c => - { - using (var conn = new SqlConnection(ConnectionString)) - { - conn.Open(); - using (var cmd = new SqlCommand(string.Format(CheckInputQueueMessageCountCommand, c.Id), conn) - { - CommandType = CommandType.Text - }) - { - var count = (int)cmd.ExecuteScalar(); - Assert.AreEqual(0, count); - } - } - }) - .Run(TimeSpan.FromSeconds(20)); + const string mode = "DTC"; + var ctx = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(ctx) + .WithEndpoint(x => x.Given((b, c) => InsertPoisonMessage(c, mode))) + .Done(CheckErrorQueue) + .AllowExceptions() + .Run(TimeSpan.FromSeconds(20)); + + AssertNoMessagesInInputQueue(ctx, mode); + } + + [Test] + public void Should_move_the_message_to_error_queue_local() + { + const string mode = "Local"; + var ctx = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(ctx) + .WithEndpoint(x => x.Given((b, c) => InsertPoisonMessage(c, mode))) + .Done(CheckErrorQueue) + .AllowExceptions() + .Run(TimeSpan.FromSeconds(20)); + + AssertNoMessagesInInputQueue(ctx, mode); + } + + [Test] + public void Should_move_the_message_to_error_queue_none() + { + const string mode = "None"; + var ctx = new Context + { + Id = Guid.NewGuid() + }; + Scenario.Define(ctx) + .WithEndpoint(x => x.Given((b, c) => InsertPoisonMessage(c, mode))) + .Done(CheckErrorQueue) + .AllowExceptions() + .Run(TimeSpan.FromSeconds(20)); + + AssertNoMessagesInInputQueue(ctx, mode); + } + + + static void AssertNoMessagesInInputQueue(Context c, string mode) + { + using (var conn = new SqlConnection(ConnectionString)) + { + conn.Open(); + using (var cmd = new SqlCommand(string.Format(CheckInputQueueMessageCountCommand, c.Id, mode), conn) + { + CommandType = CommandType.Text + }) + { + var count = (int)cmd.ExecuteScalar(); + Assert.AreEqual(0, count); + } + } + } + + static bool CheckErrorQueue(Context c) + { + using (var conn = new SqlConnection(ConnectionString)) + { + conn.Open(); + using (var cmd = new SqlCommand(string.Format(CheckDlqMessageCountCommand, c.Id), conn) + { + CommandType = CommandType.Text + }) + { + var count = (int)cmd.ExecuteScalar(); + return count == 1; + } + } + } + + static void InsertPoisonMessage(Context c, string mode) + { + using (var conn = new SqlConnection(ConnectionString)) + { + conn.Open(); + using (var cmd = new SqlCommand(string.Format(InsertPoisonMessageCommand, c.Id, mode), conn) + { + CommandType = CommandType.Text + }) + { + cmd.ExecuteNonQuery(); + } + } } public class Context : ScenarioContext @@ -75,14 +119,38 @@ public class Context : ScenarioContext public Guid Id { get; set; } } - public class Receiver : EndpointConfigurationBuilder + public class ReceiverDTC : EndpointConfigurationBuilder + { + public ReceiverDTC() + { + EndpointSetup(cfg => + { + cfg.EndpointName("Basic.Receiver.WhenReceivingAPoisonMessage.DTC"); + cfg.UseTransport(); + }); + } + } + + public class ReceiverLocal : EndpointConfigurationBuilder + { + public ReceiverLocal() + { + EndpointSetup(cfg => + { + cfg.EndpointName("Basic.Receiver.WhenReceivingAPoisonMessage.Local"); + cfg.UseTransport(); + }); + } + } + + public class ReceiverNone : EndpointConfigurationBuilder { - public Receiver() + public ReceiverNone() { EndpointSetup(cfg => { - cfg.EndpointName("Basic.Receiver.WhenReceivingAPoisonMessage"); - cfg.UseTransport(); + cfg.EndpointName("Basic.Receiver.WhenReceivingAPoisonMessage.None"); + cfg.UseTransport(); }); } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/When_sharing_the_receive_connection.cs b/src/NServiceBus.SqlServer.AcceptanceTests/When_sharing_the_receive_connection.cs index a80385c2a..734e06c25 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/When_sharing_the_receive_connection.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/When_sharing_the_receive_connection.cs @@ -21,6 +21,8 @@ public void Should_reuse_it_for_sends_to_the_same_db() Assert.False(context.IsDtcTransaction); } + + public class Context : ScenarioContext { public bool Done { get; set; } @@ -33,6 +35,7 @@ public class StartMessage : IMessage { } [Serializable] public class AnotherMessage : IMessage { } + public class ConnectionSharingEndpoint : EndpointConfigurationBuilder { public ConnectionSharingEndpoint() diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/When_using_different_connection_strings_for_each_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/When_using_different_connection_strings_for_each_endpoint.cs index 9ad1c2e79..33d8d3ac1 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/When_using_different_connection_strings_for_each_endpoint.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/When_using_different_connection_strings_for_each_endpoint.cs @@ -17,14 +17,13 @@ public class When_using_different_connection_strings_for_each_endpoint : NServic [Test] public void Should_use_configured_connection_string_when_replying() { - var context = new Context() { Id = Guid.NewGuid() }; Scenario.Define(context) - .WithEndpoint(b => b.CustomConfig(c => AddConnectionString("NServiceBus/Transport/Basic.Sender.WhenUsingDifferentConnectionStringsForEachEndpoint.SqlServerTransport", SenderConnectionStringWithSchema))) + .WithEndpoint(b => b.CustomConfig(c => AddConnectionString("NServiceBus/Transport/UsingDifferentConnectionStringsForEachEndpoint.Sender", SenderConnectionStringWithSchema))) .WithEndpoint(b => b.Given((bus, c) => bus.Send(new MyRequest { ContextId = c.Id @@ -33,13 +32,20 @@ public void Should_use_configured_connection_string_when_replying() .Run(); } - static void AddConnectionString(string name, string value) + [SetUp] + [TearDown] + public void ClearConnectionStrings() { var connectionStrings = ConfigurationManager.ConnectionStrings; //Setting the read only field to false via reflection in order to modify the connection strings var readOnlyField = typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); readOnlyField.SetValue(connectionStrings, false); - connectionStrings.Add(new ConnectionStringSettings(name, value)); + connectionStrings.Clear(); + } + + static void AddConnectionString(string name, string value) + { + ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, value)); } public class Sender : EndpointConfigurationBuilder @@ -55,7 +61,7 @@ public class ConfigureTransport public void Configure(BusConfiguration busConfiguration) { busConfiguration.UseTransport() - .UseSpecificConnectionInformation(x => x == "Basic.Receiver.WhenUsingDifferentConnectionStringsForEachEndpoint.SqlServerTransport" ? ConnectionInfo.Create().UseConnectionString(ReceiverConnectionString).UseSchema("nsb") : null) + .UseSpecificConnectionInformation(x => x == "UsingDifferentConnectionStringsForEachEndpoint.Receiver" ? ConnectionInfo.Create().UseConnectionString(ReceiverConnectionString).UseSchema("nsb") : null) .ConnectionString(SenderConnectionStringWithSchema); } } @@ -89,10 +95,8 @@ public void Configure(BusConfiguration busConfiguration) { busConfiguration.UseTransport() .UseSpecificConnectionInformation( - EndpointConnectionInfo.For("Basic.Sender.WhenUsingDifferentConnectionStringsForEachEndpoint.SqlServerTransport").UseConnectionString("ToBeOverridenViaConfig").UseSchema("ToBeOverridenViaConfig")) + EndpointConnectionInfo.For("UsingDifferentConnectionStringsForEachEndpoint.Sender").UseConnectionString("ToBeOverridenViaConfig").UseSchema("ToBeOverridenViaConfig")) .ConnectionString(ReceiverConnectionStringWithSchema); - - busConfiguration.Transactions().DisableDistributedTransactions(); } } diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/When_using_non_standard_schema.cs b/src/NServiceBus.SqlServer.AcceptanceTests/When_using_non_standard_schema.cs index 8ec8be926..062ebc6ce 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/When_using_non_standard_schema.cs +++ b/src/NServiceBus.SqlServer.AcceptanceTests/When_using_non_standard_schema.cs @@ -1,8 +1,6 @@ namespace NServiceBus.AcceptanceTests.Basic { using System; - using System.Data; - using System.Data.SqlClient; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTests.EndpointTemplates; using NServiceBus.Transports.SQLServer; @@ -14,8 +12,6 @@ public class When_using_non_standard_schema : NServiceBusAcceptanceTest [Test] public void Should_receive_the_message() { - EnsureSchemaExists("receiver"); - EnsureSchemaExists("sender"); var context = new Context { Id = Guid.NewGuid() @@ -45,7 +41,7 @@ public Sender() .UseTransport() .DefaultSchema("sender") .UseSpecificConnectionInformation( - EndpointConnectionInfo.For("Basic.Receiver.WhenUsingNonStandardSchema.SqlServerTransport").UseSchema("receiver") + EndpointConnectionInfo.For("UsingNonStandardSchema.Receiver").UseSchema("receiver") )) .AddMapping(typeof(Receiver)); } @@ -83,28 +79,5 @@ public class MyMessage : ICommand { public Guid Id { get; set; } } - - static void EnsureSchemaExists(string schema) - { - const string ConnectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=nservicebus;Integrated Security=True"; - const string SchemaDdl = - @"IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{0}') -BEGIN - EXEC('CREATE SCHEMA {0}'); -END"; - - using (var conn = new SqlConnection(ConnectionString)) - { - conn.Open(); - using (var cmd = new SqlCommand(string.Format(SchemaDdl, schema), conn) - { - CommandType = CommandType.Text - }) - { - cmd.ExecuteNonQuery(); - } - } - } - } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/packages.config b/src/NServiceBus.SqlServer.AcceptanceTests/packages.config index ba34b6cc6..d3f5b7b7a 100644 --- a/src/NServiceBus.SqlServer.AcceptanceTests/packages.config +++ b/src/NServiceBus.SqlServer.AcceptanceTests/packages.config @@ -1,7 +1,12 @@  - - - + + + + + + + + \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/BackOff.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/BackOff.cs new file mode 100644 index 000000000..3317f9cbd --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/BackOff.cs @@ -0,0 +1,36 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + + class BackOff + { + int maximum; + int currentDelay = 50; + + public BackOff(int maximum) + { + this.maximum = maximum; + } + + public long Wait(Func condition) + { + if (!condition()) + { + currentDelay = 50; + return 0; + } + var result = currentDelay; + + if (currentDelay < maximum) + { + currentDelay *= 2; + } + + if (currentDelay > maximum) + { + currentDelay = maximum; + } + return result; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ISimulator.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ISimulator.cs new file mode 100644 index 000000000..73803f3e3 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ISimulator.cs @@ -0,0 +1,9 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System.Collections.Generic; + + interface ISimulator + { + IEnumerable Simulate(Load workLoad, int maximumConcurrency); + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Load.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Load.cs new file mode 100644 index 000000000..7dd7821bd --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Load.cs @@ -0,0 +1,61 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Generic; + + class Load + { + readonly List stages = new List(); + int currentStage; + long currentGlobalTime; + int totalSentMessages; + int totalMessages; + Action enqueueAction; + + public void Connect(Action enqueueAction) + { + this.enqueueAction = enqueueAction; + } + + public int TotalSentMessages + { + get { return totalSentMessages; } + } + + public int TotalMessages + { + get { return totalMessages; } + } + + public void TimePassed(long newCurrentGlobalTime) + { + if (currentStage >= stages.Count) + { + return; + } + var timePassed = newCurrentGlobalTime - currentGlobalTime; + + while (timePassed > 0 && currentStage < stages.Count) + { + timePassed -= stages[currentStage].ConsumeTimePassed(timePassed); + if (stages[currentStage].Complete) + { + currentStage++; + } + } + currentGlobalTime = newCurrentGlobalTime; + } + + public Load AddStage(long length, long period, Func processingTime) + { + var stage = new Stage(length, period, () => + { + totalSentMessages++; + enqueueAction(new Message(processingTime())); + }); + totalMessages += (int)(length/period); + stages.Add(stage); + return this; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Message.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Message.cs new file mode 100644 index 000000000..9db28e9c4 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Message.cs @@ -0,0 +1,17 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + class Message + { + readonly long processingTime; + + public Message(long processingTime) + { + this.processingTime = processingTime; + } + + public long ProcessingTime + { + get { return processingTime; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingStepResult.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingStepResult.cs new file mode 100644 index 000000000..aebd15096 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingStepResult.cs @@ -0,0 +1,24 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + class ProcessingStepResult + { + readonly long sleepFor; + readonly bool busyProcessingMessage; + + public ProcessingStepResult(long sleepFor, bool busyProcessingMessage) + { + this.sleepFor = sleepFor; + this.busyProcessingMessage = busyProcessingMessage; + } + + public long SleepFor + { + get { return sleepFor; } + } + + public bool BusyProcessingMessage + { + get { return busyProcessingMessage; } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingThread.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingThread.cs new file mode 100644 index 000000000..9a3eb51e2 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/ProcessingThread.cs @@ -0,0 +1,53 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Generic; + using NServiceBus.Transports.SQLServer; + + class ProcessingThread + { + readonly IRampUpController rampUpController; + readonly Func receive; + readonly Action process; + readonly Action addEvent; + bool successfulRead; + + public ProcessingThread(IRampUpController rampUpController, Func receive, Action process, Action addEvent) + { + this.rampUpController = rampUpController; + this.receive = receive; + this.process = process; + this.addEvent = addEvent; + } + + public IEnumerable ReceiveLoop() + { + var backOff = new BackOff(1000); + while (rampUpController.CheckHasEnoughWork()) + { + rampUpController.RampUpIfTooMuchWork(); + var message = receive(); + if (message != null) + { + addEvent("Processing started. Time remaining: "+message.ProcessingTime); + successfulRead = true; + yield return new ProcessingStepResult(message.ProcessingTime, true); + } + else + { + rampUpController.Failed(); + } + if (successfulRead) + { + process(message); + rampUpController.Succeeded(); + successfulRead = false; + } + else + { + yield return new ProcessingStepResult(backOff.Wait(() => message == null), false); + } + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RealSimulator.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RealSimulator.cs new file mode 100644 index 000000000..0dbec0fe7 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RealSimulator.cs @@ -0,0 +1,156 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Data.SqlClient; + using System.Diagnostics; + using System.Threading; + using System.Threading.Tasks; + using NServiceBus.CircuitBreakers; + using NServiceBus.Features; + using NServiceBus.Transports.SQLServer; + using NServiceBus.Unicast; + using NServiceBus.Unicast.Transport; + + class RealSimulator : ISimulator + { + readonly string address; + readonly SqlServerPollingDequeueStrategy dequeueStrategy; + SqlServerMessageSender sender; + int messagesProcessed; + int totalMessages; + ManualResetEventSlim signalEndEvent = new ManualResetEventSlim(false); + BlockingCollection results = new BlockingCollection(); + Stopwatch currentTime; + IDisposable taskStarted; + IDisposable taskEnded; + + public RealSimulator(string address, string connectionString) + { + this.address = address; + var localConnectionParams = new LocalConnectionParams(null, connectionString, "dbo"); + new SqlServerQueueCreator(new DefaultConnectionStringProvider(localConnectionParams), ConnectionFactory.Default()).CreateQueueIfNecessary(Address.Parse(address), null); + + var transportNotifications = new TransportNotifications(); + + taskStarted = transportNotifications.ReceiveTaskStarted.Subscribe(x => AddMessage("Thread started")); + taskEnded = transportNotifications.ReceiveTaskStopped.Subscribe(x => AddMessage("Thread died")); + + dequeueStrategy = new SqlServerPollingDequeueStrategy(localConnectionParams, + new ReceiveStrategyFactory(new DummyConnectionStore(), localConnectionParams, Address.Parse("error"), ConnectionFactory.Default()), + new QueuePurger(new SecondaryReceiveConfiguration(_ => SecondaryReceiveSettings.Disabled()), localConnectionParams, ConnectionFactory.Default()), + new SecondaryReceiveConfiguration(_ => SecondaryReceiveSettings.Disabled()), + transportNotifications, + new RepeatedFailuresOverTimeCircuitBreaker("A", TimeSpan.FromDays(1000), _ => { })); + + dequeueStrategy.Init(Address.Parse(address), new TransactionSettings(true, TimeSpan.FromMinutes(2), System.Transactions.IsolationLevel.ReadCommitted, 1, false, false), + ProcessMessage, (message, exception) => { }); + + sender = new SqlServerMessageSender(new DefaultConnectionStringProvider(localConnectionParams), new DummyConnectionStore(), new DummyCallbackAddressStore(), ConnectionFactory.Default()); + } + + void AddMessage(string message) + { + results.Add(string.Format("{0,12:n} [{1,2}] {2}", currentTime.ElapsedMilliseconds, "", message)); + } + + bool ProcessMessage(TransportMessage m) + { + var processingTime = BitConverter.ToInt64(m.Body, 0); + AddMessage(string.Format("Processing started. Time remaining: {0}", processingTime)); + Thread.Sleep((int)processingTime); + var processed = Interlocked.Increment(ref messagesProcessed); + if (processed >= totalMessages) + { + AddMessage("Processing finished."); + signalEndEvent.Set(); + } + return true; + } + + public IEnumerable Simulate(Load workLoad, int threadCount) + { + currentTime = new Stopwatch(); + currentTime.Start(); + workLoad.Connect(Enqueue); + totalMessages = workLoad.TotalMessages; + dequeueStrategy.Start(threadCount); + + Task.Run(() => + { + while (workLoad.TotalSentMessages < workLoad.TotalMessages) + { + var before = currentTime.ElapsedMilliseconds; + workLoad.TimePassed(before); + var after = currentTime.ElapsedMilliseconds; + var delay = (int) (after - before); + if (delay < 50) + { + Thread.Sleep(50 - delay); + } + } + signalEndEvent.Wait(); + taskStarted.Dispose(); + taskEnded.Dispose(); + results.CompleteAdding(); + }); + return results.GetConsumingEnumerable(); + } + + void Enqueue(Message msg) + { + sender.Send(new TransportMessage + { + Body = BitConverter.GetBytes(msg.ProcessingTime), + MessageIntent = MessageIntentEnum.Send, + Recoverable = true, + }, new SendOptions(address)); + } + + private class DummyCallbackAddressStore : ICallbackAddressStore + { + public void SetCallbackAddress(Address callbackAddress) + { + } + + public bool TryGetCallbackAddress(out Address callbackAddress) + { + callbackAddress = default(Address); + return false; + } + } + + private class DummyConnectionStore : IConnectionStore + { + public bool TryGetTransaction(string connectionString, out SqlTransaction transaction) + { + transaction = null; + return false; + } + + public bool TryGetConnection(string connectionString, out SqlConnection connection) + { + connection = null; + return false; + } + + public IDisposable SetTransaction(string connectionString, SqlTransaction transaction) + { + return new NullDisposable(); + } + + public IDisposable SetConnection(string connectionString, SqlConnection connection) + { + return new NullDisposable(); + } + + private class NullDisposable : IDisposable + { + public void Dispose() + { + } + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RunningThread.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RunningThread.cs new file mode 100644 index 000000000..91e77b4af --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/RunningThread.cs @@ -0,0 +1,85 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Generic; + + class RunningThread + { + long dueAt; + long blockedAt; + readonly int threadNumber; + readonly IEnumerator processingMethod; + readonly Action diedCallback; + bool replaced; + bool dead; + bool longRunning; + + public RunningThread(int threadNumber, IEnumerator processingMethod, Action diedCallback, long dueAt) + { + this.threadNumber = threadNumber; + this.processingMethod = processingMethod; + this.diedCallback = diedCallback; + this.dueAt = dueAt; + } + + public long BlockedAt + { + get { return blockedAt; } + } + + public bool ProcessingMessage { get; private set; } + + public long DueAt + { + get { return dueAt; } + } + + public int ThreadNumber + { + get { return threadNumber; } + } + + public bool Dead + { + get { return dead; } + } + + public bool Replaced + { + get { return replaced; } + } + + public bool LongRunning + { + get { return longRunning; } + } + + public void MarkAsReplaced() + { + replaced = true; + } + + public void Tick(long currentTime) + { + if (currentTime < dueAt) + { + return; + } + var stillAlive = processingMethod.MoveNext(); + blockedAt = currentTime; + replaced = false; + if (stillAlive) + { + var processingTime = processingMethod.Current; + ProcessingMessage = processingTime.BusyProcessingMessage; + dueAt = currentTime + processingTime.SleepFor; + longRunning = processingTime.SleepFor > 5000; + } + else + { + dead = true; + diedCallback(this); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulations.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulations.cs new file mode 100644 index 000000000..2eb8e3c62 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulations.cs @@ -0,0 +1,64 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Generic; + using NUnit.Framework; + + [TestFixture] + public class Simulations + { + bool RunRealSenderAndReceiver = false; + + [Test] + public void TestSlowMessages() + { + var workload = new Load() + .AddStage(1000, 50, () => 60*60*1000); + + var simulator = CreateSimulator(); + var results = simulator.Simulate(workload, 10); + DumpToConsole(results); + } + + [Test] + public void TestVariableTimes() + { + var random = new Random(133); + var workload = new Load() + .AddStage(1000, 50, () => + { + var randomValue = random.Next(100); + if (randomValue < 10) + { + return 12*60*100; + } + if (randomValue < 30) + { + return 1*60*100; + } + return 10; + }); + + var simulator = CreateSimulator(); + var results = simulator.Simulate(workload, 10); + DumpToConsole(results); + } + + static void DumpToConsole(IEnumerable results) + { + foreach (var result in results) + { + Console.WriteLine(result); + } + } + + private ISimulator CreateSimulator() + { + if (RunRealSenderAndReceiver) + { + return new RealSimulator("SQLPerfTest", @"Data Source=.\SQLEXPRESS;Initial Catalog=nservicebus;Integrated Security=True"); + } + return new Simulator(); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulator.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulator.cs new file mode 100644 index 000000000..5492f7f8b --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Simulator.cs @@ -0,0 +1,124 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using NServiceBus.Transports.SQLServer; + + class Simulator : ISimulator + { + int maximumConcurrency; + readonly Func rampUpControllerFactory; + long currentTime; + List threads = new List(); + List> result = new List>(); + List currentQueue = new List(); + int threadCounter; + int processedMessages; + private readonly List queue = new List(); + + public Message TryDequeue() + { + if (queue.Count > 0) + { + var result = queue[0]; + queue.RemoveAt(0); + return result; + } + return null; + } + + void RampUp() + { + if (threads.Count < maximumConcurrency) + { + var dueAt = currentTime + 1; + currentQueue.Add(() => + { + var number = StartThread(dueAt); + AddEvent(number, "Thread started"); + }); + } + } + + void AddEvent(int threadNumber, string eventType) + { + result.Add(Tuple.Create(currentTime, threadNumber, eventType)); + } + + public Simulator() + { + rampUpControllerFactory = x => new ReceiveRampUpController(x, new TransportNotifications(), "SomeQueue", 7, 5); + } + + public IEnumerable Simulate(Load workload, int maximumConcurrency) + { + this.maximumConcurrency = maximumConcurrency; + workload.Connect(queue.Add); + StartThread(0); + while (threads.Count > 0) + { + workload.TimePassed(currentTime); + const int longRunningThreshold = 100; + foreach (var runningThread in threads) + { + runningThread.Tick(currentTime); + var blockedTime = currentTime - runningThread.BlockedAt; + if (!runningThread.Dead && !runningThread.Replaced && runningThread.ProcessingMessage && blockedTime > longRunningThreshold) //blocked for more than five seconds + { + runningThread.MarkAsReplaced(); + RampUp(); + } + } + foreach (var action in currentQueue) + { + action(); + } + currentQueue.Clear(); + if (threads.Count > 0) + { + var newTime = threads.Min(x => x.DueAt); + if (threads.Any(x => x.LongRunning && !x.Replaced && newTime - currentTime > longRunningThreshold)) + { + currentTime = currentTime + longRunningThreshold; + } + else + { + currentTime = newTime; + } + } + //if (!workload.HasMoreMessages && processedMessages == workload.TotalMessages) + //{ + // break; + //} + } + return result.Select(x => string.Format("{0,12:n} [{1,2}] {2}", x.Item1, x.Item2, x.Item3)); + } + + int StartThread(long dueAt) + { + var threadNumber = threadCounter; + var newThread = new ProcessingThread(rampUpControllerFactory(RampUp), TryDequeue, _ => processedMessages++, s => AddEvent(threadNumber, s)); + var running = new RunningThread(threadNumber, newThread.ReceiveLoop().GetEnumerator(), OnTheadDied, dueAt); + threads.Add(running); + threadCounter++; + return threadNumber; + } + + void OnTheadDied(RunningThread obj) + { + currentQueue.Add(() => + { + threads.Remove(obj); + //if (threads.Count == 0) + //{ + // StartThread(currentTime + 1); + //} + //else + { + AddEvent(obj.ThreadNumber, "Thread died"); + } + }); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Stage.cs b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Stage.cs new file mode 100644 index 000000000..12efe1400 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/AdaptiveExecutorSimulator/Stage.cs @@ -0,0 +1,46 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + + class Stage + { + readonly long length; + readonly Action enqueueMessage; + long elapsed; + long enqueuedMessages; + long totalMessages; + + public Stage(long length, long period, Action enqueueMessage) + { + this.length = length; + this.enqueueMessage = enqueueMessage; + totalMessages = length / period; + } + + public long Length + { + get { return length; } + } + + public bool Complete + { + get { return elapsed == length; } + } + + public long ConsumeTimePassed(long milliseconds) + { + var maxToConsume = length - elapsed; + var consumed = maxToConsume > milliseconds + ? milliseconds : maxToConsume; + elapsed += consumed; + var messagesSoFar = (elapsed*totalMessages)/Length; + var toBeGenerated = messagesSoFar - enqueuedMessages; + for (var i = 0; i < toBeGenerated; i++) + { + enqueueMessage(); + } + enqueuedMessages += toBeGenerated; + return consumed; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/BoundedExponentialBackOffTests.cs b/src/NServiceBus.SqlServer.UnitTests/BoundedExponentialBackOffTests.cs new file mode 100644 index 000000000..1e1f9af5f --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/BoundedExponentialBackOffTests.cs @@ -0,0 +1,66 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using NServiceBus.Transports.SQLServer; + using NUnit.Framework; + + [TestFixture] + public class BoundedExponentialBackOffTests + { + [Test] + public void It_does_not_wait_if_condition_evaluates_to_false() + { + var waiter = new Waiter(); + var backOff = new BoundedExponentialBackOff(1000); + + backOff.ConditionalWait(() => false, waiter.Wait); + + Assert.AreEqual(0, waiter.LastWaitTime); + } + + [Test] + public void It_waits_initial_value_if_condition_evaluates_to_true() + { + var waiter = new Waiter(); + var backOff = new BoundedExponentialBackOff(1000); + + backOff.ConditionalWait(() => true, waiter.Wait); + + Assert.AreEqual(50, waiter.LastWaitTime); + } + + [Test] + public void It_waits_more_if_condition_evaluates_to_true() + { + var waiter = new Waiter(); + var backOff = new BoundedExponentialBackOff(1000); + + backOff.ConditionalWait(() => true, _ => { }); + backOff.ConditionalWait(() => true, waiter.Wait); + + Assert.AreEqual(100, waiter.LastWaitTime); + } + + [Test] + public void It_waits_no_more_than_maximum_value() + { + var waiter = new Waiter(); + var backOff = new BoundedExponentialBackOff(100); + + backOff.ConditionalWait(() => true, _ => { }); + backOff.ConditionalWait(() => true, _ => { }); + backOff.ConditionalWait(() => true, waiter.Wait); + + Assert.AreEqual(100, waiter.LastWaitTime); + } + + private class Waiter + { + public int LastWaitTime { get; private set; } + + public void Wait(int delay) + { + LastWaitTime = delay; + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.UnitTests/NServiceBus.SqlServer.UnitTests.csproj b/src/NServiceBus.SqlServer.UnitTests/NServiceBus.SqlServer.UnitTests.csproj index 7419e0297..fb932a30b 100644 --- a/src/NServiceBus.SqlServer.UnitTests/NServiceBus.SqlServer.UnitTests.csproj +++ b/src/NServiceBus.SqlServer.UnitTests/NServiceBus.SqlServer.UnitTests.csproj @@ -45,6 +45,19 @@ + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + + @@ -52,12 +65,25 @@ + + + + + + + + + + + + + diff --git a/src/NServiceBus.SqlServer.UnitTests/SqlConnectionFactoryConfigTests.cs b/src/NServiceBus.SqlServer.UnitTests/SqlConnectionFactoryConfigTests.cs new file mode 100644 index 000000000..7a1c06174 --- /dev/null +++ b/src/NServiceBus.SqlServer.UnitTests/SqlConnectionFactoryConfigTests.cs @@ -0,0 +1,29 @@ +namespace NServiceBus.SqlServer.UnitTests +{ + using System; + using System.Data.SqlClient; + using NServiceBus.Transports.SQLServer; + using NServiceBus.Transports.SQLServer.Config; + using NUnit.Framework; + + [TestFixture] + class SqlConnectionFactoryConfigTests : ConfigTest + { + [Test] + public void Sql_connection_factory_can_be_customized() + { + Func testFactory = connectionString => new SqlConnection(@"Data Source=.\SQLEXPRESS"); + + var busConfig = new BusConfiguration(); + busConfig + .UseTransport() + .UseCustomSqlConnectionFactory(testFactory); + + var builder = Activate(busConfig, new SqlConnectionFactoryConfig()); + var factory = builder.Build(); + + Assert.IsNotNull(factory); + Assert.AreEqual(@"Data Source=.\SQLEXPRESS", factory.OpenNewConnection("Invalid").ConnectionString); + } + } +} diff --git a/src/NServiceBus.SqlServer.UnitTests/packages.config b/src/NServiceBus.SqlServer.UnitTests/packages.config index 299eeaf55..0762cafa3 100644 --- a/src/NServiceBus.SqlServer.UnitTests/packages.config +++ b/src/NServiceBus.SqlServer.UnitTests/packages.config @@ -2,4 +2,9 @@ + + + + + \ No newline at end of file diff --git a/src/NServiceBus.SqlServer.sln.DotSettings b/src/NServiceBus.SqlServer.sln.DotSettings index 2154b918d..0529d9fb6 100644 --- a/src/NServiceBus.SqlServer.sln.DotSettings +++ b/src/NServiceBus.SqlServer.sln.DotSettings @@ -154,7 +154,8 @@ CHOP_ALWAYS True True - <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> <TypePattern DisplayName="COM interfaces or structs"> <TypePattern.Match> <Or> @@ -165,77 +166,67 @@ <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> </Or> </And> - <HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" /> + <Kind Is="Struct" /> </Or> </TypePattern.Match> </TypePattern> - <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> <TypePattern.Match> <And> <Kind Is="Class" /> - <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="true" /> - <HasAttribute Name="NUnit.Framework.TestCaseFixtureAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TestCaseFixtureAttribute" Inherited="True" /> </And> </TypePattern.Match> - <Entry DisplayName="Setup/Teardown Methods"> <Entry.Match> <And> <Kind Is="Method" /> <Or> - <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="true" /> - <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="true" /> - <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="true" /> - <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> </Or> </And> </Entry.Match> </Entry> - <Entry DisplayName="All other members" /> - - <Entry DisplayName="Test Methods" Priority="100"> + <Entry Priority="100" DisplayName="Test Methods"> <Entry.Match> <And> <Kind Is="Method" /> - <HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> </And> </Entry.Match> - <Entry.SortBy> <Name /> </Entry.SortBy> </Entry> </TypePattern> - <TypePattern DisplayName="Default Pattern"> - <Entry DisplayName="Public Delegates" Priority="100"> + <Entry Priority="100" DisplayName="Public Delegates"> <Entry.Match> <And> <Access Is="Public" /> <Kind Is="Delegate" /> </And> </Entry.Match> - <Entry.SortBy> <Name /> </Entry.SortBy> </Entry> - - <Entry DisplayName="Public Enums" Priority="100"> + <Entry Priority="100" DisplayName="Public Enums"> <Entry.Match> <And> <Access Is="Public" /> <Kind Is="Enum" /> </And> </Entry.Match> - <Entry.SortBy> <Name /> </Entry.SortBy> </Entry> - <Entry DisplayName="Static Fields and Constants"> <Entry.Match> <Or> @@ -246,17 +237,10 @@ </And> </Or> </Entry.Match> - <Entry.SortBy> - <Kind> - <Kind.Order> - <DeclarationKind>Constant</DeclarationKind> - <DeclarationKind>Field</DeclarationKind> - </Kind.Order> - </Kind> + <Kind Order="Constant Field" /> </Entry.SortBy> </Entry> - <Entry DisplayName="Fields"> <Entry.Match> <And> @@ -266,23 +250,19 @@ </Not> </And> </Entry.Match> - <Entry.SortBy> <Readonly /> <Name /> </Entry.SortBy> </Entry> - <Entry DisplayName="Constructors"> <Entry.Match> <Kind Is="Constructor" /> </Entry.Match> - <Entry.SortBy> - <Static/> + <Static /> </Entry.SortBy> </Entry> - <Entry DisplayName="Properties, Indexers"> <Entry.Match> <Or> @@ -291,30 +271,25 @@ </Or> </Entry.Match> </Entry> - - <Entry DisplayName="Interface Implementations" Priority="100"> + <Entry Priority="100" DisplayName="Interface Implementations"> <Entry.Match> <And> <Kind Is="Member" /> <ImplementsInterface /> </And> </Entry.Match> - <Entry.SortBy> - <ImplementsInterface Immediate="true" /> + <ImplementsInterface Immediate="True" /> </Entry.SortBy> </Entry> - <Entry DisplayName="All other members" /> - <Entry DisplayName="Nested Types"> <Entry.Match> <Kind Is="Type" /> </Entry.Match> </Entry> </TypePattern> -</Patterns> - +</Patterns> <?xml version="1.0" encoding="utf-8" ?> <!-- @@ -581,6 +556,7 @@ II.2.12 <HandlesEvent /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> True True + True True True True diff --git a/src/NServiceBus.SqlServer/AdaptiveExecutor.cs b/src/NServiceBus.SqlServer/AdaptiveExecutor.cs index 1f68d3955..9f667e392 100644 --- a/src/NServiceBus.SqlServer/AdaptiveExecutor.cs +++ b/src/NServiceBus.SqlServer/AdaptiveExecutor.cs @@ -1,6 +1,7 @@ namespace NServiceBus.Transports.SQLServer { using System; + using System.Linq; using System.Threading; using System.Threading.Tasks; using NServiceBus.CircuitBreakers; @@ -8,42 +9,64 @@ abstract class AdaptiveExecutor : IExecutor { protected abstract T Init(); - protected abstract T Try(T initialValue, out bool success); + protected abstract T Try(out bool success); protected abstract void Finally(T value); protected abstract void HandleException(Exception ex); protected abstract IRampUpController CreateRampUpController(Action rampUpCallback); - protected abstract ITaskTracker CreateTaskTracker(int maximumConcurrency); - - protected AdaptiveExecutor(RepeatedFailuresOverTimeCircuitBreaker circuitBreaker) + protected abstract IBackOffStrategy CreateBackOffStrategy(); + + protected AdaptiveExecutor(string name, RepeatedFailuresOverTimeCircuitBreaker circuitBreaker, TransportNotifications transportNotifications, TimeSpan slowTaskThreshold) { + this.name = name; this.circuitBreaker = circuitBreaker; + this.transportNotifications = transportNotifications; + this.slowTaskThreshold = slowTaskThreshold; } public virtual void Start(int maximumConcurrency, CancellationToken token) { if (taskTracker != null) { - throw new InvalidOperationException("The executor has already been started. Use Stop() to stop it."); + throw new InvalidOperationException("The executor has already been started."); } this.token = token; - taskTracker = CreateTaskTracker(maximumConcurrency); + taskTracker = new TaskTracker(maximumConcurrency, transportNotifications, name); StartTask(); + slowTaskTimer = new Timer(_ => MonitorSlowTasks(), null, TimeSpan.Zero, slowTaskThreshold); } public virtual void Stop() { + if (taskTracker == null) + { + throw new InvalidOperationException("The executor has not been started."); + } + using (var waitHandle = new ManualResetEvent(false)) + { + slowTaskTimer.Dispose(waitHandle); + waitHandle.WaitOne(); + } taskTracker.ShutdownAll(); - taskTracker = null; } + void MonitorSlowTasks() + { + var allStates = taskTracker.GetTaskStates(); + foreach (var state in allStates.Cast()) + { + state.TriggerAnotherTaskIfLongRunning(StartTask); + } + } + void StartTask() { taskTracker.StartAndTrack(() => { + var state = new ExecutorTaskState(); var taskId = Guid.NewGuid(); var receiveTask = Task.Factory - .StartNew(ReceiveLoop, null, token, TaskCreationOptions.LongRunning, TaskScheduler.Default) + .StartNew(ReceiveLoop, state, token, TaskCreationOptions.LongRunning, TaskScheduler.Default) .ContinueWith((t, s) => { if (t.IsFaulted) @@ -66,23 +89,25 @@ void StartTask() StartTask(); }, taskId, token); - return Tuple.Create(taskId, receiveTask); + return Tuple.Create(taskId, receiveTask, state); }); } void ReceiveLoop(object obj) { - var backOff = new BackOff(1000); + var state = (ExecutorTaskState) obj; + var backOff = CreateBackOffStrategy(); var rampUpController = CreateRampUpController(StartTask); while (!token.IsCancellationRequested && rampUpController.CheckHasEnoughWork()) { bool success; + state.Reset(); rampUpController.RampUpIfTooMuchWork(); var result = Init(); try { - result = Try(result, out success); + result = Try(out success); if (success) { rampUpController.Succeeded(); @@ -98,13 +123,16 @@ void ReceiveLoop(object obj) } circuitBreaker.Success(); - backOff.Wait(() => !success); + backOff.ConditionalWait(() => !success, Thread.Sleep); } } + Timer slowTaskTimer; + readonly TimeSpan slowTaskThreshold; + readonly string name; readonly RepeatedFailuresOverTimeCircuitBreaker circuitBreaker; + readonly TransportNotifications transportNotifications; CancellationToken token; - ITaskTracker taskTracker; - + TaskTracker taskTracker; } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/AdaptivePollingReceiver.cs b/src/NServiceBus.SqlServer/AdaptivePollingReceiver.cs index 6cb1a99ae..0dd1eb880 100644 --- a/src/NServiceBus.SqlServer/AdaptivePollingReceiver.cs +++ b/src/NServiceBus.SqlServer/AdaptivePollingReceiver.cs @@ -7,13 +7,31 @@ class AdaptivePollingReceiver : AdaptiveExecutor { + /// + /// Controls the ramping up of additional threads in case one of the current threads is processing a slow message. + /// If the processing takes more than a number of seconds, an additional thread is ramped up. Such thing can happen only once per processing a single message. + /// + const int SlowTaskThresholdInMilliseconds = 5000; + /// + /// The maximum number of failures of receive for a given thread before it decides to commit suicide. + /// + const int MaximumConsecutiveFailures = 7; + /// + /// The minimum number of successful message processing attempts for a given thread before it tries to ramp up another thread. + /// + const int MinimumConsecutiveSuccesses = 5; + /// + /// The maximum time for a thread to wait if a previous receive operation failed. + /// + const int MaximumBackOffTimeMilliseconds = 1000; + public AdaptivePollingReceiver( IReceiveStrategy receiveStrategy, TableBasedQueue queue, Action endProcessMessage, RepeatedFailuresOverTimeCircuitBreaker circuitBreaker, TransportNotifications transportNotifications) - : base(circuitBreaker) + : base(queue.ToString(), circuitBreaker, transportNotifications, TimeSpan.FromMilliseconds(SlowTaskThresholdInMilliseconds)) { this.receiveStrategy = receiveStrategy; this.queue = queue; @@ -32,7 +50,7 @@ protected override ReceiveResult Init() return ReceiveResult.NoMessage(); } - protected override ReceiveResult Try(ReceiveResult initialValue, out bool success) + protected override ReceiveResult Try(out bool success) { var result = receiveStrategy.TryReceiveFrom(queue); success = result.HasReceivedMessage; @@ -54,12 +72,12 @@ protected override void HandleException(Exception ex) protected override IRampUpController CreateRampUpController(Action rampUpCallback) { - return new ReceiveRampUpController(rampUpCallback, transportNotifications, queue.ToString()); + return new ReceiveRampUpController(rampUpCallback, transportNotifications, queue.ToString(), MaximumConsecutiveFailures, MinimumConsecutiveSuccesses); } - protected override ITaskTracker CreateTaskTracker(int maximumConcurrency) + protected override IBackOffStrategy CreateBackOffStrategy() { - return new ReceiveTaskTracker(maximumConcurrency, transportNotifications, queue.ToString()); + return new BoundedExponentialBackOff(MaximumBackOffTimeMilliseconds); } readonly IReceiveStrategy receiveStrategy; diff --git a/src/NServiceBus.SqlServer/AmbientTransactionReceiveStrategy.cs b/src/NServiceBus.SqlServer/AmbientTransactionReceiveStrategy.cs index 08e9883cb..2ce6306a9 100644 --- a/src/NServiceBus.SqlServer/AmbientTransactionReceiveStrategy.cs +++ b/src/NServiceBus.SqlServer/AmbientTransactionReceiveStrategy.cs @@ -1,25 +1,26 @@ namespace NServiceBus.Transports.SQLServer { using System; - using System.Data.SqlClient; using System.Transactions; - using NServiceBus.Pipeline; using NServiceBus.Unicast.Transport; class AmbientTransactionReceiveStrategy : IReceiveStrategy { - readonly PipelineExecutor pipelineExecutor; readonly string connectionString; readonly TableBasedQueue errorQueue; readonly Func tryProcessMessageCallback; readonly TransactionOptions transactionOptions; + readonly ConnectionFactory sqlConnectionFactory; + readonly IConnectionStore connectionStore; - public AmbientTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback, PipelineExecutor pipelineExecutor, TransactionSettings transactionSettings) + public AmbientTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback, ConnectionFactory sqlConnectionFactory, IConnectionStore connectionStore, TransactionSettings transactionSettings) { - this.pipelineExecutor = pipelineExecutor; this.tryProcessMessageCallback = tryProcessMessageCallback; this.errorQueue = errorQueue; this.connectionString = connectionString; + this.sqlConnectionFactory = sqlConnectionFactory; + this.connectionStore = connectionStore; + transactionOptions = new TransactionOptions { IsolationLevel = transactionSettings.IsolationLevel, @@ -31,10 +32,9 @@ public ReceiveResult TryReceiveFrom(TableBasedQueue queue) { using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions)) { - using (var connection = new SqlConnection(connectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionString)) { - connection.Open(); - using (pipelineExecutor.SetConnection(connectionString, connection)) + using (connectionStore.SetConnection(connectionString, connection)) { var readResult = queue.TryReceive(connection); if (readResult.IsPoison) diff --git a/src/NServiceBus.SqlServer/BackOff.cs b/src/NServiceBus.SqlServer/BackOff.cs deleted file mode 100644 index 91069ccd4..000000000 --- a/src/NServiceBus.SqlServer/BackOff.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace NServiceBus.Transports.SQLServer -{ - using System; - using System.Threading; - - /// - /// A utility class that does a sleep on very call up to a limit based on a condition. - /// - class BackOff - { - int maximum; - int currentDelay = 50; - - /// - /// Initializes a new instance. - /// - /// The maximum number of milliseconds for which the thread is blocked. - public BackOff(int maximum) - { - this.maximum = maximum; - } - - /// - /// It executes the Thread sleep if condition is true, otherwise it resets. - /// - /// If the condition is true then the wait is performed. - public void Wait(Func condition) - { - if (!condition()) - { - currentDelay = 50; - return; - } - - Thread.Sleep(currentDelay); - - if (currentDelay < maximum) - { - currentDelay *= 2; - } - - if (currentDelay > maximum) - { - currentDelay = maximum; - } - } - } -} diff --git a/src/NServiceBus.SqlServer/BoundedExponentialBackOff.cs b/src/NServiceBus.SqlServer/BoundedExponentialBackOff.cs new file mode 100644 index 000000000..38f6a5c8c --- /dev/null +++ b/src/NServiceBus.SqlServer/BoundedExponentialBackOff.cs @@ -0,0 +1,46 @@ +namespace NServiceBus.Transports.SQLServer +{ + using System; + + /// + /// A utility class that does a sleep on very call up to a limit based on a condition. + /// + class BoundedExponentialBackOff : IBackOffStrategy + { + static readonly int defaultDelay = 50; + readonly int maximumDelay; + int currentDelay = defaultDelay; + + /// + /// Initializes a new instance. + /// + /// The maximum number of milliseconds for which the thread is blocked. + public BoundedExponentialBackOff(int maximumDelay) + { + this.maximumDelay = maximumDelay; + } + + /// + /// It executes the Thread sleep if condition is true, otherwise it resets. + /// + /// If the condition is true then the wait is performed. + /// + public void ConditionalWait(Func condition, Action waitAction) + { + if (condition()) + { + waitAction(currentDelay); + currentDelay = RecalculateDelay(currentDelay, maximumDelay); + } + else + { + currentDelay = defaultDelay; + } + } + + static int RecalculateDelay(int currentDelay, int maximumDelay) + { + return Math.Min(maximumDelay, currentDelay * 2); + } + } +} diff --git a/src/NServiceBus.SqlServer/CallbackQueuePipelineContextExtensions.cs b/src/NServiceBus.SqlServer/CallbackQueuePipelineContextExtensions.cs deleted file mode 100644 index e468a78b6..000000000 --- a/src/NServiceBus.SqlServer/CallbackQueuePipelineContextExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace NServiceBus.Transports.SQLServer -{ - using NServiceBus.Pipeline; - - static class CallbackQueuePipelineContextExtensions - { - const string SqlServerCallbackAddressContextKey = "SqlServerCallbackAddress"; - - public static void SetCallbackAddress(this BehaviorContext context, Address callbackAddress) - { - context.Set(SqlServerCallbackAddressContextKey,callbackAddress); - } - - public static Address TryGetCallbackAddress(this BehaviorContext context) - { - Address callbackAddress; - context.TryGet(SqlServerCallbackAddressContextKey, out callbackAddress); - return callbackAddress; - } - } -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/CollectionConnectionStringProvider.cs b/src/NServiceBus.SqlServer/CollectionConnectionStringProvider.cs index e0e7874b5..f9912dd99 100644 --- a/src/NServiceBus.SqlServer/CollectionConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/CollectionConnectionStringProvider.cs @@ -22,5 +22,10 @@ public ConnectionParams GetForDestination(Address destination) ? found.CreateConnectionParams(localConnectionParams) : null; } + + public bool AllowsNonLocalConnectionString + { + get { return connectionStrings.Any(x => x.OverridesConnectionString); } + } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/CompositeConnectionStringProvider.cs b/src/NServiceBus.SqlServer/CompositeConnectionStringProvider.cs index 8e0561253..917e551ba 100644 --- a/src/NServiceBus.SqlServer/CompositeConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/CompositeConnectionStringProvider.cs @@ -16,5 +16,10 @@ public ConnectionParams GetForDestination(Address destination) { return components.Select(x => x.GetForDestination(destination)).First(x => x != null); } + + public bool AllowsNonLocalConnectionString + { + get { return components.Any(x => x.AllowsNonLocalConnectionString); } + } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/Config/ConnectionConfig.cs b/src/NServiceBus.SqlServer/Config/ConnectionConfig.cs index 8da601dbe..1b155744d 100644 --- a/src/NServiceBus.SqlServer/Config/ConnectionConfig.cs +++ b/src/NServiceBus.SqlServer/Config/ConnectionConfig.cs @@ -3,6 +3,7 @@ namespace NServiceBus.Transports.SQLServer.Config using System; using System.Collections.Generic; using System.Configuration; + using System.Data.Common; using System.Linq; using NServiceBus.Features; @@ -32,6 +33,20 @@ public override void Configure(FeatureConfigurationContext context, string conne } CompositeConnectionStringProvider ConfigureConnectionStringProvider(FeatureConfigurationContext context, LocalConnectionParams localConnectionParams) + { + var configProvidedPerEndpointConnectionStrings = CreateConfigPerEndpointConnectionStringProvider(localConnectionParams); + var programmaticallyProvidedPerEndpointConnectionStrings = CreateProgrammaticPerEndpointConnectionStringProvider(context, localConnectionParams); + + var connectionStringProvider = new CompositeConnectionStringProvider( + configProvidedPerEndpointConnectionStrings, + programmaticallyProvidedPerEndpointConnectionStrings, + new DefaultConnectionStringProvider(localConnectionParams) + ); + + return connectionStringProvider; + } + + IConnectionStringProvider CreateConfigPerEndpointConnectionStringProvider(LocalConnectionParams localConnectionParams) { const string transportConnectionStringPrefix = "NServiceBus/Transport/"; var configConnectionStrings = @@ -42,23 +57,25 @@ CompositeConnectionStringProvider ConfigureConnectionStringProvider(FeatureConfi string schema; var connectionString = x.ConnectionString.ExtractSchemaName(out schema); var endpoint = x.Name.Replace(transportConnectionStringPrefix, String.Empty); - return EndpointConnectionInfo.For(endpoint).UseConnectionString(connectionString).UseSchema(schema); - }); + var connectionInfo = EndpointConnectionInfo.For(endpoint).UseSchema(schema); - var configProvidedPerEndpointConnectionStrings = new CollectionConnectionStringProvider(configConnectionStrings, localConnectionParams); - var programmaticallyProvidedPerEndpointConnectionStrings = CreateProgrammaticPerEndpointConnectionStringProvider(context, localConnectionParams); + var localConnectionStringBuilder = new DbConnectionStringBuilder { ConnectionString = localConnectionParams.ConnectionString }; + var overriddenConnectionStringBuilder = new DbConnectionStringBuilder { ConnectionString = connectionString }; - var connectionStringProvider = new CompositeConnectionStringProvider( - configProvidedPerEndpointConnectionStrings, - programmaticallyProvidedPerEndpointConnectionStrings, - new DefaultConnectionStringProvider(localConnectionParams) - ); - return connectionStringProvider; + if (!localConnectionStringBuilder.EquivalentTo(overriddenConnectionStringBuilder)) + { + connectionInfo = connectionInfo.UseConnectionString(connectionString); + } + return connectionInfo; + }) + .ToArray(); + + return new CollectionConnectionStringProvider(configConnectionStrings, localConnectionParams); } static IConnectionStringProvider CreateProgrammaticPerEndpointConnectionStringProvider(FeatureConfigurationContext context, LocalConnectionParams localConnectionParams) { - var collection = context.Settings.GetOrDefault>(PerEndpointConnectionStringsCollectionSettingKey); + var collection = context.Settings.GetOrDefault(PerEndpointConnectionStringsCollectionSettingKey); if (collection != null) { return new CollectionConnectionStringProvider(collection, localConnectionParams); diff --git a/src/NServiceBus.SqlServer/Config/SqlConnectionFactoryConfig.cs b/src/NServiceBus.SqlServer/Config/SqlConnectionFactoryConfig.cs new file mode 100644 index 000000000..18524a481 --- /dev/null +++ b/src/NServiceBus.SqlServer/Config/SqlConnectionFactoryConfig.cs @@ -0,0 +1,22 @@ +namespace NServiceBus.Transports.SQLServer.Config +{ + using NServiceBus.Features; + using NServiceBus.Settings; + + class SqlConnectionFactoryConfig : ConfigBase + { + internal const string CustomSqlConnectionFactorySettingKey = "SqlServer.CustomSqlConnectionFactory"; + + + public override void SetUpDefaults(SettingsHolder settings) + { + settings.SetDefault(CustomSqlConnectionFactorySettingKey, ConnectionFactory.Default()); + } + + public override void Configure(FeatureConfigurationContext context, string connectionStringWithSchema) + { + var factory = context.Settings.Get(CustomSqlConnectionFactorySettingKey); + context.Container.ConfigureComponent(b => factory, DependencyLifecycle.SingleInstance); + } + } +} diff --git a/src/NServiceBus.SqlServer/Config/SqlServerTransportFeature.cs b/src/NServiceBus.SqlServer/Config/SqlServerTransportFeature.cs index ca036f84d..6f04f6159 100644 --- a/src/NServiceBus.SqlServer/Config/SqlServerTransportFeature.cs +++ b/src/NServiceBus.SqlServer/Config/SqlServerTransportFeature.cs @@ -10,6 +10,7 @@ namespace NServiceBus.Features using Transports; using Transports.SQLServer; + class SqlServerTransportFeature : ConfigureTransport { readonly List configs = new List() @@ -17,7 +18,8 @@ class SqlServerTransportFeature : ConfigureTransport new CallbackConfig(), new CircuitBreakerConfig(), new ConnectionConfig(ConfigurationManager.ConnectionStrings.Cast().ToList()), - new PurgingConfig() + new PurgingConfig(), + new SqlConnectionFactoryConfig() }; public SqlServerTransportFeature() @@ -56,7 +58,13 @@ protected override void Configure(FeatureConfigurationContext context, string co config.Configure(context, connectionStringWithSchema); } - context.Container.ConfigureComponent(DependencyLifecycle.InstancePerCall); + context.Container.ConfigureComponent( + b => new SqlServerMessageSender( + b.Build(), + new ContextualConnectionStore(b.Build()), + new ContextualCallbackAddressStore(b.Build().CurrentContext), + b.Build()), + DependencyLifecycle.InstancePerCall); if (!context.Settings.GetOrDefault("Endpoint.SendOnly")) { @@ -64,7 +72,7 @@ protected override void Configure(FeatureConfigurationContext context, string co context.Container.ConfigureComponent(DependencyLifecycle.InstancePerCall); var errorQueue = ErrorQueueSettings.GetConfiguredErrorQueue(context.Settings); - context.Container.ConfigureComponent(b => new ReceiveStrategyFactory(b.Build(), b.Build(), errorQueue), DependencyLifecycle.InstancePerCall); + context.Container.ConfigureComponent(b => new ReceiveStrategyFactory(new ContextualConnectionStore(b.Build()), b.Build(), errorQueue, b.Build()), DependencyLifecycle.InstancePerCall); context.Container.ConfigureComponent(DependencyLifecycle.InstancePerCall); context.Container.ConfigureComponent(b => new SqlServerStorageContext(b.Build(), b.Build()), DependencyLifecycle.InstancePerUnitOfWork); diff --git a/src/NServiceBus.SqlServer/Config/ValidateOutboxOrAmbientTransactionsEnabled.cs b/src/NServiceBus.SqlServer/Config/ValidateOutboxOrAmbientTransactionsEnabled.cs new file mode 100644 index 000000000..61d46bf24 --- /dev/null +++ b/src/NServiceBus.SqlServer/Config/ValidateOutboxOrAmbientTransactionsEnabled.cs @@ -0,0 +1,43 @@ +namespace NServiceBus.Features +{ + using System; + using NServiceBus.Transports.SQLServer; + + class ValidateOutboxOrAmbientTransactionsEnabled : Feature + { + public ValidateOutboxOrAmbientTransactionsEnabled() + { + EnableByDefault(); + } + + protected override void Setup(FeatureConfigurationContext context) + { + if (!context.Settings.GetOrDefault(typeof(Outbox).FullName) + && context.Settings.Get("Transactions.SuppressDistributedTransactions") + && context.Settings.Get("Transactions.Enabled")) + { + RegisterStartupTask(); + } + } + + class ValiateTask : FeatureStartupTask + { + readonly IConnectionStringProvider connectionStringProvider; + + public ValiateTask(IConnectionStringProvider connectionStringProvider) + { + this.connectionStringProvider = connectionStringProvider; + } + + protected override void OnStart() + { + if (connectionStringProvider.AllowsNonLocalConnectionString) + { + throw new Exception(@"The transport is running in native SQL Server transactions mode without an outbox, but configuration uses " + + "multi-database sending (http://docs.particular.net/nservicebus/sqlserver/multiple-databases). Multi-database sends can only be used when either in ambient transaction mode " + + "or when outbox is enabled. Please check your endpoint configuration."); + } + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/ConnectionFactory.cs b/src/NServiceBus.SqlServer/ConnectionFactory.cs new file mode 100644 index 000000000..9e1edc741 --- /dev/null +++ b/src/NServiceBus.SqlServer/ConnectionFactory.cs @@ -0,0 +1,39 @@ +namespace NServiceBus.Transports.SQLServer +{ + using System; + using System.Data.SqlClient; + + class ConnectionFactory + { + readonly Func openNewConnection; + + public ConnectionFactory(Func factory) + { + openNewConnection = factory; + } + + public SqlConnection OpenNewConnection(string connectionString) + { + return openNewConnection(connectionString); + } + + public static ConnectionFactory Default() + { + return new ConnectionFactory(cs => + { + var connection = new SqlConnection(cs); + try + { + connection.Open(); + } + catch (Exception) + { + connection.Dispose(); + throw; + } + + return connection; + }); + } + } +} diff --git a/src/NServiceBus.SqlServer/DefaultConnectionStringProvider.cs b/src/NServiceBus.SqlServer/DefaultConnectionStringProvider.cs index f1e2c7f6d..637998f15 100644 --- a/src/NServiceBus.SqlServer/DefaultConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/DefaultConnectionStringProvider.cs @@ -13,5 +13,7 @@ public ConnectionParams GetForDestination(Address destination) { return localConnectionParams; } + + public bool AllowsNonLocalConnectionString { get { return false; }} } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/DelegateConnectionStringProvider.cs b/src/NServiceBus.SqlServer/DelegateConnectionStringProvider.cs index 1ac528443..2c178c598 100644 --- a/src/NServiceBus.SqlServer/DelegateConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/DelegateConnectionStringProvider.cs @@ -20,5 +20,7 @@ public ConnectionParams GetForDestination(Address destination) ? connectionInfo.CreateConnectionParams(localConnectionParams) : null; } + + public bool AllowsNonLocalConnectionString { get { return true; }} } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/EndpointConnectionInfo.cs b/src/NServiceBus.SqlServer/EndpointConnectionInfo.cs index 3976dd801..22db52f10 100644 --- a/src/NServiceBus.SqlServer/EndpointConnectionInfo.cs +++ b/src/NServiceBus.SqlServer/EndpointConnectionInfo.cs @@ -61,5 +61,10 @@ internal ConnectionParams CreateConnectionParams(LocalConnectionParams defaultCo { return defaultConnectionParams.MakeSpecific(connectionString, schemaName); } + + internal bool OverridesConnectionString + { + get { return connectionString != null; } + } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/ExecutorTaskState.cs b/src/NServiceBus.SqlServer/ExecutorTaskState.cs new file mode 100644 index 000000000..c8a0e5dcd --- /dev/null +++ b/src/NServiceBus.SqlServer/ExecutorTaskState.cs @@ -0,0 +1,23 @@ +namespace NServiceBus.Transports.SQLServer +{ + using System; + + class ExecutorTaskState + { + int seen; + + public void Reset() + { + seen = 0; + } + + public void TriggerAnotherTaskIfLongRunning(Action triggerAction) + { + seen += 1; + if (seen == 2) + { + triggerAction(); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/IBackOffStrategy.cs b/src/NServiceBus.SqlServer/IBackOffStrategy.cs new file mode 100644 index 000000000..35c022bcf --- /dev/null +++ b/src/NServiceBus.SqlServer/IBackOffStrategy.cs @@ -0,0 +1,9 @@ +namespace NServiceBus.Transports.SQLServer +{ + using System; + + interface IBackOffStrategy + { + void ConditionalWait(Func condition, Action waitAction); + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/ICallbackAddressStore.cs b/src/NServiceBus.SqlServer/ICallbackAddressStore.cs new file mode 100644 index 000000000..4dc4815f5 --- /dev/null +++ b/src/NServiceBus.SqlServer/ICallbackAddressStore.cs @@ -0,0 +1,31 @@ +namespace NServiceBus.Transports.SQLServer +{ + using NServiceBus.Pipeline; + + interface ICallbackAddressStore + { + void SetCallbackAddress(Address callbackAddress); + bool TryGetCallbackAddress(out Address callbackAddress); + } + + class ContextualCallbackAddressStore : ICallbackAddressStore + { + readonly BehaviorContext behaviorContext; + const string SqlServerCallbackAddressContextKey = "SqlServerCallbackAddress"; + + public ContextualCallbackAddressStore(BehaviorContext behaviorContext) + { + this.behaviorContext = behaviorContext; + } + + public void SetCallbackAddress(Address callbackAddress) + { + behaviorContext.Set(SqlServerCallbackAddressContextKey,callbackAddress); + } + + public bool TryGetCallbackAddress(out Address callbackAddress) + { + return behaviorContext.TryGet(SqlServerCallbackAddressContextKey, out callbackAddress); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/PipelineExecutorExtensions.cs b/src/NServiceBus.SqlServer/IConnectionStore.cs similarity index 63% rename from src/NServiceBus.SqlServer/PipelineExecutorExtensions.cs rename to src/NServiceBus.SqlServer/IConnectionStore.cs index d4ed7c3fe..68add005c 100644 --- a/src/NServiceBus.SqlServer/PipelineExecutorExtensions.cs +++ b/src/NServiceBus.SqlServer/IConnectionStore.cs @@ -5,28 +5,43 @@ using Janitor; using NServiceBus.Pipeline; - static class PipelineExecutorExtensions + interface IConnectionStore { - public static bool TryGetTransaction(this PipelineExecutor pipelineExecutor, string connectionString, out SqlTransaction transaction) + bool TryGetTransaction(string connectionString, out SqlTransaction transaction); + bool TryGetConnection(string connectionString, out SqlConnection connection); + IDisposable SetTransaction(string connectionString, SqlTransaction transaction); + IDisposable SetConnection(string connectionString, SqlConnection connection); + } + + class ContextualConnectionStore : IConnectionStore + { + readonly PipelineExecutor pipelineExecutor; + + public ContextualConnectionStore(PipelineExecutor pipelineExecutor) + { + this.pipelineExecutor = pipelineExecutor; + } + + public bool TryGetTransaction(string connectionString, out SqlTransaction transaction) { var key = MakeTransactionKey(connectionString); return pipelineExecutor.CurrentContext.TryGet(key, out transaction); } - public static bool TryGetConnection(this PipelineExecutor pipelineExecutor, string connectionString, out SqlConnection connection) + public bool TryGetConnection(string connectionString, out SqlConnection connection) { var key = MakeConnectionKey(connectionString); return pipelineExecutor.CurrentContext.TryGet(key, out connection); } - public static IDisposable SetTransaction(this PipelineExecutor pipelineExecutor, string connectionString, SqlTransaction transaction) + public IDisposable SetTransaction(string connectionString, SqlTransaction transaction) { var key = MakeTransactionKey(connectionString); pipelineExecutor.CurrentContext.Set(key, transaction); return new ContextItemRemovalDisposable(key, pipelineExecutor); } - public static IDisposable SetConnection(this PipelineExecutor pipelineExecutor, string connectionString, SqlConnection connection) + public IDisposable SetConnection(string connectionString, SqlConnection connection) { var key = MakeConnectionKey(connectionString); pipelineExecutor.CurrentContext.Set(key, connection); diff --git a/src/NServiceBus.SqlServer/IConnectionStringProvider.cs b/src/NServiceBus.SqlServer/IConnectionStringProvider.cs index 3fe4489c1..cc978fd09 100644 --- a/src/NServiceBus.SqlServer/IConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/IConnectionStringProvider.cs @@ -3,5 +3,6 @@ interface IConnectionStringProvider { ConnectionParams GetForDestination(Address destination); + bool AllowsNonLocalConnectionString { get; } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/ITaskTracker.cs b/src/NServiceBus.SqlServer/ITaskTracker.cs deleted file mode 100644 index 538ea9297..000000000 --- a/src/NServiceBus.SqlServer/ITaskTracker.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace NServiceBus.Transports.SQLServer -{ - using System; - using System.Threading.Tasks; - - interface ITaskTracker - { - void StartAndTrack(Func> taskFactory); - void Forget(Guid id); - bool ShouldStartAnotherTaskImmediately { get; } - void ShutdownAll(); - } -} \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/NServiceBus.SqlServer.csproj b/src/NServiceBus.SqlServer/NServiceBus.SqlServer.csproj index f0d713873..cbca3c838 100644 --- a/src/NServiceBus.SqlServer/NServiceBus.SqlServer.csproj +++ b/src/NServiceBus.SqlServer/NServiceBus.SqlServer.csproj @@ -67,9 +67,11 @@ - + - + + + @@ -77,6 +79,8 @@ + + @@ -91,7 +95,6 @@ - @@ -99,16 +102,17 @@ - + - + + diff --git a/src/NServiceBus.SqlServer/NativeTransactionReceiveStrategy.cs b/src/NServiceBus.SqlServer/NativeTransactionReceiveStrategy.cs index 478ead264..2f155e0d2 100644 --- a/src/NServiceBus.SqlServer/NativeTransactionReceiveStrategy.cs +++ b/src/NServiceBus.SqlServer/NativeTransactionReceiveStrategy.cs @@ -2,37 +2,36 @@ namespace NServiceBus.Transports.SQLServer { using System; using System.Data; - using System.Data.SqlClient; - using NServiceBus.Pipeline; using NServiceBus.Unicast.Transport; class NativeTransactionReceiveStrategy : IReceiveStrategy { - readonly PipelineExecutor pipelineExecutor; readonly string connectionString; readonly TableBasedQueue errorQueue; readonly Func tryProcessMessageCallback; readonly IsolationLevel isolationLevel; + readonly ConnectionFactory sqlConnectionFactory; + readonly IConnectionStore connectionStore; - public NativeTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback, PipelineExecutor pipelineExecutor, TransactionSettings transactionSettings) + public NativeTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback, ConnectionFactory sqlConnectionFactory, IConnectionStore connectionStore, TransactionSettings transactionSettings) { - this.pipelineExecutor = pipelineExecutor; this.tryProcessMessageCallback = tryProcessMessageCallback; this.errorQueue = errorQueue; this.connectionString = connectionString; + this.sqlConnectionFactory = sqlConnectionFactory; + this.connectionStore = connectionStore; isolationLevel = GetSqlIsolationLevel(transactionSettings.IsolationLevel); } public ReceiveResult TryReceiveFrom(TableBasedQueue queue) { - using (var connection = new SqlConnection(connectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionString)) { - connection.Open(); - using (pipelineExecutor.SetConnection(connectionString, connection)) + using (connectionStore.SetConnection(connectionString, connection)) { using (var transaction = connection.BeginTransaction(isolationLevel)) { - using (pipelineExecutor.SetTransaction(connectionString, transaction)) + using (connectionStore.SetTransaction(connectionString, transaction)) { MessageReadResult readResult; try diff --git a/src/NServiceBus.SqlServer/NoTransactionReceiveStrategy.cs b/src/NServiceBus.SqlServer/NoTransactionReceiveStrategy.cs index cd2cf8ae8..9f2beacb2 100644 --- a/src/NServiceBus.SqlServer/NoTransactionReceiveStrategy.cs +++ b/src/NServiceBus.SqlServer/NoTransactionReceiveStrategy.cs @@ -1,27 +1,27 @@ namespace NServiceBus.Transports.SQLServer { using System; - using System.Data.SqlClient; class NoTransactionReceiveStrategy : IReceiveStrategy { readonly string connectionString; readonly TableBasedQueue errorQueue; readonly Func tryProcessMessageCallback; + readonly ConnectionFactory sqlConnectionFactory; - public NoTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback) + public NoTransactionReceiveStrategy(string connectionString, TableBasedQueue errorQueue, Func tryProcessMessageCallback, ConnectionFactory sqlConnectionFactory) { this.connectionString = connectionString; this.errorQueue = errorQueue; this.tryProcessMessageCallback = tryProcessMessageCallback; + this.sqlConnectionFactory = sqlConnectionFactory; } public ReceiveResult TryReceiveFrom(TableBasedQueue queue) { MessageReadResult readResult; - using (var connection = new SqlConnection(connectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionString)) { - connection.Open(); readResult = queue.TryReceive(connection); if (readResult.IsPoison) { diff --git a/src/NServiceBus.SqlServer/NullConnectionStringProvider.cs b/src/NServiceBus.SqlServer/NullConnectionStringProvider.cs index 1e45d87ac..3a9138dc9 100644 --- a/src/NServiceBus.SqlServer/NullConnectionStringProvider.cs +++ b/src/NServiceBus.SqlServer/NullConnectionStringProvider.cs @@ -6,5 +6,7 @@ public ConnectionParams GetForDestination(Address destination) { return null; } + + public bool AllowsNonLocalConnectionString { get { return false; } } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/QueuePurger.cs b/src/NServiceBus.SqlServer/QueuePurger.cs index 687848ef2..f638bad02 100644 --- a/src/NServiceBus.SqlServer/QueuePurger.cs +++ b/src/NServiceBus.SqlServer/QueuePurger.cs @@ -9,11 +9,13 @@ namespace NServiceBus.Transports.SQLServer class QueuePurger : IQueuePurger { readonly LocalConnectionParams localConnectionParams; + readonly ConnectionFactory sqlConnectionFactory; - public QueuePurger(SecondaryReceiveConfiguration secondaryReceiveConfiguration, LocalConnectionParams localConnectionParams) + public QueuePurger(SecondaryReceiveConfiguration secondaryReceiveConfiguration, LocalConnectionParams localConnectionParams, ConnectionFactory sqlConnectionFactory) { this.secondaryReceiveConfiguration = secondaryReceiveConfiguration; this.localConnectionParams = localConnectionParams; + this.sqlConnectionFactory = sqlConnectionFactory; } public void Purge(Address address) @@ -23,10 +25,8 @@ public void Purge(Address address) void Purge(IEnumerable tableNames) { - using (var connection = new SqlConnection(localConnectionParams.ConnectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(localConnectionParams.ConnectionString)) { - connection.Open(); - foreach (var tableName in tableNames) { using (var command = new SqlCommand(string.Format(SqlPurge, localConnectionParams.Schema, tableName), connection) diff --git a/src/NServiceBus.SqlServer/ReadIncomingCallbackAddressBehavior.cs b/src/NServiceBus.SqlServer/ReadIncomingCallbackAddressBehavior.cs index 73d797d3b..009c9885e 100644 --- a/src/NServiceBus.SqlServer/ReadIncomingCallbackAddressBehavior.cs +++ b/src/NServiceBus.SqlServer/ReadIncomingCallbackAddressBehavior.cs @@ -12,7 +12,7 @@ public void Invoke(IncomingContext context, Action next) string incomingCallbackQueue; if (context.IncomingLogicalMessage != null && context.IncomingLogicalMessage.Headers.TryGetValue(CallbackConfig.CallbackHeaderKey, out incomingCallbackQueue)) { - context.SetCallbackAddress(Address.Parse(incomingCallbackQueue)); + new ContextualCallbackAddressStore(context).SetCallbackAddress(Address.Parse(incomingCallbackQueue)); } next(); } diff --git a/src/NServiceBus.SqlServer/ReceiveRampUpController.cs b/src/NServiceBus.SqlServer/ReceiveRampUpController.cs index 27b5a46ed..ddd00205e 100644 --- a/src/NServiceBus.SqlServer/ReceiveRampUpController.cs +++ b/src/NServiceBus.SqlServer/ReceiveRampUpController.cs @@ -9,12 +9,16 @@ class ReceiveRampUpController : IRampUpController readonly Action rampUpCallback; readonly TransportNotifications transportNotifications; readonly string queueName; + int maximumConsecutiveFailures; + int minimumConsecutiveSuccesses; - public ReceiveRampUpController(Action rampUpCallback, TransportNotifications transportNotifications, string queueName) + public ReceiveRampUpController(Action rampUpCallback, TransportNotifications transportNotifications, string queueName, int maximumConsecutiveFailures, int minimumConsecutiveSuccesses) { this.rampUpCallback = rampUpCallback; this.transportNotifications = transportNotifications; this.queueName = queueName; + this.maximumConsecutiveFailures = maximumConsecutiveFailures; + this.minimumConsecutiveSuccesses = minimumConsecutiveSuccesses; } public void Succeeded() @@ -31,7 +35,7 @@ public void Failed() public bool CheckHasEnoughWork() { - var result = consecutiveFailures < 7; + var result = consecutiveFailures < maximumConsecutiveFailures; if (!result) { transportNotifications.InvokeTooLittleWork(queueName); @@ -52,7 +56,7 @@ public void RampUpIfTooMuchWork() private bool HasTooMuchWork { - get { return consecutiveSuccesses > 5; } + get { return consecutiveSuccesses > minimumConsecutiveSuccesses; } } } diff --git a/src/NServiceBus.SqlServer/ReceiveStrategyFactory.cs b/src/NServiceBus.SqlServer/ReceiveStrategyFactory.cs index 34831a2d2..49b60a456 100644 --- a/src/NServiceBus.SqlServer/ReceiveStrategyFactory.cs +++ b/src/NServiceBus.SqlServer/ReceiveStrategyFactory.cs @@ -1,34 +1,36 @@ namespace NServiceBus.Transports.SQLServer { using System; - using NServiceBus.Pipeline; using NServiceBus.Unicast.Transport; class ReceiveStrategyFactory { - readonly PipelineExecutor pipelineExecutor; + readonly IConnectionStore connectionStore; readonly Address errorQueueAddress; readonly LocalConnectionParams localConnectionParams; + readonly ConnectionFactory sqlConnectionFactory; - public ReceiveStrategyFactory(PipelineExecutor pipelineExecutor, LocalConnectionParams localConnectionParams, Address errorQueueAddress) + public ReceiveStrategyFactory(IConnectionStore connectionStore, LocalConnectionParams localConnectionParams, Address errorQueueAddress, ConnectionFactory sqlConnectionFactory) { - this.pipelineExecutor = pipelineExecutor; + this.connectionStore = connectionStore; this.errorQueueAddress = errorQueueAddress; this.localConnectionParams = localConnectionParams; + this.sqlConnectionFactory = sqlConnectionFactory; } public IReceiveStrategy Create(TransactionSettings settings, Func tryProcessMessageCallback) { var errorQueue = new TableBasedQueue(errorQueueAddress, localConnectionParams.Schema); + if (settings.IsTransactional) { if (settings.SuppressDistributedTransactions) { - return new NativeTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback, pipelineExecutor, settings); + return new NativeTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback, sqlConnectionFactory, connectionStore, settings); } - return new AmbientTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback, pipelineExecutor, settings); + return new AmbientTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback, sqlConnectionFactory, connectionStore, settings); } - return new NoTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback); + return new NoTransactionReceiveStrategy(localConnectionParams.ConnectionString, errorQueue, tryProcessMessageCallback, sqlConnectionFactory); } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/SqlServerMessageSender.cs b/src/NServiceBus.SqlServer/SqlServerMessageSender.cs index 4d2c48e64..3e648bf36 100644 --- a/src/NServiceBus.SqlServer/SqlServerMessageSender.cs +++ b/src/NServiceBus.SqlServer/SqlServerMessageSender.cs @@ -3,19 +3,22 @@ using System; using System.Data.SqlClient; using System.Transactions; - using Pipeline; using Unicast; using Unicast.Queuing; class SqlServerMessageSender : ISendMessages { readonly IConnectionStringProvider connectionStringProvider; - readonly PipelineExecutor pipelineExecutor; + readonly IConnectionStore connectionStore; + readonly ICallbackAddressStore callbackAddressStore; + readonly ConnectionFactory sqlConnectionFactory; - public SqlServerMessageSender(IConnectionStringProvider connectionStringProvider, PipelineExecutor pipelineExecutor) + public SqlServerMessageSender(IConnectionStringProvider connectionStringProvider, IConnectionStore connectionStore, ICallbackAddressStore callbackAddressStore, ConnectionFactory sqlConnectionFactory) { this.connectionStringProvider = connectionStringProvider; - this.pipelineExecutor = pipelineExecutor; + this.connectionStore = connectionStore; + this.callbackAddressStore = callbackAddressStore; + this.sqlConnectionFactory = sqlConnectionFactory; } public void Send(TransportMessage message, SendOptions sendOptions) @@ -30,22 +33,21 @@ public void Send(TransportMessage message, SendOptions sendOptions) if (sendOptions.EnlistInReceiveTransaction) { SqlTransaction currentTransaction; - if (pipelineExecutor.TryGetTransaction(connectionInfo.ConnectionString, out currentTransaction)) + if (connectionStore.TryGetTransaction(connectionInfo.ConnectionString, out currentTransaction)) { queue.Send(message, sendOptions, currentTransaction.Connection, currentTransaction); } else { SqlConnection currentConnection; - if (pipelineExecutor.TryGetConnection(connectionInfo.ConnectionString, out currentConnection)) + if (connectionStore.TryGetConnection(connectionInfo.ConnectionString, out currentConnection)) { queue.Send(message, sendOptions, currentConnection); } else { - using (var connection = new SqlConnection(connectionInfo.ConnectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionInfo.ConnectionString)) { - connection.Open(); queue.Send(message, sendOptions, connection); } } @@ -56,9 +58,8 @@ public void Send(TransportMessage message, SendOptions sendOptions) // Suppress so that even if DTC is on, we won't escalate using (var tx = new TransactionScope(TransactionScopeOption.Suppress)) { - using (var connection = new SqlConnection(connectionInfo.ConnectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionInfo.ConnectionString)) { - connection.Open(); queue.Send(message, sendOptions, connection); } @@ -102,9 +103,14 @@ static Address SenderProvidedDestination(SendOptions sendOptions) Address RequestorProvidedCallbackAddress(SendOptions sendOptions) { - return IsReply(sendOptions) - ? pipelineExecutor.CurrentContext.TryGetCallbackAddress() - : null; + if (IsReply(sendOptions)) + { + Address callbackAddress; + callbackAddressStore.TryGetCallbackAddress(out callbackAddress); + return callbackAddress; + } + + return null; } static bool IsReply(SendOptions sendOptions) diff --git a/src/NServiceBus.SqlServer/SqlServerQueueCreator.cs b/src/NServiceBus.SqlServer/SqlServerQueueCreator.cs index 85df1ca52..150c37575 100644 --- a/src/NServiceBus.SqlServer/SqlServerQueueCreator.cs +++ b/src/NServiceBus.SqlServer/SqlServerQueueCreator.cs @@ -29,10 +29,9 @@ [RowVersion] ASC public void CreateQueueIfNecessary(Address address, string account) { var connectionParams = connectionStringProvider.GetForDestination(address); - using (var connection = new SqlConnection(connectionParams.ConnectionString)) + using (var connection = sqlConnectionFactory.OpenNewConnection(connectionParams.ConnectionString)) { var sql = string.Format(Ddl, connectionParams.Schema, address.GetTableName()); - connection.Open(); using (var command = new SqlCommand(sql, connection) {CommandType = CommandType.Text}) { @@ -42,10 +41,12 @@ public void CreateQueueIfNecessary(Address address, string account) } readonly IConnectionStringProvider connectionStringProvider; + readonly ConnectionFactory sqlConnectionFactory; - public SqlServerQueueCreator(IConnectionStringProvider connectionStringProvider) + public SqlServerQueueCreator(IConnectionStringProvider connectionStringProvider, ConnectionFactory sqlConnectionFactory) { this.connectionStringProvider = connectionStringProvider; + this.sqlConnectionFactory = sqlConnectionFactory; } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/SqlServerSettingsExtensions.cs b/src/NServiceBus.SqlServer/SqlServerSettingsExtensions.cs index d0531eb68..bd3ce3fa0 100644 --- a/src/NServiceBus.SqlServer/SqlServerSettingsExtensions.cs +++ b/src/NServiceBus.SqlServer/SqlServerSettingsExtensions.cs @@ -2,6 +2,8 @@ { using System; using System.Collections.Generic; + using System.Data.SqlClient; + using System.Linq; using Configuration.AdvanceExtensibility; using NServiceBus.Transports.SQLServer; using NServiceBus.Transports.SQLServer.Config; @@ -60,7 +62,7 @@ public static TransportExtensions UseSpecificConnectionInfor { throw new InvalidOperationException("Per-endpoint connection information can be specified only once, either by passing a collection or a callback."); } - transportExtensions.GetSettings().Set(ConnectionConfig.PerEndpointConnectionStringsCollectionSettingKey, connectionInformationCollection); + transportExtensions.GetSettings().Set(ConnectionConfig.PerEndpointConnectionStringsCollectionSettingKey, connectionInformationCollection.ToArray()); return transportExtensions; } @@ -140,5 +142,17 @@ public static TransportExtensions PauseAfterReceiveFailure(t transportExtensions.GetSettings().Set(CircuitBreakerConfig.CircuitBreakerDelayAfterFailureSettingsKey, pauseTime); return transportExtensions; } + + /// + /// Overrides the default time SQL Connections factory. + /// + /// + /// Factory for creating and opening new SQL Connections. + /// + public static TransportExtensions UseCustomSqlConnectionFactory(this TransportExtensions transportExtensions, Func sqlConnectionFactory) + { + transportExtensions.GetSettings().Set(SqlConnectionFactoryConfig.CustomSqlConnectionFactorySettingKey, new ConnectionFactory(sqlConnectionFactory)); + return transportExtensions; + } } } \ No newline at end of file diff --git a/src/NServiceBus.SqlServer/SqlServerStorageContext.cs b/src/NServiceBus.SqlServer/SqlServerStorageContext.cs index 12feb2329..da4ccc48e 100644 --- a/src/NServiceBus.SqlServer/SqlServerStorageContext.cs +++ b/src/NServiceBus.SqlServer/SqlServerStorageContext.cs @@ -26,7 +26,7 @@ public IDbConnection Connection get { SqlConnection connection; - return pipelineExecutor.TryGetConnection(localConnectionParams.ConnectionString, out connection) + return new ContextualConnectionStore(pipelineExecutor).TryGetConnection(localConnectionParams.ConnectionString, out connection) ? connection : null; } @@ -40,7 +40,7 @@ public SqlTransaction Transaction get { SqlTransaction transaction; - return pipelineExecutor.TryGetTransaction(localConnectionParams.ConnectionString, out transaction) + return new ContextualConnectionStore(pipelineExecutor).TryGetTransaction(localConnectionParams.ConnectionString, out transaction) ? transaction : null; } diff --git a/src/NServiceBus.SqlServer/ReceiveTaskTracker.cs b/src/NServiceBus.SqlServer/TaskTracker.cs similarity index 65% rename from src/NServiceBus.SqlServer/ReceiveTaskTracker.cs rename to src/NServiceBus.SqlServer/TaskTracker.cs index bf875115f..0bf7ab518 100644 --- a/src/NServiceBus.SqlServer/ReceiveTaskTracker.cs +++ b/src/NServiceBus.SqlServer/TaskTracker.cs @@ -6,40 +6,40 @@ using System.Threading.Tasks; using NServiceBus.Logging; - class ReceiveTaskTracker : ITaskTracker + class TaskTracker { - public ReceiveTaskTracker(int maximumConcurrency, TransportNotifications transportNotifications, string queueName) + public TaskTracker(int maximumConcurrency, TransportNotifications transportNotifications, string executorName) { this.maximumConcurrency = maximumConcurrency; this.transportNotifications = transportNotifications; - this.queueName = queueName; + this.executorName = executorName; } - public void StartAndTrack(Func> taskFactory) + public void StartAndTrack(Func> taskFactory) { lock (lockObj) { if (shuttingDown) { - Logger.DebugFormat("Ignoring start task request for '{0}' because shutdown is in progress.", queueName); + Logger.DebugFormat("Ignoring start task request for '{0}' because shutdown is in progress.", executorName); return; } if (trackedTasks.Count >= maximumConcurrency) { if (Logger.IsDebugEnabled) { - Logger.DebugFormat("Ignoring start task request for '{0}' because of maximum concurrency limit of {1} has been reached.", queueName, maximumConcurrency); + Logger.DebugFormat("Ignoring start task request for '{0}' because of maximum concurrency limit of {1} has been reached.", executorName, maximumConcurrency); } - transportNotifications.InvokeMaximumConcurrencyLevelReached(queueName, maximumConcurrency); + transportNotifications.InvokeMaximumConcurrencyLevelReached(executorName, maximumConcurrency); return; } var tuple = taskFactory(); - trackedTasks.Add(tuple.Item1, tuple.Item2); + trackedTasks.Add(tuple.Item1, Tuple.Create(tuple.Item2, tuple.Item3)); if (Logger.IsDebugEnabled) { - Logger.DebugFormat("Starting a new receive task for '{0}'. Total count current/max {1}/{2}", queueName, trackedTasks.Count, maximumConcurrency); + Logger.DebugFormat("Starting a new receive task for '{0}'. Total count current/max {1}/{2}", executorName, trackedTasks.Count, maximumConcurrency); } - transportNotifications.InvokeReceiveTaskStarted(queueName, trackedTasks.Count, maximumConcurrency); + transportNotifications.InvokeReceiveTaskStarted(executorName, trackedTasks.Count, maximumConcurrency); } } @@ -56,13 +56,21 @@ public void Forget(Guid id) { if (Logger.IsDebugEnabled) { - Logger.DebugFormat("Stopping a receive task for '{0}'. Total count current/max {1}/{2}", queueName, trackedTasks.Count, maximumConcurrency); + Logger.DebugFormat("Stopping a receive task for '{0}'. Total count current/max {1}/{2}", executorName, trackedTasks.Count, maximumConcurrency); } - transportNotifications.InvokeReceiveTaskStopped(queueName, trackedTasks.Count, maximumConcurrency); + transportNotifications.InvokeReceiveTaskStopped(executorName, trackedTasks.Count, maximumConcurrency); } } } + public IEnumerable GetTaskStates() + { + lock (lockObj) + { + return trackedTasks.Values.Select(x => x.Item2).ToArray(); + } + } + public bool ShouldStartAnotherTaskImmediately { get @@ -82,14 +90,14 @@ public void ShutdownAll() { if (Logger.IsDebugEnabled) { - Logger.Debug("Stopping all receive tasks."); + Logger.Debug("Stopping all tasks."); } lock (lockObj) { shuttingDown = true; try { - Task.WaitAll(trackedTasks.Values.ToArray()); + Task.WaitAll(trackedTasks.Values.Select(x => x.Item1).ToArray()); } catch (AggregateException aex) { @@ -99,12 +107,12 @@ public void ShutdownAll() } readonly object lockObj = new object(); - readonly Dictionary trackedTasks = new Dictionary(); + readonly Dictionary> trackedTasks = new Dictionary>(); bool shuttingDown; readonly int maximumConcurrency; readonly TransportNotifications transportNotifications; - readonly string queueName; + readonly string executorName; - static readonly ILog Logger = LogManager.GetLogger(); + static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/Scripts/Reset-Database.sql b/src/Scripts/Reset-Database.sql index dd9451aed..9c4ac84c6 100644 --- a/src/Scripts/Reset-Database.sql +++ b/src/Scripts/Reset-Database.sql @@ -87,15 +87,36 @@ GO /* Drop all tables */ DECLARE @name VARCHAR(128) +DECLARE @schema VARCHAR(128) DECLARE @SQL VARCHAR(254) -SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name]) +SELECT TOP 1 @name = sys.objects.name, @schema = sys.schemas.name FROM sys.objects INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id WHERE [type] = 'U' ORDER BY sys.objects.name WHILE @name IS NOT NULL BEGIN - SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']' + SELECT @SQL = 'DROP TABLE [' + @schema + '].[' + RTRIM(@name) +']' EXEC (@SQL) - PRINT 'Dropped Table: ' + @name - SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name]) + PRINT 'Dropped Table: ' + @schema + '.' + @name + SELECT @name = NULL + SELECT TOP 1 @name = sys.objects.name, @schema = sys.schemas.name FROM sys.objects INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id WHERE [type] = 'U' ORDER BY sys.objects.name END -GO \ No newline at end of file +GO + +/* Create schemas */ +IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'nsb') +BEGIN + EXEC('CREATE SCHEMA nsb') +END +GO + +IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'sender') +BEGIN + EXEC('CREATE SCHEMA sender') +END +GO + +IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'receiver') +BEGIN + EXEC('CREATE SCHEMA receiver') +END +GO