Files
ScadaBridge/docs/test_infra/test_infra.md
T
Joseph Doherty 6ae605160c chore(auth): ScadaBridge unify dev LDAP base DN to dc=zb,dc=local (Task 1.6)
Replace dc=scadabridge,dc=local with dc=zb,dc=local in all dev/test LDAP
references — app config, docker test-cluster node configs (docker/ and
docker-env2/), GLAuth fixture, dev tooling, Host.Tests fixtures,
IntegrationTests factory, and operational test_infra docs. OU structure
(ou=SCADA-Admins,ou=users,etc.) preserved throughout. Email domains
(@scadabridge.local), hostnames, and container names are untouched.
Historical plan docs (2026-05-24-second-environment.md,
2026-05-31-folder-repo-rename-scadabridge-design.md) excluded as
point-in-time records. No synthetic dc=example,dc=com placeholders touched.
2026-06-02 06:54:14 -04:00

6.1 KiB

Test Infrastructure

This document describes the local Docker-based test infrastructure for ScadaBridge development. Seven services provide the external dependencies needed to run and test the system locally. The first seven run in infra/docker-compose.yml; Traefik runs alongside the cluster nodes in docker/docker-compose.yml.

Services

Service Image Port(s) Config Compose File
OPC UA Server mcr.microsoft.com/iotedge/opc-plc:latest 50000 (OPC UA), 8080 (web) infra/opcua/nodes.json infra/
OPC UA Server 2 mcr.microsoft.com/iotedge/opc-plc:latest 50010 (OPC UA), 8081 (web) infra/opcua/nodes.json infra/
LDAP Server glauth/glauth:latest 3893 infra/glauth/config.toml infra/
MS SQL 2022 mcr.microsoft.com/mssql/server:2022-latest 1433 infra/mssql/setup.sql infra/
SMTP (Mailpit) axllent/mailpit:latest 1025 (SMTP), 8025 (web) Environment vars infra/
REST API (Flask) Custom build (infra/restapi/Dockerfile) 5200 infra/restapi/app.py infra/
Playwright mcr.microsoft.com/playwright:v1.58.2-noble 3000 (WebSocket) Command args infra/
Traefik LB traefik:v3.4 9000 (proxy), 8180 (dashboard) docker/traefik/ docker/

Quick Start

cd infra
docker compose up -d

After the first startup, run the SQL setup and seed scripts:

docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
  -i /docker-entrypoint-initdb.d/setup.sql

docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
  -i /docker-entrypoint-initdb.d/machinedata_seed.sql

Per-Service Documentation

Each service has a dedicated document with configuration details, verification steps, and troubleshooting:

Remote Test Infrastructure

In addition to the local Docker services, the following remote services are available for testing against real AVEVA System Platform hardware.

Primary/backup testing: The dual OPC UA test servers (ports 50000 and 50010) in local Docker provide primary/backup endpoint pairs for testing Data Connection Layer failover. Use docker compose stop opcua to simulate primary failure and verify automatic failover to the backup.

Alarms & Conditions (native alarms): The infra OPC PLC server does expose OPC UA Alarms & Conditions — a ConditionRefresh against its event notifier replays the active condition set and a SnapshotComplete, so the native alarm mirror (IAlarmSubscribableConnectionNativeAlarmActor) can be exercised live. The OpcUaAlarmLiveSmokeTests.SubscribeAlarms_DeliversConditionRefreshSnapshot [SkippableFact] (Trait RequiresOpcUa) round-trips against opc.tcp://localhost:50000 and asserts the snapshot arrives; it reports Skipped (not failed) when the server is unreachable or — on a substitute server that lacks A&C — when no snapshot arrives within the window. The MxAccess Gateway alarm feed (MxGateway protocol) requires a live gateway and is verified via the docker-env2 manual deploy check, not in CI.

Connection Strings

For use in appsettings.Development.json:

{
  "ConnectionStrings": {
    "ScadaBridgeConfig": "Server=localhost,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
    "ScadaBridgeMachineData": "Server=localhost,1433;Database=ScadaBridgeMachineData;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
  },
  "Ldap": {
    "Server": "localhost",
    "Port": 3893,
    "BaseDN": "dc=zb,dc=local",
    "UseSsl": false
  },
  "OpcUa": {
    "EndpointUrl": "opc.tcp://localhost:50000"
  },
  "OpcUa2": {
    "EndpointUrl": "opc.tcp://localhost:50010"
  },
  "Smtp": {
    "Server": "localhost",
    "Port": 1025,
    "AuthMode": "None",
    "FromAddress": "scada-notifications@company.com",
    "ConnectionTimeout": 30
  },
  "ExternalSystems": {
    "TestApi": {
      "BaseUrl": "http://localhost:5200",
      "AuthMode": "ApiKey",
      "ApiKey": "scadabridge-test-key-1"
    }
  }
}

Stopping & Teardown

cd infra
docker compose down            # stop containers, preserve SQL data volume
docker compose stop opcua      # stop a single service (also: opcua2, ldap, mssql, smtp, restapi)

Full teardown (removes volumes, optionally images and venv):

cd infra
./teardown.sh              # stop containers + delete SQL data volume
./teardown.sh --images     # also remove downloaded Docker images
./teardown.sh --all        # also remove the Python venv

After a full teardown, the next docker compose up -d starts fresh — re-run the SQL setup script.

Files

infra/
  docker-compose.yml          # All seven services
  teardown.sh                 # Teardown script (volumes, images, venv)
  glauth/config.toml          # LDAP users and groups
  mssql/setup.sql             # Database and user creation
  mssql/machinedata_seed.sql  # Machine Data tables, stored procedures, sample data
  opcua/nodes.json            # Custom OPC UA tag definitions
  restapi/app.py              # Flask REST API server
  restapi/Dockerfile          # REST API container build
  tools/                      # Python CLI tools (opcua, ldap, mssql, smtp, restapi)
  README.md                   # Quick-start for the infra folder

docker/
  traefik/traefik.yml         # Traefik static config (entrypoints, file provider)
  traefik/dynamic.yml         # Traefik dynamic config (load balancer, health check routing)