e89ac2df33
RoslynVirtualTagEvaluatorTests' race test failed 1 of 3 full Host integration runs under 28 CPU burners (load ~300) with 24 of 4,800 evaluations refused 'previous evaluation still running' - impossible for one sequential loop per id unless a finished run still held its slot after the caller resumed. It did: ScriptRunGuard released the slot from a ContinueWith on the run task, and a task is observably complete before its continuations run, so the next run of the key (the next trigger, or the evaluator's immediate retry after a raced ObjectDisposedException) could be refused - a Bad publish for a script that had finished. Same class #789 fixed for the out-of-process runner. The release (and the late allocation-breach quarantine, now ahead of it) runs in the run's own finally, before the task completes; the continuation only disposes the CTS and observes the fault. New ScriptRunGuardTests.A_caller_that_awaited_its_run_is_never_refused_by_it widens the release with a test hook (SlotReleasingForTest) - mutation-checked: releasing from a continuation again refuses 49 of 50. The race test now prints elapsed / evaluations / clears / pool state / failure histogram on every assertion and on its hang detector. After: 3/3 full Host integration runs pass under the same load. Core.Scripting 298, ScriptedAlarms 109, Calculation 84 green. Co-Authored-By: Claude <noreply@anthropic.com>
ZB.MOM.WW.OtOpcUa.Host.IntegrationTests
Two-node Akka cluster integration tests on top of TwoNodeClusterHarness.
Default mode (no infra required)
dotnet test tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests
Uses Microsoft.EntityFrameworkCore.InMemory for ConfigDb and a stub ILdapAuthService that
accepts any username when the password is valid-password. Each harness instance creates a
unique in-memory database scoped to its lifetime. This is the mode CI runs by default.
Real-infra mode (SQL Server + OpenLDAP)
When you need to exercise EF behaviors that diverge between providers (index uniqueness,
RowVersion concurrency, JSON columns, migration application) or a real LDAP bind, bring up
the bundled compose stack and set the env-var switches:
docker compose -f tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/docker-compose.yml up -d
export OTOPCUA_HARNESS_USE_SQL=1
export OTOPCUA_HARNESS_USE_LDAP=1
dotnet test tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests
docker compose -f tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/docker-compose.yml down -v
SQL Server mode (OTOPCUA_HARNESS_USE_SQL=1)
- Container:
mcr.microsoft.com/mssql/server:2022-latestonlocalhost:14331 - Each
TwoNodeClusterHarness.StartAsync()creates a unique databaseOtOpcUa_Harness_{guid}viaDatabase.EnsureCreatedAsync()and drops it onDisposeAsync()(best-effort). - Port
14331chosen to avoid colliding with thedocker-dev/fleet (which uses14330).
LDAP mode (OTOPCUA_HARNESS_USE_LDAP=1)
- Container:
bitnami/openldap:2.6onlocalhost:3894 - Users
alice/alice123andbob/bob123, all underou=FleetAdmin. - Port
3894chosen to avoid colliding with thedocker-dev/fleet (which uses3893).
Local-dev caveat
This dev VM (DESKTOP-6JL3KKO) does not run Docker locally. Real-infra mode runs on the
shared Linux Docker host (10.100.0.35) per docs/v2/dev-environment.md, or in CI on Linux.