d2d4db492b
maxParallelThreads was unset everywhere and only 3 of ~20 test projects carried an xunit.runner.json at all, so xunit ran Environment.ProcessorCount collections at once (14 on the dev box) in every suite. That is the general load multiplier behind the row-82/91/95 flake family. Policy: per-suite caps, NOT a global one. Pure unit suites stay uncapped for speed; a suite gets a config only when a test CLASS costs a real external or OS-level resource, so ProcessorCount of them at once is a resource question rather than a CPU question. Four suites qualify, all capped at maxParallelThreads: 4. - ConfigurationDatabase.Tests, AuditLog.Tests, SiteCallAudit.Tests — verified as the three that actually take MsSqlMigrationFixture (the latter two by project reference). Every MSSQL-backed test class means a CREATE DATABASE plus the ~100-migration chain against the one shared dev SQL Server. 4 is chosen to MATCH the default slot count of row 82's cross-process sp_getapplock migrate semaphore, so the in-process and cross-process limits agree rather than fighting. - Host.Tests — classes boot real ASP.NET Core hosts and real ActorSystems; Akka.Remote binds real sockets, Kestrel binds real ports, gRPC dials them. Threads are capped, collections are NOT serialized. IntegrationTests (parallelizeAssembly/parallelizeTestCollections false) and CentralUI.PlaywrightTests (maxParallelThreads 1) already carry stricter pre-existing settings and are left alone — the Playwright suite drives a browser against a live rig, where shared UI state, not CPU, is the constraint. Each capped csproj gains <Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />; the SDK does not copy it automatically and without it the file is silently ignored. Verified by moving the copied file out of bin/ to take an uncapped baseline: ConfigurationDatabase.Tests ran at 216 % CPU uncapped vs 145 % capped, so the cap demonstrably takes effect. Cost is close to nil — these suites are latency-bound on an external resource, not CPU-bound (14-25 % utilisation for the two slowest). Standalone, uncapped -> capped: AuditLog 383 tests 1m52s -> 1m51s; Host 520 tests 4m05s -> 4m08s; ConfigurationDatabase 396 tests 10s -> 12s; SiteCallAudit 66 tests 8s -> 8s. All green. docs/test_infra/test_infra.md gains a Test Parallelism Policy section: the two axes (in-process collection threads = this cap; cross-process solution-level dotnet test = unbounded in general, bounded on the DB-migration path by the sp_getapplock semaphore), the per-suite table with reasons, the rules (cap threads rather than serialize; a cap is not a substitute for test isolation; the Content copy is required), and the default for new projects (no config until the project acquires a per-class external resource). test_infra_db.md cross-links it from the semaphore bullet.
105 lines
5.1 KiB
XML
105 lines
5.1 KiB
XML
<Project Sdk="Microsoft.NET.Sdk">
|
|
|
|
<PropertyGroup>
|
|
<TargetFramework>net10.0</TargetFramework>
|
|
<ImplicitUsings>enable</ImplicitUsings>
|
|
<Nullable>enable</Nullable>
|
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
<IsPackable>false</IsPackable>
|
|
</PropertyGroup>
|
|
|
|
<ItemGroup>
|
|
<PackageReference Include="Akka.TestKit.Xunit2" />
|
|
<PackageReference Include="coverlet.collector" />
|
|
<!--
|
|
Bundle D D2 needs Microsoft.Data.SqlClient for the MsSqlMigrationFixture
|
|
(mirroring ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests). Pinning 6.1.1 here for
|
|
the same reason: EF SqlServer 10.0.7 needs >= 6.1.1 but the central pin
|
|
is 6.0.2 (production ExternalSystemGateway). Override is test-only.
|
|
-->
|
|
<PackageReference Include="Microsoft.Data.SqlClient" VersionOverride="6.1.1" />
|
|
<PackageReference Include="Microsoft.Data.Sqlite" />
|
|
<!-- Security pin: GHSA-2m69-gcr7-jv3q. Microsoft.Data.Sqlite pulls the
|
|
vulnerable native 2.1.11; 2.1.12 patches it. Bumping Sqlite does not help. -->
|
|
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" />
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
|
|
<!--
|
|
M4 Bundle E (Task E3): Microsoft.Extensions.Configuration.Json,
|
|
DependencyInjection, and Logging.Abstractions are now provided by the
|
|
Microsoft.AspNetCore.App framework reference below (pulled in for the
|
|
TestHost-based middleware E2E) so we drop them as explicit package
|
|
references to satisfy the warn-as-error pruning rule.
|
|
-->
|
|
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
|
<PackageReference Include="NSubstitute" />
|
|
<PackageReference Include="xunit" />
|
|
<PackageReference Include="xunit.runner.visualstudio" />
|
|
<!--
|
|
SkippableFact pattern (xunit 2.9.x has no native Assert.Skip) — used by
|
|
Bundle D D2 MSSQL-backed AuditLogIngestActor tests to report Skipped when
|
|
the dev MSSQL container is not reachable.
|
|
-->
|
|
<PackageReference Include="Xunit.SkippableFact" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<Using Include="Xunit" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<!--
|
|
Deferred-work register row 96 — per-suite in-process parallelism cap.
|
|
Resource-heavy suite: MSSQL-backed classes take an MsSqlMigrationFixture
|
|
per test CLASS (CREATE DATABASE + the full migration chain on the ONE
|
|
shared dev SQL Server) and most classes stand up an Akka TestKit
|
|
ActorSystem with fast-ticking actors. Uncapped, xunit runs
|
|
Environment.ProcessorCount collections at once. The cap is threads only —
|
|
collections stay parallel — and 4 matches the default slot count of the
|
|
cross-process sp_getapplock migrate semaphore (row 82), so the in-process
|
|
and cross-process limits agree. Policy: docs/test_infra/test_infra.md.
|
|
The json must be copied to the output directory to take effect.
|
|
-->
|
|
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<ProjectReference Include="../../src/ZB.MOM.WW.ScadaBridge.AuditLog/ZB.MOM.WW.ScadaBridge.AuditLog.csproj" />
|
|
<!--
|
|
D2: the AuditLogIngestActor tests use the real AuditLogRepository against
|
|
a per-test MSSQL database via MsSqlMigrationFixture. The fixture lives in
|
|
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests; we reference that test project so
|
|
the fixture + EF migrations come along without duplicating them.
|
|
-->
|
|
<ProjectReference Include="../ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests.csproj" />
|
|
<!--
|
|
G2/G3/G4: the cached-call combined telemetry integration tests compose the
|
|
production OperationTrackingStore (site SQLite source of truth for
|
|
Tracking.Status) alongside the M2 audit writer chain, so the harness
|
|
needs a project reference to SiteRuntime where the store lives.
|
|
-->
|
|
<ProjectReference Include="../../src/ZB.MOM.WW.ScadaBridge.SiteRuntime/ZB.MOM.WW.ScadaBridge.SiteRuntime.csproj" />
|
|
<!--
|
|
M4 Bundle E (Task E2): the dispatcher audit-trail end-to-end test
|
|
constructs the production NotificationOutboxActor against the real
|
|
CentralAuditWriter so the Attempted/Delivered NotifyDeliver rows land in
|
|
the central MSSQL AuditLog table.
|
|
-->
|
|
<ProjectReference Include="../../src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/ZB.MOM.WW.ScadaBridge.NotificationOutbox.csproj" />
|
|
<!--
|
|
M4 Bundle E (Task E3): the inbound API audit-trail end-to-end test wires
|
|
the production AuditWriteMiddleware into a TestHost pipeline and asserts
|
|
one InboundRequest/InboundAuthFailure row per request lands in the
|
|
central MSSQL AuditLog.
|
|
-->
|
|
<ProjectReference Include="../../src/ZB.MOM.WW.ScadaBridge.InboundAPI/ZB.MOM.WW.ScadaBridge.InboundAPI.csproj" />
|
|
<ProjectReference Include="../ZB.MOM.WW.ScadaBridge.TestSupport/ZB.MOM.WW.ScadaBridge.TestSupport.csproj" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<!-- M4 Bundle E (Task E3): need ASP.NET Core for the TestHost-based middleware E2E. -->
|
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
|
<PackageReference Include="Microsoft.AspNetCore.TestHost" />
|
|
</ItemGroup>
|
|
|
|
</Project>
|