pipework 0.8.11 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/cli/commands/test.d.ts +1 -0
- package/dist/cli/commands/test.d.ts.map +1 -1
- package/dist/cli/commands/test.js +24 -1
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/data/valve/artifact.d.ts +18 -0
- package/dist/data/valve/artifact.d.ts.map +1 -0
- package/dist/data/valve/artifact.js +15 -0
- package/dist/data/valve/artifact.js.map +1 -0
- package/dist/data/valve/contract-diff.d.ts +15 -0
- package/dist/data/valve/contract-diff.d.ts.map +1 -0
- package/dist/data/valve/contract-diff.js +12 -0
- package/dist/data/valve/contract-diff.js.map +1 -0
- package/dist/data/valve/cross.d.ts +15 -0
- package/dist/data/valve/cross.d.ts.map +1 -0
- package/dist/data/valve/cross.js +48 -0
- package/dist/data/valve/cross.js.map +1 -0
- package/dist/data/valve/decision.d.ts +29 -0
- package/dist/data/valve/decision.d.ts.map +1 -0
- package/dist/data/valve/decision.js +19 -0
- package/dist/data/valve/decision.js.map +1 -0
- package/dist/data/valve/faucet.d.ts +18 -0
- package/dist/data/valve/faucet.d.ts.map +1 -0
- package/dist/data/valve/faucet.js +34 -0
- package/dist/data/valve/faucet.js.map +1 -0
- package/dist/data/valve/gate.d.ts +28 -0
- package/dist/data/valve/gate.d.ts.map +1 -0
- package/dist/data/valve/gate.js +74 -0
- package/dist/data/valve/gate.js.map +1 -0
- package/dist/data/valve/graph.d.ts +28 -0
- package/dist/data/valve/graph.d.ts.map +1 -0
- package/dist/data/valve/graph.js +43 -0
- package/dist/data/valve/graph.js.map +1 -0
- package/dist/data/valve/index.d.ts +18 -0
- package/dist/data/valve/index.d.ts.map +1 -0
- package/dist/data/valve/index.js +10 -0
- package/dist/data/valve/index.js.map +1 -0
- package/dist/data/valve/namespace.d.ts +45 -0
- package/dist/data/valve/namespace.d.ts.map +1 -0
- package/dist/data/valve/namespace.js +45 -0
- package/dist/data/valve/namespace.js.map +1 -0
- package/dist/data/valve/registry.d.ts +14 -0
- package/dist/data/valve/registry.d.ts.map +1 -0
- package/dist/data/valve/registry.js +41 -0
- package/dist/data/valve/registry.js.map +1 -0
- package/dist/data/valve/supply.d.ts +33 -0
- package/dist/data/valve/supply.d.ts.map +1 -0
- package/dist/data/valve/supply.js +96 -0
- package/dist/data/valve/supply.js.map +1 -0
- package/dist/data/valve/types.d.ts +138 -0
- package/dist/data/valve/types.d.ts.map +1 -0
- package/dist/data/valve/types.js +2 -0
- package/dist/data/valve/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/test/reap.d.ts +33 -0
- package/dist/test/reap.d.ts.map +1 -0
- package/dist/test/reap.js +117 -0
- package/dist/test/reap.js.map +1 -0
- package/dist/test/setup.d.ts.map +1 -1
- package/dist/test/setup.js +49 -8
- package/dist/test/setup.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import postgres from 'postgres';
|
|
2
|
+
import type { Manifold } from '../core/pipework.js';
|
|
3
|
+
export interface ReapResult {
|
|
4
|
+
readonly droppedDatabases: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Advisory-lock key identifying a test run. A live run holds this lock on a
|
|
8
|
+
* dedicated connection for its entire lifetime; Postgres releases it
|
|
9
|
+
* automatically when that connection ends by any means (clean exit, crash,
|
|
10
|
+
* SIGKILL, reboot). The reaper reads "lock is free" as "owning run is dead".
|
|
11
|
+
*/
|
|
12
|
+
export declare function runLockKey(nonce: string): bigint;
|
|
13
|
+
/** Admin (`/postgres`) connection URL for a database URL. */
|
|
14
|
+
export declare function getAdminUrl(databaseUrl: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Drop test databases left behind by runs that never reached teardown
|
|
17
|
+
* (Ctrl-C, timeout, crash). A database is reaped only when BOTH hold:
|
|
18
|
+
*
|
|
19
|
+
* - its run's advisory lock is free — the owning run's process is gone
|
|
20
|
+
* (a legacy name with no nonce is treated as ownerless); and
|
|
21
|
+
* - `numbackends = 0` — no connections remain, so reaping cannot pull a
|
|
22
|
+
* database out from under workers orphaned by a SIGKILL'd parent.
|
|
23
|
+
*
|
|
24
|
+
* Both conditions only ever make the reaper more conservative, so it can
|
|
25
|
+
* never drop a database belonging to a live or still-provisioning run.
|
|
26
|
+
*/
|
|
27
|
+
export declare function reapOrphanTestDatabases(admin: postgres.Sql): Promise<ReapResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Reap orphan test databases across every Postgres server referenced by the
|
|
30
|
+
* manifold's database config. Used by `pipework test --reap`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function reapConfiguredTestDatabases(instance: Manifold): Promise<ReapResult>;
|
|
33
|
+
//# sourceMappingURL=reap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reap.d.ts","sourceRoot":"","sources":["../../src/test/reap.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAenD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAIvD;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BtF;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBzF"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import postgres from 'postgres';
|
|
2
|
+
import { quoteIdentifier } from '../data/db/identifiers.js';
|
|
3
|
+
const TEST_DB_PREFIX = 'pipework_test_';
|
|
4
|
+
const APP_ROLE_PREFIX = 'pipework_app_';
|
|
5
|
+
// LIKE pattern matching every per-run test database. The backslashes escape the
|
|
6
|
+
// underscores so they match literally rather than as single-char wildcards.
|
|
7
|
+
const TEST_DB_LIKE = 'pipework\\_test\\_%';
|
|
8
|
+
// Per-run test database and role names end with `_<pid>_<nonce>`, where the
|
|
9
|
+
// nonce is 12 random hex chars. The reaper recovers the nonce from a database
|
|
10
|
+
// name to rebuild that run's advisory-lock key.
|
|
11
|
+
const NONCE_SUFFIX = /_([0-9a-f]{12})$/;
|
|
12
|
+
/**
|
|
13
|
+
* Advisory-lock key identifying a test run. A live run holds this lock on a
|
|
14
|
+
* dedicated connection for its entire lifetime; Postgres releases it
|
|
15
|
+
* automatically when that connection ends by any means (clean exit, crash,
|
|
16
|
+
* SIGKILL, reboot). The reaper reads "lock is free" as "owning run is dead".
|
|
17
|
+
*/
|
|
18
|
+
export function runLockKey(nonce) {
|
|
19
|
+
return BigInt('0x' + nonce);
|
|
20
|
+
}
|
|
21
|
+
/** Admin (`/postgres`) connection URL for a database URL. */
|
|
22
|
+
export function getAdminUrl(databaseUrl) {
|
|
23
|
+
const url = new URL(databaseUrl);
|
|
24
|
+
url.pathname = '/postgres';
|
|
25
|
+
return url.toString();
|
|
26
|
+
}
|
|
27
|
+
function pairedRoleName(datname) {
|
|
28
|
+
return APP_ROLE_PREFIX + datname.slice(TEST_DB_PREFIX.length);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Drop test databases left behind by runs that never reached teardown
|
|
32
|
+
* (Ctrl-C, timeout, crash). A database is reaped only when BOTH hold:
|
|
33
|
+
*
|
|
34
|
+
* - its run's advisory lock is free — the owning run's process is gone
|
|
35
|
+
* (a legacy name with no nonce is treated as ownerless); and
|
|
36
|
+
* - `numbackends = 0` — no connections remain, so reaping cannot pull a
|
|
37
|
+
* database out from under workers orphaned by a SIGKILL'd parent.
|
|
38
|
+
*
|
|
39
|
+
* Both conditions only ever make the reaper more conservative, so it can
|
|
40
|
+
* never drop a database belonging to a live or still-provisioning run.
|
|
41
|
+
*/
|
|
42
|
+
export async function reapOrphanTestDatabases(admin) {
|
|
43
|
+
const rows = await admin `
|
|
44
|
+
SELECT datname, numbackends
|
|
45
|
+
FROM pg_stat_database
|
|
46
|
+
WHERE datname LIKE ${TEST_DB_LIKE}
|
|
47
|
+
`;
|
|
48
|
+
const droppedDatabases = [];
|
|
49
|
+
for (const { datname, numbackends } of rows) {
|
|
50
|
+
if (numbackends > 0)
|
|
51
|
+
continue;
|
|
52
|
+
const nonce = NONCE_SUFFIX.exec(datname)?.[1];
|
|
53
|
+
const key = nonce === undefined ? null : runLockKey(nonce);
|
|
54
|
+
if (key !== null && !(await tryAcquire(admin, key)))
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
if (await dropDatabase(admin, datname)) {
|
|
58
|
+
droppedDatabases.push(datname);
|
|
59
|
+
await dropRole(admin, pairedRoleName(datname));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
if (key !== null) {
|
|
64
|
+
await admin `SELECT pg_advisory_unlock(${key.toString()}::bigint)`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { droppedDatabases };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Reap orphan test databases across every Postgres server referenced by the
|
|
72
|
+
* manifold's database config. Used by `pipework test --reap`.
|
|
73
|
+
*/
|
|
74
|
+
export async function reapConfiguredTestDatabases(instance) {
|
|
75
|
+
const adminUrls = new Set();
|
|
76
|
+
for (const [, dbConfig] of instance.config.databases()) {
|
|
77
|
+
adminUrls.add(getAdminUrl(dbConfig.url));
|
|
78
|
+
}
|
|
79
|
+
const droppedDatabases = [];
|
|
80
|
+
for (const adminUrl of adminUrls) {
|
|
81
|
+
const client = postgres(adminUrl, { max: 1, onnotice: () => { } });
|
|
82
|
+
try {
|
|
83
|
+
const result = await reapOrphanTestDatabases(client);
|
|
84
|
+
droppedDatabases.push(...result.droppedDatabases);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await client.end();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { droppedDatabases };
|
|
91
|
+
}
|
|
92
|
+
async function tryAcquire(admin, key) {
|
|
93
|
+
const rows = await admin `
|
|
94
|
+
SELECT pg_try_advisory_lock(${key.toString()}::bigint) AS locked
|
|
95
|
+
`;
|
|
96
|
+
return rows[0]?.locked === true;
|
|
97
|
+
}
|
|
98
|
+
async function dropDatabase(admin, datname) {
|
|
99
|
+
try {
|
|
100
|
+
await admin.unsafe(`DROP DATABASE IF EXISTS ${quoteIdentifier(datname, 'database')}`);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// A backend connected between the numbackends check and the DROP — leave
|
|
105
|
+
// this database for the next run's reaper.
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function dropRole(admin, role) {
|
|
110
|
+
try {
|
|
111
|
+
await admin.unsafe(`DROP ROLE IF EXISTS ${quoteIdentifier(role, 'role')}`);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Role still owns objects in another database — best effort.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=reap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reap.js","sourceRoot":"","sources":["../../src/test/reap.ts"],"names":[],"mappings":"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"}
|
package/dist/test/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAMnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAoBD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAa/F;AAyGD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAsC3D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEtE;AAED,wBAAgB,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAEpE"}
|
package/dist/test/setup.js
CHANGED
|
@@ -1,28 +1,59 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
1
2
|
import postgres from 'postgres';
|
|
2
3
|
import { drizzle } from '../data/query/postgres-js/index.js';
|
|
3
4
|
import { sql } from '../data/query/index.js';
|
|
4
5
|
import { quoteIdentifier } from '../data/db/identifiers.js';
|
|
5
6
|
import { applyMigrations } from '../data/migrate/apply.js';
|
|
7
|
+
import { getAdminUrl, reapOrphanTestDatabases, runLockKey } from './reap.js';
|
|
6
8
|
const testDatabases = new Map();
|
|
7
9
|
let adminClient = null;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
// A random per-process fingerprint, embedded in every database and role name
|
|
11
|
+
// this run creates. It keys the advisory lock the run holds for its lifetime,
|
|
12
|
+
// letting another run's reaper tell this run's databases apart from orphans.
|
|
13
|
+
const runNonce = randomBytes(6).toString('hex');
|
|
14
|
+
let lockClient = null;
|
|
15
|
+
let reaped = false;
|
|
13
16
|
function testDbName(baseName) {
|
|
14
|
-
return `pipework_test_${baseName}_${process.pid}`;
|
|
17
|
+
return `pipework_test_${baseName}_${process.pid}_${runNonce}`;
|
|
15
18
|
}
|
|
16
19
|
function appRoleName(baseName) {
|
|
17
|
-
return `pipework_app_${baseName}_${process.pid}`;
|
|
20
|
+
return `pipework_app_${baseName}_${process.pid}_${runNonce}`;
|
|
18
21
|
}
|
|
19
22
|
export async function setupTestDatabases(instance) {
|
|
20
|
-
|
|
23
|
+
const databases = [...instance.config.databases()];
|
|
24
|
+
const firstDb = databases[0];
|
|
25
|
+
if (firstDb !== undefined) {
|
|
26
|
+
await prepareRun(getAdminUrl(firstDb[1].url));
|
|
27
|
+
}
|
|
28
|
+
for (const [name, dbConfig] of databases) {
|
|
21
29
|
const testDb = await createTestDatabase(name, dbConfig);
|
|
22
30
|
testDatabases.set(name, testDb);
|
|
23
31
|
}
|
|
24
32
|
return testDatabases;
|
|
25
33
|
}
|
|
34
|
+
// Acquire this run's advisory lock and reap orphans before provisioning. The
|
|
35
|
+
// lock is taken before the first CREATE DATABASE so a concurrent run's reaper
|
|
36
|
+
// can never mistake this run's freshly-created, backend-less databases for
|
|
37
|
+
// orphans. It is held on a dedicated connection (idle/lifetime timeouts off)
|
|
38
|
+
// so Postgres releases it only when this process dies.
|
|
39
|
+
async function prepareRun(adminUrl) {
|
|
40
|
+
if (adminClient === null) {
|
|
41
|
+
adminClient = postgres(adminUrl, { max: 1, onnotice: () => { } });
|
|
42
|
+
}
|
|
43
|
+
if (lockClient === null) {
|
|
44
|
+
lockClient = postgres(adminUrl, { max: 1, idle_timeout: 0, max_lifetime: 0, onnotice: () => { } });
|
|
45
|
+
await lockClient `SELECT pg_advisory_lock(${runLockKey(runNonce).toString()}::bigint)`;
|
|
46
|
+
}
|
|
47
|
+
if (!reaped) {
|
|
48
|
+
reaped = true;
|
|
49
|
+
try {
|
|
50
|
+
await reapOrphanTestDatabases(adminClient);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Reaping is best effort — never let stale-orphan cleanup break setup.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
26
57
|
async function createTestDatabase(name, dbConfig) {
|
|
27
58
|
const adminUrl = getAdminUrl(dbConfig.url);
|
|
28
59
|
if (!adminClient) {
|
|
@@ -80,6 +111,16 @@ async function provisionAppRole(client, testUrl, dbName, roleName) {
|
|
|
80
111
|
return appUrl.toString();
|
|
81
112
|
}
|
|
82
113
|
export async function teardownTestDatabases() {
|
|
114
|
+
if (lockClient !== null) {
|
|
115
|
+
try {
|
|
116
|
+
await lockClient `SELECT pg_advisory_unlock(${runLockKey(runNonce).toString()}::bigint)`;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Connection already gone — Postgres released the lock when it died.
|
|
120
|
+
}
|
|
121
|
+
await lockClient.end();
|
|
122
|
+
lockClient = null;
|
|
123
|
+
}
|
|
83
124
|
if (!adminClient)
|
|
84
125
|
return;
|
|
85
126
|
const admin = drizzle(adminClient);
|
package/dist/test/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAA;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"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"}
|