mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
require('ts-node/register/transpile-only');
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
const {
|
||||
postgresqlMainMigrationStream,
|
||||
} = require('../../back/migrations/postgresql');
|
||||
const {
|
||||
postgresqlControlSchemaContract,
|
||||
} = require('../../back/migrations/postgresql/schemaContract');
|
||||
const {
|
||||
PostgresSchemaReadinessError,
|
||||
} = require('../../back/migrations/postgresql/schemaReadiness');
|
||||
const {
|
||||
PostgresRunRepository,
|
||||
} = require('../../back/runtime/adapters/postgresql/runRepository');
|
||||
const {
|
||||
bootstrapClusterControlRuntime,
|
||||
} = require('../../back/runtime/adapters/postgresql/clusterControlRuntimeBootstrap');
|
||||
|
||||
function migrationHistory() {
|
||||
return postgresqlMainMigrationStream.migrations.map((migration, index) => ({
|
||||
streamId: 'postgresql-main',
|
||||
dialect: 'postgresql',
|
||||
migrationId: migration.id,
|
||||
checksum: migration.checksum,
|
||||
appliedAtMs: index + 1,
|
||||
}));
|
||||
}
|
||||
|
||||
function runtimePrivileges() {
|
||||
const privileges = {
|
||||
schema_migrations: [true, false, false, false],
|
||||
schema_capabilities: [true, false, false, false],
|
||||
runs: [true, true, true, false],
|
||||
run_attempts: [true, true, true, false],
|
||||
run_events: [true, true, false, false],
|
||||
run_retry_policies: [true, true, true, false],
|
||||
};
|
||||
return Object.entries(privileges).map(
|
||||
([
|
||||
tableName,
|
||||
[selectAllowed, insertAllowed, updateAllowed, deleteAllowed],
|
||||
]) => ({
|
||||
tableName,
|
||||
selectAllowed,
|
||||
insertAllowed,
|
||||
updateAllowed,
|
||||
deleteAllowed,
|
||||
isOwner: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function databaseResource(events, overrides = {}) {
|
||||
const contract = postgresqlControlSchemaContract;
|
||||
const pool = {
|
||||
async query(text) {
|
||||
events.push(
|
||||
`query:${
|
||||
events.filter((event) => event.startsWith('query:')).length + 1
|
||||
}`,
|
||||
);
|
||||
if (text.includes("current_setting('server_version_num')")) {
|
||||
return {
|
||||
rows: [
|
||||
{
|
||||
serverVersionNum: overrides.serverVersionNum ?? '160014',
|
||||
currentUser: 'ql3_runtime',
|
||||
inRecovery: false,
|
||||
transactionReadOnly: 'off',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
if (text.includes('FROM "ql3"."schema_migrations"')) {
|
||||
return { rows: migrationHistory() };
|
||||
}
|
||||
if (text.includes('FROM "ql3"."schema_capabilities"')) {
|
||||
return {
|
||||
rows: [
|
||||
{
|
||||
contractName: contract.contractName,
|
||||
contractVersion: contract.contractVersion,
|
||||
migrationId: contract.migrationId,
|
||||
capabilities: contract.capabilities,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
if (text.includes('FROM information_schema.columns')) {
|
||||
return {
|
||||
rows: contract.tables.flatMap((table) =>
|
||||
table.columns.map((columnName) => ({
|
||||
tableName: table.name,
|
||||
columnName,
|
||||
})),
|
||||
),
|
||||
};
|
||||
}
|
||||
if (text.includes('FROM pg_indexes')) {
|
||||
return {
|
||||
rows: contract.indexes.map((indexName) => ({ indexName })),
|
||||
};
|
||||
}
|
||||
if (text.includes('FROM pg_constraint')) {
|
||||
return {
|
||||
rows: [
|
||||
...contract.checks.map((constraintName) => ({
|
||||
constraintName,
|
||||
constraintType: 'check',
|
||||
})),
|
||||
...contract.foreignKeys.map((constraintName) => ({
|
||||
constraintName,
|
||||
constraintType: 'foreign_key',
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
if (text.includes('FROM pg_catalog.pg_roles')) {
|
||||
return {
|
||||
rows: [
|
||||
{
|
||||
canLogin: true,
|
||||
superuser: false,
|
||||
createDatabase: false,
|
||||
createRole: false,
|
||||
replication: false,
|
||||
bypassRowLevelSecurity: false,
|
||||
databaseConnect: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
if (text.includes('has_schema_privilege')) {
|
||||
return { rows: [{ schemaUsage: true, schemaCreate: false }] };
|
||||
}
|
||||
if (text.includes('has_table_privilege')) {
|
||||
return { rows: runtimePrivileges() };
|
||||
}
|
||||
throw new Error(`unexpected query: ${text}`);
|
||||
},
|
||||
async connect() {
|
||||
throw new Error('Repository connections are not used during bootstrap');
|
||||
},
|
||||
};
|
||||
return {
|
||||
pool,
|
||||
async close() {
|
||||
events.push('close-database');
|
||||
if (overrides.closeError) throw overrides.closeError;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function activationStack(
|
||||
events,
|
||||
recovery = { safe: true, remaining: 0, failed: 0 },
|
||||
) {
|
||||
return {
|
||||
async reconcile() {
|
||||
events.push('reconcile');
|
||||
return recovery;
|
||||
},
|
||||
async startLifecycles() {
|
||||
events.push('start-lifecycles');
|
||||
return true;
|
||||
},
|
||||
installAdmission() {
|
||||
events.push('install-admission');
|
||||
return () => events.push('dispose-admission');
|
||||
},
|
||||
async stop() {
|
||||
events.push('stop-stack');
|
||||
return 'stopped';
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function bootstrapOptions(events, overrides = {}) {
|
||||
return {
|
||||
enabled: true,
|
||||
profile: 'cluster-control',
|
||||
async openDatabase() {
|
||||
events.push('open-database');
|
||||
return databaseResource(events);
|
||||
},
|
||||
create({ evidence, runs }) {
|
||||
events.push('create-stack');
|
||||
assert.equal(evidence.contractVersion, 2);
|
||||
assert.equal(runs instanceof PostgresRunRepository, true);
|
||||
return activationStack(events);
|
||||
},
|
||||
audit(record) {
|
||||
events.push(`audit:${record.state}`);
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('disabled and wrong-profile bootstrap never opens PostgreSQL', async () => {
|
||||
const disabledEvents = [];
|
||||
const disabled = await bootstrapClusterControlRuntime(
|
||||
bootstrapOptions(disabledEvents, { enabled: false }),
|
||||
);
|
||||
assert.equal(disabled.status, 'disabled');
|
||||
assert.deepEqual(disabledEvents, ['audit:disabled']);
|
||||
|
||||
const wrongProfileEvents = [];
|
||||
await assert.rejects(
|
||||
bootstrapClusterControlRuntime(
|
||||
bootstrapOptions(wrongProfileEvents, { profile: 'edge' }),
|
||||
),
|
||||
/cannot activate cluster-control/,
|
||||
);
|
||||
assert.deepEqual(wrongProfileEvents, []);
|
||||
});
|
||||
|
||||
test('readiness failure closes the database before returning the root error', async () => {
|
||||
const events = [];
|
||||
await assert.rejects(
|
||||
bootstrapClusterControlRuntime(
|
||||
bootstrapOptions(events, {
|
||||
async openDatabase() {
|
||||
events.push('open-database');
|
||||
return databaseResource(events, { serverVersionNum: '150018' });
|
||||
},
|
||||
}),
|
||||
),
|
||||
(error) =>
|
||||
error instanceof PostgresSchemaReadinessError &&
|
||||
error.code === 'server_version_unsupported',
|
||||
);
|
||||
assert.equal(events.includes('create-stack'), false);
|
||||
assert.deepEqual(events.slice(-2), ['audit:failed', 'close-database']);
|
||||
});
|
||||
|
||||
test('opens once, assembles after readiness, and closes after stack shutdown', async () => {
|
||||
const events = [];
|
||||
const result = await bootstrapClusterControlRuntime(bootstrapOptions(events));
|
||||
assert.equal(result.status, 'active');
|
||||
assert.equal(events.filter((event) => event === 'open-database').length, 1);
|
||||
assert.ok(events.indexOf('create-stack') > events.lastIndexOf('query:7'));
|
||||
const first = result.stop();
|
||||
assert.equal(first, result.stop());
|
||||
assert.equal(await first, 'stopped');
|
||||
assert.deepEqual(events.slice(-4), [
|
||||
'dispose-admission',
|
||||
'stop-stack',
|
||||
'audit:stopped',
|
||||
'close-database',
|
||||
]);
|
||||
});
|
||||
|
||||
test('unsafe recovery stops the stack and closes the database', async () => {
|
||||
const events = [];
|
||||
await assert.rejects(
|
||||
bootstrapClusterControlRuntime(
|
||||
bootstrapOptions(events, {
|
||||
create({ runs }) {
|
||||
events.push('create-stack');
|
||||
assert.equal(runs instanceof PostgresRunRepository, true);
|
||||
return activationStack(events, {
|
||||
safe: false,
|
||||
remaining: 1,
|
||||
failed: 0,
|
||||
});
|
||||
},
|
||||
}),
|
||||
),
|
||||
/did not converge safely/,
|
||||
);
|
||||
assert.equal(events.includes('install-admission'), false);
|
||||
assert.deepEqual(events.slice(-3), [
|
||||
'stop-stack',
|
||||
'audit:failed',
|
||||
'close-database',
|
||||
]);
|
||||
});
|
||||
|
||||
test('database close failure does not skip stack shutdown and remains idempotent', async () => {
|
||||
const events = [];
|
||||
const closeError = new Error('database close failed');
|
||||
const result = await bootstrapClusterControlRuntime(
|
||||
bootstrapOptions(events, {
|
||||
async openDatabase() {
|
||||
events.push('open-database');
|
||||
return databaseResource(events, { closeError });
|
||||
},
|
||||
}),
|
||||
);
|
||||
const first = result.stop();
|
||||
assert.equal(first, result.stop());
|
||||
await assert.rejects(first, (error) => error === closeError);
|
||||
assert.deepEqual(events.slice(-4), [
|
||||
'dispose-admission',
|
||||
'stop-stack',
|
||||
'audit:stopped',
|
||||
'close-database',
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user