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.
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
# 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"
|
||||
Reference in New Issue
Block a user