From 5059e6542c076fe1664772c9ba302b4499eda4d7 Mon Sep 17 00:00:00 2001 From: afprtclr Date: Tue, 22 Sep 2026 16:35:53 +0200 Subject: [PATCH 1/2] Using spy endpoints for testing for messages to ServiceControl --- .../When_a_new_endpoint_is_detected.cs | 57 +++++++++++++++---- ...importing_a_message_resolved_by_a_retry.cs | 57 ++++++++++++++++--- ...terceptMessagesDestinedToServiceControl.cs | 24 -------- .../InterceptedMessagesScenarioContext.cs | 11 ---- 4 files changed, 95 insertions(+), 54 deletions(-) delete mode 100644 src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptMessagesDestinedToServiceControl.cs delete mode 100644 src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptedMessagesScenarioContext.cs diff --git a/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs b/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs index 1b00fe60b5..3b1c076bb8 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs @@ -1,12 +1,15 @@ namespace ServiceControl.Audit.AcceptanceTests.Monitoring { + using System; + using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; using AcceptanceTesting.EndpointTemplates; using NServiceBus; using NServiceBus.AcceptanceTesting; + using NServiceBus.Pipeline; using NUnit.Framework; - using TestSupport; + using Contracts.EndpointControl; using Conventions = NServiceBus.AcceptanceTesting.Customization.Conventions; class When_a_new_endpoint_is_detected : AcceptanceTest @@ -14,18 +17,15 @@ class When_a_new_endpoint_is_detected : AcceptanceTest [Test] public async Task Should_notify_service_control() { - CustomConfiguration = endpointConfiguration => - { - endpointConfiguration.Pipeline.Register(typeof(InterceptMessagesDestinedToServiceControl), - "Intercepts messages destined to ServiceControl"); - }; + SetSettings = s => s.ServiceControlQueueAddress = Conventions.EndpointNamingConvention(typeof(SpyEndpoint)); - var context = await Define() + var context = await Define() .WithEndpoint(b => b.When((bus, c) => bus.SendLocal(new MyMessage()))) - .Done(c => c.SentRegisterEndpointCommands.Any()) + .WithEndpoint() + .Done(c => c.ReceivedRegisterEndpointCommands.Any()) .Run(); - var command = context.SentRegisterEndpointCommands.Single(); + var command = context.ReceivedRegisterEndpointCommands.Single(); Assert.That(command.Endpoint.Name, Is.EqualTo(Conventions.EndpointNamingConvention(typeof(Receiver)))); } @@ -40,6 +40,43 @@ public class MyMessageHandler : IHandleMessages } } + public class SpyEndpoint : EndpointConfigurationBuilder + { + public SpyEndpoint() => EndpointSetup(c => + c.Pipeline.Register(new IgnoreCustomCheckResultsBehavior(), "Ignores custom check results reported to the spied queue")); + + class IgnoreCustomCheckResultsBehavior : Behavior + { + public override Task Invoke(ITransportReceiveContext context, Func next) + { + if (context.Message.Headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) + && messageTypes.StartsWith(CustomCheckResultType, StringComparison.Ordinal)) + { + return Task.CompletedTask; + } + + return next(); + } + + const string CustomCheckResultType = "ServiceControl.Plugin.CustomChecks.Messages.ReportCustomCheckResult"; + } + + [Handler] + public class RegisterNewEndpointHandler(MyContext testContext) : IHandleMessages + { + public Task Handle(RegisterNewEndpoint message, IMessageHandlerContext context) + { + testContext.ReceivedRegisterEndpointCommands.Add(message); + return Task.CompletedTask; + } + } + } + public class MyMessage : ICommand; + + public class MyContext : ScenarioContext + { + public ConcurrentBag ReceivedRegisterEndpointCommands { get; } = []; + } } -} \ No newline at end of file +} diff --git a/src/ServiceControl.Audit.AcceptanceTests/Recoverability/When_importing_a_message_resolved_by_a_retry.cs b/src/ServiceControl.Audit.AcceptanceTests/Recoverability/When_importing_a_message_resolved_by_a_retry.cs index b839836e8c..f753c4ee29 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/Recoverability/When_importing_a_message_resolved_by_a_retry.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/Recoverability/When_importing_a_message_resolved_by_a_retry.cs @@ -1,6 +1,8 @@ namespace ServiceControl.Audit.AcceptanceTests.Recoverability { using System; + using System.Collections.Concurrent; + using System.Linq; using System.Threading.Tasks; using AcceptanceTesting; using AcceptanceTesting.EndpointTemplates; @@ -8,24 +10,22 @@ using Audit.Monitoring; using NServiceBus; using NServiceBus.AcceptanceTesting; + using NServiceBus.Pipeline; using NUnit.Framework; - using TestSupport; + using Contracts.EndpointControl; + using Conventions = NServiceBus.AcceptanceTesting.Customization.Conventions; class When_importing_a_message_resolved_by_a_retry : AcceptanceTest { [Test] public async Task Should_set_status_to_resolved() { - CustomConfiguration = endpointConfiguration => - { - endpointConfiguration.Pipeline.Register(typeof(InterceptMessagesDestinedToServiceControl), - "Intercepts messages destined to ServiceControl"); - }; + SetSettings = s => s.ServiceControlQueueAddress = Conventions.EndpointNamingConvention(typeof(SpyEndpoint)); MessagesView auditedMessage = null; var messageId = Guid.NewGuid().ToString(); - await Define() + var context = await Define() .WithEndpoint(b => b.When(s => { var options = new SendOptions(); @@ -35,17 +35,19 @@ await Define() options.SetMessageId(messageId); return s.Send(new MyMessage(), options); })) + .WithEndpoint() .Done(async c => { var result = await this.TryGetSingle("/api/messages", m => m.MessageId == messageId); auditedMessage = result; - return result; + return result.HasResult && c.ReceivedRegisterEndpointCommands.Any(); }) .Run(); Assert.That(auditedMessage.Status, Is.EqualTo(MessageStatus.ResolvedSuccessfully)); + Assert.That(context.ReceivedRegisterEndpointCommands, Is.Not.Empty); } public class Receiver : EndpointConfigurationBuilder @@ -59,6 +61,43 @@ public class MyMessageHandler : IHandleMessages } } + public class SpyEndpoint : EndpointConfigurationBuilder + { + public SpyEndpoint() => EndpointSetup(c => + c.Pipeline.Register(new IgnoreCustomCheckResultsBehavior(), "Ignores custom check results reported to the spied queue")); + + class IgnoreCustomCheckResultsBehavior : Behavior + { + public override Task Invoke(ITransportReceiveContext context, Func next) + { + if (context.Message.Headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) + && messageTypes.StartsWith(CustomCheckResultType, StringComparison.Ordinal)) + { + return Task.CompletedTask; + } + + return next(); + } + + const string CustomCheckResultType = "ServiceControl.Plugin.CustomChecks.Messages.ReportCustomCheckResult"; + } + + [Handler] + public class RegisterNewEndpointHandler(MyContext testContext) : IHandleMessages + { + public Task Handle(RegisterNewEndpoint message, IMessageHandlerContext context) + { + testContext.ReceivedRegisterEndpointCommands.Add(message); + return Task.CompletedTask; + } + } + } + public class MyMessage : ICommand; + + public class MyContext : ScenarioContext + { + public ConcurrentBag ReceivedRegisterEndpointCommands { get; } = []; + } } -} \ No newline at end of file +} diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptMessagesDestinedToServiceControl.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptMessagesDestinedToServiceControl.cs deleted file mode 100644 index 9d605d44ca..0000000000 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptMessagesDestinedToServiceControl.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ServiceControl.Audit.AcceptanceTests.TestSupport -{ - using System; - using System.Threading.Tasks; - using Contracts.EndpointControl; - using NServiceBus.AcceptanceTesting; - using NServiceBus.Pipeline; - - class InterceptMessagesDestinedToServiceControl(ScenarioContext scenarioContext) : Behavior - { - public override Task Invoke(IOutgoingLogicalMessageContext context, Func next) - { - var interceptingContext = scenarioContext as InterceptedMessagesScenarioContext; - switch (context.Message.Instance) - { - case RegisterNewEndpoint newEndpoint: - interceptingContext?.SentRegisterEndpointCommands.Add(newEndpoint); - return Task.CompletedTask; - default: - return next(); - } - } - } -} \ No newline at end of file diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptedMessagesScenarioContext.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptedMessagesScenarioContext.cs deleted file mode 100644 index ea94e537d9..0000000000 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/InterceptedMessagesScenarioContext.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ServiceControl.Audit.AcceptanceTests.TestSupport -{ - using System.Collections.Concurrent; - using Contracts.EndpointControl; - using NServiceBus.AcceptanceTesting; - - public class InterceptedMessagesScenarioContext : ScenarioContext - { - public ConcurrentBag SentRegisterEndpointCommands { get; } = []; - } -} \ No newline at end of file From b043a5ed04e4c146ae4ab06b17d3c1733addba4b Mon Sep 17 00:00:00 2001 From: afprtclr Date: Wed, 23 Sep 2026 08:59:09 +0200 Subject: [PATCH 2/2] Renaming collection after PR comment --- .../Monitoring/When_a_new_endpoint_is_detected.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs b/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs index 3b1c076bb8..e0442f9aa0 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/Monitoring/When_a_new_endpoint_is_detected.cs @@ -22,10 +22,10 @@ public async Task Should_notify_service_control() var context = await Define() .WithEndpoint(b => b.When((bus, c) => bus.SendLocal(new MyMessage()))) .WithEndpoint() - .Done(c => c.ReceivedRegisterEndpointCommands.Any()) + .Done(c => c.SentRegisterEndpointCommands.Any()) .Run(); - var command = context.ReceivedRegisterEndpointCommands.Single(); + var command = context.SentRegisterEndpointCommands.Single(); Assert.That(command.Endpoint.Name, Is.EqualTo(Conventions.EndpointNamingConvention(typeof(Receiver)))); } @@ -66,7 +66,7 @@ public class RegisterNewEndpointHandler(MyContext testContext) : IHandleMessages { public Task Handle(RegisterNewEndpoint message, IMessageHandlerContext context) { - testContext.ReceivedRegisterEndpointCommands.Add(message); + testContext.SentRegisterEndpointCommands.Add(message); return Task.CompletedTask; } } @@ -76,7 +76,7 @@ public class MyMessage : ICommand; public class MyContext : ScenarioContext { - public ConcurrentBag ReceivedRegisterEndpointCommands { get; } = []; + public ConcurrentBag SentRegisterEndpointCommands { get; } = []; } } }