Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.IntegrationTests/Docker/postgres/docker-compose.yml
T
Joseph Doherty 9675823cd6 test(sql): env-gated Postgres + Oracle integration suites
Two disposable docker fixtures (postgres:17-alpine on 15432, gvenzl/oracle-free:
23-slim on 11521) shaped like the existing mssql one — project label, distinct
container name, healthcheck, one-shot seed service — plus a live suite per
provider, gated on SQL_PG_* / SQL_ORACLE_* and skipping clean offline.

Each suite covers what a DIALECT can get wrong, rather than re-running the
provider-agnostic read semantics already pinned against SQL Server and SQLite:
liveness + catalog load, a KeyValue read, the provider's own row-limit syntax via
topByTimestamp (LIMIT 1 / FETCH FIRST 1 ROWS ONLY, where T-SQL emits TOP 1),
identifier case-folding through the design §8.1 catalog gate, and the AdminUI
browse walk driven through SqlDriverBrowser.

Two seed decisions are load-bearing rather than scaffolding:

- The Postgres schema is owned by a role the suite is NOT; the connecting login
  holds USAGE + SELECT only. That is the exact provisioning PostgresDialect's
  ListSchemasSql exists for (information_schema.schemata lists only schemas the
  role OWNS, so a granted-not-owning poller would see none and every tag would be
  rejected). A fixture that owned its own schema would pass either way.
- Every identifier in both seeds is created UNQUOTED, so the catalogs hold
  lower-case (Postgres) and UPPER-case (Oracle) spellings. The case-folding legs
  author the opposite case and pin SqlCatalog.TryMatch's REAL contract — exact
  ordinal first, then a UNIQUE case-insensitive match whose catalog spelling is
  substituted — which on both providers is what makes mixed-case authoring work
  at all, since both dialects emit case-sensitive double-quoted identifiers.

Connection strings are composed through dialect.Factory.CreateConnectionString-
Builder() and the abstract DbConnectionStringBuilder indexer, so the csproj keeps
its no-direct-provider-reference discipline; every key used was verified accepted
through that indexer. The csproj gains only Driver.Sql.Browser, for the browse leg.

Live-run evidence (local OrbStack, both images arm64): Postgres 5/5 green;
Oracle 6/6 green after the ORA-01745 dialect fix this suite found. Offline the
whole project is 33 skipped / 0 failed.
2026-08-05 07:15:43 -04:00

79 lines
3.8 KiB
YAML

# Dedicated, DISPOSABLE PostgreSQL for the Sql driver's Postgres live gate (PostgresReadTests).
#
# ── SAFETY ─────────────────────────────────────────────────────────────────────
# This stack owns its OWN postgres container, `otopcua-sql-pg`, on host port 15432.
# Nothing else on the rig runs PostgreSQL, so there is no shared-server hazard of the
# kind the mssql blackhole fixture guards against — but the same discipline applies:
# a distinct container_name and a distinct host port, and `restart: "no"` so a killed
# container stays down rather than respawning.
#
# ── DEPLOY (docker runs on the shared Linux host, 10.100.0.35) ──────────────────
# # from a Windows VM:
# lmxopcua-fix sync sql-pg # rsync this dir → /opt/otopcua-sql-pg/
# lmxopcua-fix up sql-pg # single-service stack (+ one-shot seed), no profile arg
#
# # from macOS (there is no lmxopcua-fix there — drive the host over SSH):
# rsync -av tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.IntegrationTests/Docker/postgres/ \
# dohertj2@10.100.0.35:/opt/otopcua-sql-pg/
# ssh dohertj2@10.100.0.35 'cd /opt/otopcua-sql-pg && SQL_PG_PASSWORD=... docker compose up -d'
#
# ── RUN THE GATE ───────────────────────────────────────────────────────────────
# export SQL_PG_ENDPOINT=10.100.0.35:15432
# export SQL_PG_USER=otopcua # optional; this is the default
# export SQL_PG_PASSWORD=... # the same value this compose was brought up with
# dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.IntegrationTests \
# --filter "FullyQualifiedName~PostgresReadTests"
#
# The one-shot `postgres-seed` service applies seed-pg.sql once the server is healthy, so
# the stack is self-seeding. Unlike the mssql fixture the suite does NOT seed defensively
# on connect: the seed creates ROLES (an owner role that is not the connecting principal),
# which the read-only fixture login deliberately cannot do — see seed-pg.sql.
name: otopcua-sql-pg
services:
postgres:
image: postgres:17-alpine
container_name: otopcua-sql-pg
labels:
project: lmxopcua
restart: "no"
environment:
# Dev-only sandbox password for a throwaway container; the seed gives the unprivileged
# `otopcua` login the SAME value, which is what the suite reads from SQL_PG_PASSWORD.
POSTGRES_PASSWORD: "${SQL_PG_PASSWORD:-Sqlpg_dev_pw1}"
POSTGRES_DB: sqlpollfixture
ports:
- "15432:5432"
healthcheck:
# pg_isready against the fixture database: the server accepting a connection to the
# database the seed targets is the readiness signal, not merely a listening socket.
test:
- "CMD-SHELL"
- "pg_isready -U postgres -d sqlpollfixture || exit 1"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s
# One-shot seed: waits for the server to pass its healthcheck, applies seed-pg.sql, exits.
postgres-seed:
image: postgres:17-alpine
labels:
project: lmxopcua
restart: "no"
depends_on:
postgres:
condition: service_healthy
environment:
PGPASSWORD: "${SQL_PG_PASSWORD:-Sqlpg_dev_pw1}"
APP_PASSWORD: "${SQL_PG_PASSWORD:-Sqlpg_dev_pw1}"
volumes:
- ./seed-pg.sql:/seed.sql:ro
entrypoint:
- "/bin/sh"
- "-c"
# ON_ERROR_STOP=1 so a broken seed fails the service rather than leaving a half-seeded
# database that makes a later test failure look like a driver bug.
- "psql -v ON_ERROR_STOP=1 -v app_password=\"$${APP_PASSWORD}\" -h postgres -U postgres -d sqlpollfixture -f /seed.sql"