From a78ffea4c55a6fdfcb97f590a815237acb234a77 Mon Sep 17 00:00:00 2001 From: implementer Date: Sat, 29 Aug 2026 10:45:00 +0000 Subject: [PATCH] test: lock in the PostgreSQL 18.6 container criteria (E00-S03-T01) - compose-config.test.mjs: assertDbService requires the pinned postgres:18.6-bookworm image; new docker-gated real-stack probe starts the stack and asserts SHOW server_version exposes 18.6; mutation probe proves reverting to a floating major tag fails the criterion; parser probe updated - build-targets.test.mjs: db-service mutation fixture updated to the pinned image tag --- tests/build-targets.test.mjs | 4 +-- tests/compose-config.test.mjs | 58 ++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/tests/build-targets.test.mjs b/tests/build-targets.test.mjs index b2dd338..f374f82 100644 --- a/tests/build-targets.test.mjs +++ b/tests/build-targets.test.mjs @@ -345,8 +345,8 @@ test('a platforms list on the db service (which has no build config) cannot sati const dbOnly = text .replace(/\n\s*platforms:\n(?:\s*- [^\n]+\n)+/, '\n') .replace( - ' image: postgres:18-bookworm\n', - ' image: postgres:18-bookworm\n platforms:\n - linux/amd64\n - linux/arm64\n', + ' image: postgres:18.6-bookworm\n', + ' image: postgres:18.6-bookworm\n platforms:\n - linux/amd64\n - linux/arm64\n', ); assert.notEqual(dbOnly, text, 'the mutation must actually move the platforms list onto db'); assert.throws(() => assertBuildTargets(parseYaml(dbOnly)), /platforms/); diff --git a/tests/compose-config.test.mjs b/tests/compose-config.test.mjs index cb9d601..dcd6095 100644 --- a/tests/compose-config.test.mjs +++ b/tests/compose-config.test.mjs @@ -180,8 +180,9 @@ function assertDbService(compose) { assert.ok(db, 'compose.yaml must declare a "db" service (docker compose up -d starts the database)'); assert.equal( db.image, - 'postgres:18-bookworm', - 'the "db" service must use the committed PostgreSQL 18 image (postgres:18-bookworm)', + 'postgres:18.6-bookworm', + 'the "db" service must use the committed PostgreSQL 18.6 image (postgres:18.6-bookworm — E00-S03-T01 ' + + 'pins the exact minor so the database container exposes the expected PostgreSQL version)', ); const env = db.environment ?? {}; assert.equal(env.POSTGRES_DB, '${POSTGRES_DB:-eppp}', 'db must set POSTGRES_DB (with a default)'); @@ -640,6 +641,43 @@ test('a database fixture survives docker compose restart and recreate (named db- } }); +test('the database container exposes the expected PostgreSQL version (18.6)', { skip: !DOCKER_COMPOSE || !DOCKER_DAEMON }, () => { + // E00-S03-T01 acceptance criteria: a PostgreSQL 18.6 container is used as + // the database AND the container exposes the expected PostgreSQL version. + // The committed image tag is pinned to postgres:18.6-bookworm (asserted + // statically above); this probe starts the stack and asks the running + // server itself (`SHOW server_version`) — the issue's test plan ("start the + // container and confirm PostgreSQL 18.6") — so the version the container + // actually exposes is verified end to end, not just the declared tag. + const up = run('docker', ['compose', 'up', '-d'], { cwd: REPO_ROOT }); + assert.equal( + up.status, + 0, + `"docker compose up -d" must exit 0:\n${(up.stdout || '')}\n${(up.stderr || '')}`.trim(), + ); + try { + waitForDbHealthy(); + const version = run( + 'docker', + ['compose', 'exec', '-T', 'db', 'psql', '-U', 'eppp', '-d', 'eppp', '-tA', '-c', 'SHOW server_version;'], + { cwd: REPO_ROOT, timeout: 60_000 }, + ); + assert.equal( + version.status, + 0, + `"SHOW server_version" must succeed against the running db container:\n` + + `${(version.stdout || '')}\n${(version.stderr || '')}`.trim(), + ); + assert.match( + version.stdout.trim(), + /^18\.6\b/, + `the running db container must expose PostgreSQL 18.6 (SHOW server_version got: "${version.stdout.trim()}")`, + ); + } finally { + run('docker', ['compose', 'down'], { cwd: REPO_ROOT }); + } +}); + // --------------------------------------------------------------------------- // Non-vacuous probes — the assertions above really do fail on violations // --------------------------------------------------------------------------- @@ -648,7 +686,7 @@ test('the YAML parser reads the committed structure (non-vacuous parser probe)', const parsed = parseYaml(` services: db: - image: postgres:18-bookworm + image: postgres:18.6-bookworm environment: POSTGRES_DB: eppp ports: @@ -665,7 +703,7 @@ services: db: condition: service_healthy `); - assert.equal(parsed.services.db.image, 'postgres:18-bookworm'); + assert.equal(parsed.services.db.image, 'postgres:18.6-bookworm'); assert.equal(parsed.services.db.environment.POSTGRES_DB, 'eppp'); assert.deepEqual(parsed.services.db.ports, ['5432:5432']); assert.match(parsed.services.db.healthcheck.test, /pg_isready/); @@ -682,6 +720,18 @@ test('removing the db service makes the database criterion fail (mutation probe) assert.throws(() => assertDbService(compose), /"db" service/); }); +test('reverting the db image to a floating major tag fails the PostgreSQL 18.6 criterion (mutation probe)', () => { + // E00-S03-T01 pins the exact 18.6 minor (postgres:18.6-bookworm). A + // floating major tag (postgres:18-bookworm / postgres:18) would not + // guarantee the container exposes PostgreSQL 18.6, so reverting to one must + // fail the pinned-image assertion. + const text = read(COMPOSE_PATH); + const mutated = text.replace('postgres:18.6-bookworm', 'postgres:18-bookworm'); + assert.notEqual(mutated, text, 'the mutation must actually revert the pinned image tag'); + const compose = parseYaml(mutated); + assert.throws(() => assertDbService(compose), /18\.6/); +}); + test('removing the app service makes the application criterion fail (mutation probe)', () => { const text = read(COMPOSE_PATH); const withoutApp = text.replace(/^ app:\n(?: .*\n?)*/m, '');