From 5108076003242ee05dba2acc0d781bb0eb0a12f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Sat, 26 Sep 2026 16:04:35 +0200 Subject: [PATCH 1/4] test(integration): run SQL Server 2025 CU9 on the ubuntu-22.04 base The fixture used the stale 2025-RTM-ubuntu-24.04-preview image. SQL Server 2025 images on the ubuntu-24.04 base crash intermittently during startup with a sqlpal/LSASS fatal error (Reason 0x00000002, errno 11), more often when several containers start at once (microsoft/mssql-docker#974). Integration tests start one container per target framework concurrently, so a single crash failed every SQL Server test of that TFM. Switch to 2025-CU9-ubuntu-22.04, which is not affected. --- .../Internals/Services/SqlServerContainerFixture.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs b/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs index 0f218834..851ab278 100644 --- a/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs +++ b/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs @@ -6,8 +6,10 @@ public sealed class SqlServerContainerFixture : IAsyncDisposable, IAsyncInitializer { + // Stay on the ubuntu-22.04 base: the SQL Server 2025 ubuntu-24.04 images crash intermittently during + // startup (sqlpal/LSASS fatal error), see https://github.com/microsoft/mssql-docker/issues/974. private readonly MsSqlContainer _container = new MsSqlBuilder( - /*dockerimage*/"mcr.microsoft.com/mssql/server:2025-RTM-ubuntu-24.04-preview" + /*dockerimage*/"mcr.microsoft.com/mssql/server:2025-CU9-ubuntu-22.04" ) .WithLogger(NullLogger.Instance) .Build(); From 00aa0dfa1c34d830023b0bffb6bf70585f7bb916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Sat, 26 Sep 2026 16:04:35 +0200 Subject: [PATCH 2/4] chore(renovate): track SQL Server CU tags with regex versioning Loose docker versioning could not move the 2025-RTM-ubuntu-24.04-preview tag to any GA cumulative update. Use regex versioning for mcr.microsoft.com/mssql/server so CU and GDR releases are proposed on the same Ubuntu base while preview, RC and CTP tags are ignored. --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/renovate.json b/renovate.json index f52ce837..54c9a03f 100644 --- a/renovate.json +++ b/renovate.json @@ -61,6 +61,12 @@ "semanticCommitScope": "docker", "versioning": "loose" }, + { + "description": "Track SQL Server CU/GDR releases on the ubuntu-22.04 base only; preview/RC/CTP tags never match. See microsoft/mssql-docker#974.", + "matchDatasources": ["docker"], + "matchPackageNames": ["mcr.microsoft.com/mssql/server"], + "versioning": "regex:^(?\\d+)-CU(?\\d+)(-GDR(?\\d+))?-ubuntu-(?\\d+\\.\\d+)$" + }, { "groupName": "Testcontainers packages", "groupSlug": "testcontainers-packages", From b113f215d53eb0e3f2e0b9456a4b7927ea49a711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Sat, 26 Sep 2026 16:38:01 +0200 Subject: [PATCH 3/4] test(rabbitmq): keep the integration test exchange alive between tests TUnit creates a new test class instance per test, so each test opens its own connection and exclusive queue. The exchange was declared auto-delete; closing the previous test's connection removed its queue binding and the broker deleted the exchange asynchronously, sometimes after the next test's idempotent ExchangeDeclare, so its QueueBind failed with 404 NOT_FOUND. Declare the exchange without auto-delete; it lives only as long as the per-session container. --- .../RabbitMQ/RabbitMqMessageTransportIntegrationTests.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/NetEvolve.Pulse.Tests.Integration/RabbitMQ/RabbitMqMessageTransportIntegrationTests.cs b/tests/NetEvolve.Pulse.Tests.Integration/RabbitMQ/RabbitMqMessageTransportIntegrationTests.cs index e32e1945..be36f3ba 100644 --- a/tests/NetEvolve.Pulse.Tests.Integration/RabbitMQ/RabbitMqMessageTransportIntegrationTests.cs +++ b/tests/NetEvolve.Pulse.Tests.Integration/RabbitMQ/RabbitMqMessageTransportIntegrationTests.cs @@ -49,7 +49,10 @@ await _adminChannel ExchangeName, ExchangeType.Fanout, durable: false, - autoDelete: true, + // Not auto-delete: each test gets its own instance and connection, and closing the previous + // one removes its exclusive queue's binding, which would asynchronously delete the exchange + // between this declare and the next test's QueueBind (404 NOT_FOUND). + autoDelete: false, cancellationToken: cancellationToken ) .ConfigureAwait(false); From b9456a2b74098cb353c4777f8f98482b22e13890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Sat, 26 Sep 2026 19:06:03 +0200 Subject: [PATCH 4/4] test(integration): replace a SQL Server container that crashes during startup The ubuntu-22.04 base did not avoid the intermittent SQL Server 2025 startup crash (sqlpal/LSASS fatal error, Reason 0x00000002). Run 36255943687 hit it again on 2025-CU9-ubuntu-22.04 and failed all 133 SQL Server tests on net10.0. When a container exits before it is ready, dispose it and start a fresh one, up to 3 attempts. Each retry is written to stderr and, on GitHub Actions, to the job summary so the crash rate stays visible. A crash on the last attempt still fails the tests with the container output. Refs: microsoft/mssql-docker#974 --- .../Services/SqlServerContainerFixture.cs | 72 ++++++++++++++++--- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs b/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs index 851ab278..7dab8f14 100644 --- a/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs +++ b/tests/NetEvolve.Pulse.Tests.Integration/Internals/Services/SqlServerContainerFixture.cs @@ -1,22 +1,74 @@ namespace NetEvolve.Pulse.Tests.Integration.Internals; +using DotNet.Testcontainers.Containers; using Microsoft.Extensions.Logging.Abstractions; using Testcontainers.MsSql; using TUnit.Core.Interfaces; public sealed class SqlServerContainerFixture : IAsyncDisposable, IAsyncInitializer { - // Stay on the ubuntu-22.04 base: the SQL Server 2025 ubuntu-24.04 images crash intermittently during - // startup (sqlpal/LSASS fatal error), see https://github.com/microsoft/mssql-docker/issues/974. - private readonly MsSqlContainer _container = new MsSqlBuilder( - /*dockerimage*/"mcr.microsoft.com/mssql/server:2025-CU9-ubuntu-22.04" - ) - .WithLogger(NullLogger.Instance) - .Build(); + // SQL Server 2025 containers crash intermittently during startup (sqlpal/LSASS fatal error, Reason 0x00000002), + // more often when several start concurrently, as they do here (one per target framework). This happens on the + // ubuntu-24.04 and the ubuntu-22.04 base, see https://github.com/microsoft/mssql-docker/issues/974. A crashed + // container is replaced by a fresh one (bounded), and every retry is reported. + private const int MaxStartAttempts = 3; - public string ConnectionString => _container.GetConnectionString() + ";MultipleActiveResultSets=True;"; + private MsSqlContainer? _container; - public ValueTask DisposeAsync() => _container.DisposeAsync(); + public string ConnectionString => + ( + _container ?? throw new InvalidOperationException("The SQL Server container has not been started.") + ).GetConnectionString() + ";MultipleActiveResultSets=True;"; - public async Task InitializeAsync() => await _container.StartAsync().ConfigureAwait(false); + public ValueTask DisposeAsync() => _container?.DisposeAsync() ?? ValueTask.CompletedTask; + + public async Task InitializeAsync() + { + for (var attempt = 1; attempt < MaxStartAttempts; attempt++) + { + var container = CreateContainer(); + try + { + await container.StartAsync().ConfigureAwait(false); + _container = container; + return; + } + catch (ContainerNotRunningException ex) + { + await ReportCrashAsync(attempt, ex).ConfigureAwait(false); + await container.DisposeAsync().ConfigureAwait(false); + } + } + + // Last attempt: let a further crash fail the tests with the container output. + _container = CreateContainer(); + await _container.StartAsync().ConfigureAwait(false); + } + + // Test output of passing runs is not printed by `dotnet test`, so a retry is also written to the GitHub Actions job + // summary (when running there) to keep the upstream crash rate observable. + private static async Task ReportCrashAsync(int attempt, ContainerNotRunningException ex) + { + var message = + $"[SqlServerContainerFixture] SQL Server container crashed during startup (attempt {attempt}/{MaxStartAttempts}, {TestHelper.TargetFramework}), starting a new one."; + await Console.Error.WriteLineAsync($"{message}{Environment.NewLine}{ex.Message}").ConfigureAwait(false); + + var summary = Environment.GetEnvironmentVariable("GITHUB_STEP_SUMMARY"); + if (!string.IsNullOrEmpty(summary)) + { + await File.AppendAllTextAsync( + summary, + $"> [!WARNING]{Environment.NewLine}> {message}{Environment.NewLine}{Environment.NewLine}" + ) + .ConfigureAwait(false); + } + } + + private static MsSqlContainer CreateContainer() + { + var builder = new MsSqlBuilder( + /*dockerimage*/"mcr.microsoft.com/mssql/server:2025-CU9-ubuntu-22.04" + ); + return builder.WithLogger(NullLogger.Instance).Build(); + } }