# Description This PR fixes bounded ManagedSession reconnect cleanup and reorganizes the sample applications into domain-focused folders. ## Reconnect cleanup - Bounds reconnect integration cleanup with independent 30-second close and dispose limits. - Sends `CloseSession` through the awaited transport request path during `Session.DisposeAsync`. - Preserves explicit `Session.CloseAsync` behavior that waits for or cancels outstanding publish requests. - Covers the disposal request path with a regression test. ## Sample organization - `samples/OpenUsd`: `GeneratorServer`, `SiteCompositionServer` - `samples/Redundancy`: `RedundantClient`, `RedundantServer`, `RedundantPubSub` - `samples/Isa95`: `MinimalIsa95Server` - `samples/MinimalApi`: `MinimalBoilerServer`, `MinimalCalcServer`, `MinimalClient` - `samples/DI`: `PumpDeviceIntegrationServer` - `samples/Lds`: `ConsoleLdsServer` - `samples/Reference`: `ConsoleReferenceClient`, `ConsoleReferenceServer` - `samples/PubSub`: `ConsoleReferencePubSubClient` `UA.slnx` now exposes the same requested domain groups. Project references, tests, runtime sample probes, CI workflows, Dockerfiles, Compose files, helper scripts, and documentation were updated to the new paths. `samples/Robotics/MinimalRobotServer` remains under `Robotics`. ## Validation - `dotnet build UA.slnx` - 3 Redundancy short-haul sample tests - 70 DI sample tests - 914 OpenUSD tests - 1 WotCon model-materialization test - 137 AOT tests - `docker compose config` for all 6 moved Redundancy Compose files ## Related Issues - Fixes #4273 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce new build or analyzer warnings. - [x] I built the complete `UA.slnx` solution locally. - [ ] I ran all tests locally against at least .NET Framework and .NET 10. - [ ] I fixed all failing and flaky tests in the CI pipelines and all CodeQL warnings. - [x] I have addressed all PR feedback received. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> Co-authored-by: Marc Schier <mschier@microsoft.com> Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> Copilot-Session: a2c2838f-74ae-4997-a1d4-50574d9e0636
4.4 KiB
Redundant Sample Integration Tests
The Opc.Ua.Redundancy.Samples.Tests project contains process-level integration tests that launch the redundant sample applications
— RedundantServer, RedundantClient and
RedundantPubSub — as real external processes and assert on the high-availability behavior they log
(FAILOVER:, DATA LOSS:, HA OK:, and reconnect events). They exercise the samples in their supported setups so that regressions in the
end-to-end high-availability experience are caught automatically, and they demonstrate both successful failover and the visibility of data loss.
The tests come in a short-haul form that runs as part of normal pull-request validation, and a long-haul soak form that runs on a dedicated, manually triggered CI job (and on a weekly schedule) to validate high-availability operation over an extended period.
Short-haul tests (pull-request validation)
Short-haul tests are deterministic and complete in seconds. They are discovered and run automatically by the normal
Build and Test workflow (and the Azure DevOps test stages), because the project follows the
tests/Opc.Ua.*.Tests naming convention. They are tagged with the NUnit category SampleHaShortHaul:
- PubSub demo, hot mode — runs
RedundantPubSub --role demo --ha-mode hotand asserts the promoted publisher continues the SequenceNumber across failover with no reset (SIMULATED: HA OK: sequence continued ...). - PubSub demo, cold mode — runs the same demo in cold mode and asserts the SequenceNumber reset (data loss) is made visible
(
SIMULATED: DATA LOSS: sequence reset ...). - Server + client connectivity — launches a
RedundantServerand aRedundantClienttogether and asserts the client connects and begins high-availability monitoring.
Run them locally from the repository root:
dotnet test tests/Opc.Ua.Redundancy.Samples.Tests/Opc.Ua.Redundancy.Samples.Tests.csproj --filter "Category=SampleHaShortHaul"
Long-haul tests (manual / scheduled soak)
Long-haul tests are marked [Explicit] (NUnit category SampleHaLongHaul) so they never run on pull requests. They loop for a configurable
duration and assert the high-availability guarantees hold across many failovers:
- PubSub failover soak — repeatedly runs the PubSub demo in hot and cold modes for the whole duration, asserting the correct continuity (hot) and data-loss (cold) narrative every iteration.
- Client reconnect soak — runs a
RedundantClientagainst aRedundantServerfor the whole duration and repeatedly kills and restarts the server, asserting the client transparently detects the loss, reconnects when the server returns, and never crashes.
The soak duration is controlled by the SAMPLE_HA_DURATION_MINUTES environment variable (default 60). Run a short local soak with:
$env:SAMPLE_HA_DURATION_MINUTES = "5"
dotnet test tests/Opc.Ua.Redundancy.Samples.Tests/Opc.Ua.Redundancy.Samples.Tests.csproj --filter "Category=SampleHaLongHaul"
The long-haul tests run in CI through dedicated, manually triggerable jobs on both platforms:
- GitHub Actions — the Sample HA Long-Haul Test workflow (
workflow_dispatchwith adurationinput, plus a weekly schedule). - Azure DevOps — the sample-ha-longhaul pipeline (manual run with a
durationMinutesparameter, plus a weekly schedule).
Multi-replica leader-election failover
The full multi-replica leader-election topologies — strong (Raft) active/passive and eventual (CRDT gossip) active/active — rely on a
stable virtual endpoint with DNS-based re-resolution to a surviving replica. These are demonstrated end-to-end by the docker-compose setups under
samples/Redundancy/RedundantServer and samples/Redundancy/RedundantClient, which run
several replicas on a container network and let you kill the active replica to observe cross-replica failover. The process-level long-haul soak
above focuses on the failover-detection, reconnect, and data-loss-visibility behavior that runs deterministically inside a CI runner without
container networking.