From 6c2f7f8e4c77ffc003ebdf2a96f0a5da74e5a9bc Mon Sep 17 00:00:00 2001 From: Rhys Parry Date: Tue, 5 May 2026 23:37:29 +0000 Subject: [PATCH] Fix race condition in ObserveUnauthorizedPollingConnections test The polling service begins connecting immediately when Build() returns, so calling TrustOnly(empty) afterwards left a window where the first connection could be authorized before trust was revoked. Move the no-trust configuration into the builder so the client's trust list is empty before the service starts polling, eliminating the race entirely. Co-Authored-By: Claude Sonnet 4.6 --- .../Support/LatestClientAndLatestServiceBuilder.cs | 6 ++++++ .../Halibut.Tests/Support/LatestClientBuilder.cs | 14 ++++++++++++-- .../Observability/ConnectionObserverFixture.cs | 3 +-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/source/Halibut.Tests/Support/LatestClientAndLatestServiceBuilder.cs b/source/Halibut.Tests/Support/LatestClientAndLatestServiceBuilder.cs index b1d37fd0d..b9f043b71 100644 --- a/source/Halibut.Tests/Support/LatestClientAndLatestServiceBuilder.cs +++ b/source/Halibut.Tests/Support/LatestClientAndLatestServiceBuilder.cs @@ -297,6 +297,12 @@ public LatestClientAndLatestServiceBuilder WithClientTrustingTheWrongCertificate return this; } + public LatestClientAndLatestServiceBuilder WithClientTrustingNoThumbprints() + { + clientBuilder.WithClientTrustingNoThumbprints(); + return this; + } + public LatestClientAndLatestServiceBuilder WithServiceTrustingTheWrongCertificate() { serviceBuilder.WithServiceTrustingTheWrongCertificate(); diff --git a/source/Halibut.Tests/Support/LatestClientBuilder.cs b/source/Halibut.Tests/Support/LatestClientBuilder.cs index eff387b75..1de31111f 100644 --- a/source/Halibut.Tests/Support/LatestClientBuilder.cs +++ b/source/Halibut.Tests/Support/LatestClientBuilder.cs @@ -24,7 +24,8 @@ public class LatestClientBuilder : IClientBuilder CertAndThumbprint clientCertAndThumbprint; readonly PollingQueueTestCase? pollingQueueTestCase; - string clientTrustsThumbprint; + string clientTrustsThumbprint; + bool clientTrustsNoThumbprints; IRpcObserver? clientRpcObserver; Func? portForwarderFactory; Reference? portForwarderReference; @@ -181,6 +182,12 @@ public LatestClientBuilder WithClientTrustingTheWrongCertificate() clientTrustsThumbprint = CertAndThumbprint.Wrong.Thumbprint; return this; } + + public LatestClientBuilder WithClientTrustingNoThumbprints() + { + clientTrustsNoThumbprints = true; + return this; + } public LatestClientBuilder WithClientRpcObserver(IRpcObserver? clientRpcObserver) { @@ -215,7 +222,10 @@ public async Task Build(CancellationToken cancellationToken) } var client = clientBuilder.Build(); - client.Trust(clientTrustsThumbprint); + if (!clientTrustsNoThumbprints) + { + client.Trust(clientTrustsThumbprint); + } var disposableCollection = new DisposableCollection(); PortForwarder? portForwarder = null; diff --git a/source/Halibut.Tests/Transport/Observability/ConnectionObserverFixture.cs b/source/Halibut.Tests/Transport/Observability/ConnectionObserverFixture.cs index 426c342a4..65fd17164 100644 --- a/source/Halibut.Tests/Transport/Observability/ConnectionObserverFixture.cs +++ b/source/Halibut.Tests/Transport/Observability/ConnectionObserverFixture.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using FluentAssertions; @@ -83,10 +82,10 @@ public async Task ObserveUnauthorizedPollingConnections(ClientAndServiceTestCase await using (var clientAndBuilder = await clientAndServiceTestCase.CreateTestCaseBuilder() .WithStandardServices() .AsLatestClientAndLatestServiceBuilder() + .WithClientTrustingNoThumbprints() .WithConnectionObserverOnTcpServer(connectionsObserver) .Build(CancellationToken)) { - clientAndBuilder.Client.TrustOnly(new List()); using var cts = new CancellationTokenSource(); var token = cts.Token;