Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests
Joseph Doherty b037cc7ac4
v2-ci / build (push) Successful in 4m42s
v2-ci / unit-tests (push) Failing after 15m19s
chore(secrets): adopt ZB.MOM.WW.Secrets 0.6.2 — fail-closed store-path validation
Four-minor jump 0.2.3 → 0.6.2. The release line exists because a deploy
renaming the app directory took the MxGateway credential store with it
(2026-08-09, two silent days): Secrets:SqlitePath must now be absolute AND
outside the content root, rejected at boot rather than relocated. 0.6.2 over
0.6.1 is message-only (the rejection text now teaches the mounted-volume
case and forecloses the override hunt) — the live rig evidence below was
gathered at 0.6.1 and the validator behavior is identical.

Adoption changes beyond the pins:

- appsettings.json drops the relative "otopcua-secrets.db" (now boot-fatal);
  dev gets the library's absolute per-user default, deployments supply their
  own (wonder already pins an absolute out-of-root path in the service env).
- Program.cs's pre-host ${secret:} expander now calls the FOUR-argument
  AddZbSecrets with builder.Environment.ContentRootPath. This call site is
  the actual fix, not the pin: the throwaway container has no
  IHostEnvironment, and without the explicit root the under-content-root
  rule is skipped at exactly the moment the migrator creates the store file
  (the 0.6.0 defect). Do NOT simplify back to the 3-argument overload — it
  compiles and silently reopens the gap. Pinned by a Program.cs source-scan
  test AND a runtime falsification control that RUNS the migration and
  demonstrably creates the store at the rejected path under the 3-arg form.
- docker-dev: Secrets__SqlitePath moves /app/data → /data via a SECOND mount
  of the same per-node volume (same file at the volume root, so seeded
  stores carry over) because /app is the container's content root and the
  new rule correctly rejects it. LocalDb stays on /app/data (secrets-only
  rule).
- SecretsStorePathValidationTests: positive-control probes, artifact-first
  (relative and in-content-root paths must FAIL leaving no file; outside-
  root passes; the no-explicit-root control proves the file assertions can
  fail) — a clean boot is equally consistent with the validator never being
  wired.

Live-verified on the six-node docker-dev rig (at 0.6.1): all nodes boot
under the new validation with stores at /data; an AdminUI-written secret
converged into BOTH central nodes' independent stores; site-a held only its
own pair's secrets (Phase 6 pair-local isolation intact). Replicator wire
behavior unchanged 0.3.0–0.6.x per CHANGELOG; registration-graph pins and
the full suite pass.
2026-08-11 09:06:43 -04:00
..

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-latest on localhost:14331
  • Each TwoNodeClusterHarness.StartAsync() creates a unique database OtOpcUa_Harness_{guid} via Database.EnsureCreatedAsync() and drops it on DisposeAsync() (best-effort).
  • Port 14331 chosen to avoid colliding with the docker-dev/ fleet (which uses 14330).

LDAP mode (OTOPCUA_HARNESS_USE_LDAP=1)

  • Container: bitnami/openldap:2.6 on localhost:3894
  • Users alice / alice123 and bob / bob123, all under ou=FleetAdmin.
  • Port 3894 chosen to avoid colliding with the docker-dev/ fleet (which uses 3893).

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.