Files
UA-.NETStandard/docs/RedundancySampleTests.md
Marc SchierandCopilot Autofix powered by AI e9313ef957 Only use GitHub action for CI and nightly, establish release-branch-only package publication (#4513)
## Description

Two related changes to how the 2.0 line is built and shipped.

### 1. Release-branch-only package publication

- `master` produces development previews only.
- Stable packages can only be built from a canonical
`release/<major>.<minor>` branch and are promoted manually from the
exact signed candidate artifact.
- Core packages use explicit `major.minor.patch` versions (`2.0.0`,
`2.0.1`, then `2.1.0`); git height never changes a stable package patch.
- XRegistry, WoT Connectivity, Vision, Robotics, Redundancy,
Positioning, OpenUSD, ISA95, AI, DI, the relevant MCP extensions, and
OpenUSD connector tools remain `-preview.N` while following the core
numeric version.
- nuget.org receives only non-`.Debug` package IDs; GitHub Packages
retains the complete signed Release/Debug candidate.
- `docs/ReleaseProcess.md` is a reproducible runbook for developers and
agents, with each step stating its completion evidence.

Promotion is source-bound and byte-checked: `release.yml` checks out
nothing until the candidate SHA is known, and
`assert-published-packages-match.ps1` proves that any version already on
a feed holds *this* candidate's content before `--skip-duplicate` is
allowed to skip it. Canonical release-branch naming is matched
case-sensitively with no leading zeroes, and `version.json`'s
`publicReleaseRefSpec`, both policy helpers and the copy `release.yml`
inlines are pinned to one expression by tests.

### 2. PR CI moved to GitHub-hosted runners

- `.github/workflows/buildandtest.yml` (**CI**) now owns pull-request
validation outright, covering the Windows Debug/Release net48 + net10.0
solution builds and fast tests that only Azure Pipelines ran, alongside
the existing Linux/macOS, all-target and NativeAOT legs. `build-and-test
summary` remains the stable required check name.
- `.github/workflows/nightly.yml` is a new **manual-only**
(`workflow_dispatch`) full-scope workflow covering the Azure nightly
workload: all solutions x seven target profiles x Debug/Release, the
net472/netstandard profiles, Windows + Linux NativeAOT, and the
long-running and durable tiers.
- Shared deterministic discovery/batching lives in
`.github/scripts/get-ci-matrix.ps1` with a local composite action, so
both entry points expand the same workload manifest instead of
duplicating a large embedded script.
- `azure-pipelines.yml` is set to `pr: none`.
- The standalone pump sample image workflow is folded into the
consolidated **Images CI** workflow, which now builds all ten images and
publishes an `images summary` rollup suitable as a required check.

## Related Issues

No related issue provided.

## 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.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [x] I have addressed **all** PR feedback received.

## Validation

- `Opc.Ua.Tools.Tests` full `net10.0` suite: **959 passed, 1 skipped, 0
failed**.
- Version/package-policy regression subset
(`PackageVersionPolicyTests`): **60 passed, 0 failed**.
- GitHub Actions **CI** run 35719807620: **149/149 jobs green** on
GitHub-hosted runners.
- Canonical release-branch rule verified against the pinned nbgv 3.7.115
by building throwaway branches: `release/2.0`, `release/0.9`,
`release/10.42` -> `PublicRelease=True`; `release/02.0`, `release/2.00`,
`Release/2.0` -> `False`.
- Package identity gate verified against a live nuget.org package:
served packages carry a repository `.signature.p7s`, so equality is
decided on content excluding that part. Re-signing and zip reordering
produce an identical digest; a one-byte content change does not.
- Synthetic Release-only, Debug-only, combined, preview, duplicate,
orphaned-symbol, mismatched-root and accidental-stable-family package
sets exercise the shared validator.
- Stable-release rehearsal in an isolated `release/2.0` clone:
`Opc.Ua.Di` packed as `2.0.0-preview.6` depending on stable Core
`2.0.0`; `Opc.Ua.Di.Client` likewise against stable Client `2.0.0`.
- All workflow YAML, `version.json`, the package-policy PowerShell
scripts and the internal release-runbook anchors parse.

## Known validation limits

- Full `UA.slnx` `net48` and `net10.0` local validation remains blocked
by pre-existing `NETSDK1005` and dependency-version failures in
unmodified fuzz/sample projects; the corresponding checklist items
intentionally stay open.
- The TRX-driven test verdict added for the intermittent at-exit host
stall is proven by `CiTestVerdictTests`; the stall itself has not
recurred since.
- `nightly.yml` has not yet been run against a full-scope Azure run for
tuple-level parity — see below.

## Operational follow-up

This remains a preparation PR targeting `master`. It does **not**
authorize a release.

Release sequence:

1. Merge this PR.
2. Create canonical `release/2.0`, advance `master` to
`2.1.0-preview.{height}`, and open a separate `2.0.0` version PR against
`release/2.0`.
3. Follow
[`docs/ReleaseProcess.md`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/docs/ReleaseProcess.md)
for candidate dry-run, environment approval, promotion, tag/release
finalization, and next-patch preview setup.

CI migration steps still needing administrator access are tracked in
[`docs/DeveloperGuide.md#migration-status`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/docs/DeveloperGuide.md#migration-status):
proving `nightly.yml` parity on a trusted SHA with the private fuzz
corpus provisioned, turning off definition 14's service-side PR
override, retiring the Azure full-scope schedules and push trigger, and
retiring the duplicate `azure-pipelines-preview.yml` publisher.

> **Before cutting `release/2.0`:** the `Release` ruleset requires the
Azure context for *every* `refs/heads/release/*`, but a new 2.x branch
inherits `pr: none`, so that context would never report and would block
every PR into the new line. Exclude the new ref from that ruleset, or
add a 2.x ruleset requiring `build-and-test summary`, as part of
creating the branch.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-23 15:47:43 +00:00

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 CI 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 hot and 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 RedundantServer and a RedundantClient together 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 RedundantClient against a RedundantServer for 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_dispatch with a duration input, plus a weekly schedule).
  • Azure DevOps — the sample-ha-longhaul pipeline (manual run with a durationMinutes parameter, 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.