Files
qinglong/test/back/ql3PostgresHaDockerContract.test.cjs

146 lines
4.7 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { test } = require('node:test');
const {
privateReportPath,
writePrivateReport,
} = require('../../scripts/ql3-postgres-ha-contract.cjs');
const ROOT = path.resolve(__dirname, '../..');
const SOURCE = fs.readFileSync(
path.join(ROOT, 'scripts/ql3-postgres-ha-contract.cjs'),
'utf8',
);
test('mounts PostgreSQL 18 named volumes at the image-declared root', () => {
assert.match(
SOURCE,
/const POSTGRES_VOLUME_ROOT = '\/var\/lib\/postgresql';/,
);
assert.match(
SOURCE,
/const POSTGRES_DATA = '\/var\/lib\/postgresql\/18\/docker';/,
);
assert.equal(
SOURCE.match(
/\$\{names\.(?:primary|standby)Volume\}:\$\{POSTGRES_VOLUME_ROOT\}/g,
)?.length,
6,
);
assert.doesNotMatch(
SOURCE,
/\$\{names\.(?:primary|standby)Volume\}:\$\{POSTGRES_DATA\}/,
);
assert.equal(SOURCE.match(/`PGDATA=\$\{POSTGRES_DATA\}`/g)?.length, 2);
assert.match(
SOURCE,
/mkdir -p \$\{POSTGRES_DATA\} && chown -R postgres:postgres \$\{POSTGRES_DATA\}/,
);
});
test('removes only its isolated HA containers, named volumes and networks', () => {
const removeContainers =
"docker(['rm', '-f', '-v', names.primary, names.standby]";
const removeVolumes =
"docker(['volume', 'rm', names.primaryVolume, names.standbyVolume]";
assert.match(SOURCE, /ql3-ha-primary-/);
assert.match(SOURCE, /ql3-ha-standby-/);
assert.ok(SOURCE.indexOf(removeContainers) > 0);
assert.ok(SOURCE.indexOf(removeVolumes) > SOURCE.indexOf(removeContainers));
assert.doesNotMatch(SOURCE, /(?:system|builder|volume) prune/);
assert.doesNotMatch(SOURCE, /ql3-cnpg-evidence-control-plane/);
});
test('publishes only a compact stdout envelope after durable report creation', () => {
assert.match(SOURCE, /const reportFile = privateReportPath\(argv\);/);
assert.match(SOURCE, /writePrivateReport\(reportFile, report\);/);
assert.ok(
SOURCE.indexOf('writePrivateReport(reportFile, report);') <
SOURCE.indexOf('reportSha256:'),
);
assert.doesNotMatch(
SOURCE,
/process\.stdout\.write\(`\$\{JSON\.stringify\(report, null, 2\)\}/,
);
});
test('publishes a private no-replace PostgreSQL HA report atomically', (t) => {
const directory = fs.mkdtempSync(
path.join(fs.realpathSync(os.tmpdir()), 'ql3-postgres-ha-report-test-'),
);
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
const reportPath = path.join(directory, 'report.json');
assert.equal(privateReportPath([`--report=${reportPath}`], {}), reportPath);
assert.equal(
privateReportPath(['--', `--report=${reportPath}`], {}),
reportPath,
);
const report = {
schemaVersion: 1,
fixture: 'qinglong/postgresql-ha-contract@v1',
gates: { passed: true },
};
writePrivateReport(reportPath, report);
assert.equal(fs.lstatSync(reportPath).mode & 0o777, 0o600);
assert.deepEqual(JSON.parse(fs.readFileSync(reportPath, 'utf8')), report);
assert.deepEqual(
fs.readdirSync(directory).filter((name) => name.endsWith('.tmp')),
[],
);
assert.throws(
() => writePrivateReport(reportPath, report),
/EEXIST|file already exists/,
);
assert.deepEqual(
fs.readdirSync(directory).filter((name) => name.endsWith('.tmp')),
[],
);
});
test('selects a canonical private temporary report path by default', () => {
const selected = privateReportPath([], {});
assert.equal(path.isAbsolute(selected), true);
assert.equal(fs.realpathSync(path.dirname(selected)), path.dirname(selected));
assert.equal(fs.existsSync(selected), false);
});
test('rejects ambiguous, relative, existing and symlink-parent report paths', (t) => {
const directory = fs.mkdtempSync(
path.join(fs.realpathSync(os.tmpdir()), 'ql3-postgres-ha-path-test-'),
);
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
const reportPath = path.join(directory, 'report.json');
assert.throws(
() => privateReportPath(['--report=relative.json'], {}),
/normalized absolute file/,
);
assert.throws(
() =>
privateReportPath([`--report=${reportPath}`], {
QL3_HA_REPORT: path.join(directory, 'other.json'),
}),
/only once/,
);
fs.writeFileSync(reportPath, '{}\n', { mode: 0o600 });
assert.throws(
() => privateReportPath([`--report=${reportPath}`], {}),
/refusing to overwrite/,
);
const realParent = path.join(directory, 'real');
const linkedParent = path.join(directory, 'linked');
fs.mkdirSync(realParent, { mode: 0o700 });
fs.symlinkSync(realParent, linkedParent);
assert.throws(
() =>
privateReportPath(
[`--report=${path.join(linkedParent, 'report.json')}`],
{},
),
/canonical real directory/,
);
});