@substrat-run/contract-tests 0.159.0 → 0.161.0
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/dist/attachment-bytes-suite.d.ts +9 -0
- package/dist/attachment-bytes-suite.d.ts.map +1 -0
- package/dist/attachment-bytes-suite.js +97 -0
- package/dist/attachment-bytes-suite.js.map +1 -0
- package/dist/connector-fixture.d.ts +2 -2
- package/dist/connector-fixture.d.ts.map +1 -1
- package/dist/directory-audit-suite.d.ts +23 -0
- package/dist/directory-audit-suite.d.ts.map +1 -0
- package/dist/directory-audit-suite.js +560 -0
- package/dist/directory-audit-suite.js.map +1 -0
- package/dist/directory-restore-suite.d.ts.map +1 -1
- package/dist/directory-restore-suite.js +99 -0
- package/dist/directory-restore-suite.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/introspection-reads-suite.d.ts +35 -0
- package/dist/introspection-reads-suite.d.ts.map +1 -0
- package/dist/introspection-reads-suite.js +114 -0
- package/dist/introspection-reads-suite.js.map +1 -0
- package/dist/many-migrations-suite.d.ts +9 -0
- package/dist/many-migrations-suite.d.ts.map +1 -0
- package/dist/many-migrations-suite.js +76 -0
- package/dist/many-migrations-suite.js.map +1 -0
- package/dist/many-migrations.d.ts +16 -0
- package/dist/many-migrations.d.ts.map +1 -0
- package/dist/many-migrations.js +50 -0
- package/dist/many-migrations.js.map +1 -0
- package/dist/membership-executor-suite.d.ts.map +1 -1
- package/dist/membership-executor-suite.js +8 -5
- package/dist/membership-executor-suite.js.map +1 -1
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +10 -0
- package/dist/modules.js.map +1 -1
- package/dist/reserved-role-suite.d.ts +6 -0
- package/dist/reserved-role-suite.d.ts.map +1 -1
- package/dist/reserved-role-suite.js +176 -8
- package/dist/reserved-role-suite.js.map +1 -1
- package/dist/restore-role-suite.d.ts +17 -0
- package/dist/restore-role-suite.d.ts.map +1 -0
- package/dist/restore-role-suite.js +107 -0
- package/dist/restore-role-suite.js.map +1 -0
- package/dist/role-state-suite.d.ts +17 -0
- package/dist/role-state-suite.d.ts.map +1 -0
- package/dist/role-state-suite.js +80 -0
- package/dist/role-state-suite.js.map +1 -0
- package/dist/schedule-platform-requests-suite.d.ts +7 -1
- package/dist/schedule-platform-requests-suite.d.ts.map +1 -1
- package/dist/schedule-platform-requests-suite.js +349 -2
- package/dist/schedule-platform-requests-suite.js.map +1 -1
- package/dist/schedule-purge-request-module.d.ts +88 -0
- package/dist/schedule-purge-request-module.d.ts.map +1 -0
- package/dist/schedule-purge-request-module.js +114 -0
- package/dist/schedule-purge-request-module.js.map +1 -0
- package/dist/schedule-purge-two-module.d.ts +141 -0
- package/dist/schedule-purge-two-module.d.ts.map +1 -0
- package/dist/schedule-purge-two-module.js +153 -0
- package/dist/schedule-purge-two-module.js.map +1 -0
- package/dist/scope-host-suite.d.ts.map +1 -1
- package/dist/scope-host-suite.js +1329 -8
- package/dist/scope-host-suite.js.map +1 -1
- package/dist/size-reads-suite.d.ts +20 -0
- package/dist/size-reads-suite.d.ts.map +1 -0
- package/dist/size-reads-suite.js +77 -0
- package/dist/size-reads-suite.js.map +1 -0
- package/dist/stored-vertical-copy-suite.d.ts +15 -0
- package/dist/stored-vertical-copy-suite.d.ts.map +1 -0
- package/dist/stored-vertical-copy-suite.js +68 -0
- package/dist/stored-vertical-copy-suite.js.map +1 -0
- package/dist/unreadable-scope-row-suite.d.ts +16 -0
- package/dist/unreadable-scope-row-suite.d.ts.map +1 -0
- package/dist/unreadable-scope-row-suite.js +152 -0
- package/dist/unreadable-scope-row-suite.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { platformActorId, principalId, scopeId, tenantId } from '@substrat-run/contracts';
|
|
3
|
+
import { releaseRoleSetRefusal, ulid } from '@substrat-run/kernel';
|
|
4
|
+
/**
|
|
5
|
+
* #2446: `roleStateLocal`, the state a promote judges the incoming version's role set against
|
|
6
|
+
* before it moves a scope, reads the same on both adapters: the roles the host stores for the
|
|
7
|
+
* tenant (with their holders), and the role keys anyone holds a live scope-level seat in at that
|
|
8
|
+
* scope (`SCOPE_SEATED_ROLES_SQL`). A tenant-level seat is not a scope's; a revoked seat is not a
|
|
9
|
+
* seat. It names no principal. And the promote's question over it (`releaseRoleSetRefusal`) refuses
|
|
10
|
+
* a seated person's role made `holder: 'system'` and admits its unseated twin.
|
|
11
|
+
*/
|
|
12
|
+
export function roleStateContractSuite(adapterName, makeFixture) {
|
|
13
|
+
describe(`a scope's role state, as a promote reads it (#2446): ${adapterName}`, () => {
|
|
14
|
+
let fixture;
|
|
15
|
+
const staff = platformActorId.parse(ulid());
|
|
16
|
+
const t = tenantId.parse(ulid());
|
|
17
|
+
const s = scopeId.parse(ulid());
|
|
18
|
+
const other = scopeId.parse(ulid());
|
|
19
|
+
const alice = principalId.parse(ulid());
|
|
20
|
+
const bob = principalId.parse(ulid());
|
|
21
|
+
const carol = principalId.parse(ulid());
|
|
22
|
+
const USE = 'rst:use';
|
|
23
|
+
const RUN = 'rst:run';
|
|
24
|
+
const flip = {
|
|
25
|
+
permissions: [{ key: USE }, { key: RUN, holder: 'system' }],
|
|
26
|
+
roles: [{ key: 'member', permissions: [RUN], holder: 'system' }],
|
|
27
|
+
};
|
|
28
|
+
beforeAll(async () => {
|
|
29
|
+
fixture = await makeFixture();
|
|
30
|
+
const { host } = fixture;
|
|
31
|
+
await host.admin.createTenant(staff, { id: t, slug: `role-state-${t.slice(-8).toLowerCase()}`, name: 'Role state' });
|
|
32
|
+
for (const id of [s, other]) {
|
|
33
|
+
await host.provisionScope(staff, { tenantId: t, scopeId: id, vertical: 'role-state' });
|
|
34
|
+
await host.admin.activateScope(staff, t, id);
|
|
35
|
+
}
|
|
36
|
+
const roles = [
|
|
37
|
+
{ key: 'member', permissions: [USE], source: 'vertical' },
|
|
38
|
+
{ key: 'runner', permissions: [RUN], source: 'vertical', holder: 'system' },
|
|
39
|
+
{ key: 'tenant-wide', permissions: [USE], source: 'vertical' },
|
|
40
|
+
{ key: 'elsewhere', permissions: [USE], source: 'vertical' },
|
|
41
|
+
];
|
|
42
|
+
for (const role of roles)
|
|
43
|
+
await host.admin.defineRole(staff, t, role);
|
|
44
|
+
for (const id of [s, other])
|
|
45
|
+
await fixture.projectRoles?.(t, id, roles);
|
|
46
|
+
await host.admin.assignRole(staff, { principalId: alice, roleKey: 'member', node: { tenantId: t, scopeId: s } });
|
|
47
|
+
await host.admin.assignRole(staff, { principalId: bob, roleKey: 'tenant-wide', node: { tenantId: t, scopeId: null } });
|
|
48
|
+
await host.admin.assignRole(staff, { principalId: carol, roleKey: 'elsewhere', node: { tenantId: t, scopeId: other } });
|
|
49
|
+
});
|
|
50
|
+
afterAll(async () => fixture?.cleanup());
|
|
51
|
+
it('reads the tenant’s stored roles with their holders, and the scope-level seats there', async () => {
|
|
52
|
+
const state = await fixture.roleState(t, s);
|
|
53
|
+
const byKey = Object.fromEntries(state.roles.map((r) => [r.key, r]));
|
|
54
|
+
expect(byKey['member']).toMatchObject({ key: 'member', permissions: [USE] });
|
|
55
|
+
expect(byKey['member']?.holder ?? 'person').toBe('person');
|
|
56
|
+
expect(byKey['runner']).toEqual({ key: 'runner', permissions: [RUN], holder: 'system' });
|
|
57
|
+
// A tenant-level seat (bob's) is not this scope's.
|
|
58
|
+
expect(state.seated).toEqual(['member']);
|
|
59
|
+
// A seat in another scope of the tenant is that scope's, not this one's.
|
|
60
|
+
expect((await fixture.roleState(t, other)).seated).toEqual(['elsewhere']);
|
|
61
|
+
});
|
|
62
|
+
it('names role keys only, never a principal', async () => {
|
|
63
|
+
const wire = JSON.stringify(await fixture.roleState(t, s));
|
|
64
|
+
expect(wire).not.toContain(alice);
|
|
65
|
+
expect(wire).not.toContain(bob);
|
|
66
|
+
expect(JSON.stringify(await fixture.roleState(t, other))).not.toContain(carol);
|
|
67
|
+
});
|
|
68
|
+
it('the promote’s question over it refuses a seated person’s role made holder: system; twin: another scope passes', async () => {
|
|
69
|
+
expect(releaseRoleSetRefusal(flip, await fixture.roleState(t, s))).toMatch(/^role 'member' is held by a principal \(stored as a person's role\), so it cannot be declared holder: 'system'/);
|
|
70
|
+
expect(releaseRoleSetRefusal(flip, await fixture.roleState(t, other))).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
it('a revoked seat is no seat, and the same release then passes', async () => {
|
|
73
|
+
await fixture.host.admin.unassignRole(staff, { principalId: alice, roleKey: 'member', node: { tenantId: t, scopeId: s } });
|
|
74
|
+
const state = await fixture.roleState(t, s);
|
|
75
|
+
expect(state.seated).toEqual([]);
|
|
76
|
+
expect(releaseRoleSetRefusal(flip, state)).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=role-state-suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-state-suite.js","sourceRoot":"","sources":["../src/role-state-suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ScopeHostFixture } from './scope-host-suite.js';
|
|
2
|
+
import type { RawScopeSql } from './entity-state-suite.js';
|
|
2
3
|
/**
|
|
3
4
|
* Contract suite for #2431: a scheduled pass REPORTS the platform requests its fires enqueued, so
|
|
4
5
|
* the sweep that ran it can drain the scope in the same pass instead of leaving them a sweep
|
|
@@ -8,5 +9,10 @@ import type { ScopeHostFixture } from './scope-host-suite.js';
|
|
|
8
9
|
* `runDueSchedules` is called directly, never a sweep, so registering this module changes no
|
|
9
10
|
* other suite's fired/skipped counts, and the shared directory is safe.
|
|
10
11
|
*/
|
|
11
|
-
export declare function schedulePlatformRequestsContractSuite(adapterName: string, makeFixture: () => Promise<ScopeHostFixture
|
|
12
|
+
export declare function schedulePlatformRequestsContractSuite(adapterName: string, makeFixture: () => Promise<ScopeHostFixture>,
|
|
13
|
+
/**
|
|
14
|
+
* Runs SQL against a scope's own storage — to age a binned row past its purge horizon. Optional so
|
|
15
|
+
* the export stays additive: without it the purge-horizon cases are skipped, the rest run.
|
|
16
|
+
*/
|
|
17
|
+
raw?: RawScopeSql): void;
|
|
12
18
|
//# sourceMappingURL=schedule-platform-requests-suite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-platform-requests-suite.d.ts","sourceRoot":"","sources":["../src/schedule-platform-requests-suite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schedule-platform-requests-suite.d.ts","sourceRoot":"","sources":["../src/schedule-platform-requests-suite.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAwB3D;;;;;;;;GAQG;AACH,wBAAgB,qCAAqC,CACnD,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC;AAC5C;;;GAGG;AACH,GAAG,CAAC,EAAE,WAAW,GAChB,IAAI,CA4ZN"}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
-
import { isPlatformRequest, moduleId, platformActorId, scopeId, tenantId } from '@substrat-run/contracts';
|
|
2
|
+
import { MAX_PENDING_PLATFORM_REQUESTS, isPlatformRequest, moduleId, permissionKey, platformActorId, principalId, scopeId, tenantId, } from '@substrat-run/contracts';
|
|
3
3
|
import { ulid } from '@substrat-run/kernel';
|
|
4
4
|
import { SCHED_REQUEST_KIND, schedRequestMod } from './modules.js';
|
|
5
|
+
import { GREEDY_PURGE_ROW, PURGE_REQUEST_DAYS, PURGE_REQUEST_KIND, PURGE_REQUEST_MODULE_ID, QUIET_PURGE_ROW, purgeRequestMod, } from './schedule-purge-request-module.js';
|
|
6
|
+
import { FILL_TWO_ROW, PURGE_TWO_DAYS, PURGE_TWO_KIND, PURGE_TWO_MODULE_ID, QUIET_TWO_ROW, purgeTwoMod, } from './schedule-purge-two-module.js';
|
|
5
7
|
const SCHED_REQUEST = moduleId.parse('@test/sched-request');
|
|
8
|
+
const PURGE_REQUEST = moduleId.parse(PURGE_REQUEST_MODULE_ID);
|
|
9
|
+
const PURGE_TWO = moduleId.parse(PURGE_TWO_MODULE_ID);
|
|
10
|
+
const DAY = 86_400_000;
|
|
6
11
|
/**
|
|
7
12
|
* Contract suite for #2431: a scheduled pass REPORTS the platform requests its fires enqueued, so
|
|
8
13
|
* the sweep that ran it can drain the scope in the same pass instead of leaving them a sweep
|
|
@@ -12,22 +17,33 @@ const SCHED_REQUEST = moduleId.parse('@test/sched-request');
|
|
|
12
17
|
* `runDueSchedules` is called directly, never a sweep, so registering this module changes no
|
|
13
18
|
* other suite's fired/skipped counts, and the shared directory is safe.
|
|
14
19
|
*/
|
|
15
|
-
export function schedulePlatformRequestsContractSuite(adapterName, makeFixture
|
|
20
|
+
export function schedulePlatformRequestsContractSuite(adapterName, makeFixture,
|
|
21
|
+
/**
|
|
22
|
+
* Runs SQL against a scope's own storage — to age a binned row past its purge horizon. Optional so
|
|
23
|
+
* the export stays additive: without it the purge-horizon cases are skipped, the rest run.
|
|
24
|
+
*/
|
|
25
|
+
raw) {
|
|
16
26
|
describe(`a scheduled pass reports the platform requests it enqueued (#2431): ${adapterName}`, () => {
|
|
17
27
|
let fixture;
|
|
18
28
|
let host;
|
|
19
29
|
const t = tenantId.parse(ulid());
|
|
20
30
|
const s = scopeId.parse(ulid());
|
|
21
31
|
const staff = platformActorId.parse(ulid());
|
|
32
|
+
const alice = principalId.parse(ulid());
|
|
22
33
|
beforeAll(async () => {
|
|
23
34
|
fixture = await makeFixture();
|
|
24
35
|
host = fixture.host;
|
|
25
36
|
host.registerModule(schedRequestMod);
|
|
37
|
+
host.registerModule(purgeRequestMod);
|
|
38
|
+
host.registerModule(purgeTwoMod);
|
|
26
39
|
await host.admin.createTenant(staff, { id: t, slug: `sched-request-${t.toLowerCase()}`, name: 'Scheduled requests' });
|
|
27
40
|
await host.admin.grantEntitlement(staff, t, 'sched');
|
|
28
41
|
// Seats the schedules' declared permission on the module's system principal.
|
|
29
42
|
await host.provisionScope(staff, { tenantId: t, scopeId: s, vertical: 'sched-request-vertical' });
|
|
30
43
|
await host.admin.activateScope(staff, t, s);
|
|
44
|
+
const keys = ['purgereq:write', 'purgereq:trash', 'purgetwo:write', 'purgetwo:trash-a', 'purgetwo:trash-b'].map((k) => permissionKey.parse(k));
|
|
45
|
+
await host.admin.defineRole(staff, t, { key: 'purger', permissions: keys, source: 'vertical' });
|
|
46
|
+
await host.admin.assignRole(staff, { principalId: alice, roleKey: 'purger', node: { tenantId: t, scopeId: null } });
|
|
31
47
|
});
|
|
32
48
|
afterAll(async () => {
|
|
33
49
|
await fixture.cleanup();
|
|
@@ -50,6 +66,337 @@ export function schedulePlatformRequestsContractSuite(adapterName, makeFixture)
|
|
|
50
66
|
expect(report.platformRequests).toBeUndefined();
|
|
51
67
|
expect(await queued()).toEqual([1, 2]);
|
|
52
68
|
});
|
|
69
|
+
// Skipped when the host passes no `raw` SQL door: the rows cannot be aged past the horizon.
|
|
70
|
+
describe.skipIf(raw === undefined)('a purge horizon (#2440)', () => {
|
|
71
|
+
/** A new primary scope, so the schedule's cadence row starts empty. */
|
|
72
|
+
const freshScope = async () => {
|
|
73
|
+
const fresh = scopeId.parse(ulid());
|
|
74
|
+
await host.provisionScope(staff, { tenantId: t, scopeId: fresh, vertical: 'sched-request-vertical' });
|
|
75
|
+
await host.admin.activateScope(staff, t, fresh);
|
|
76
|
+
return fresh;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* `names.length` rows, binned and aged past the horizon, so one pass purges them all. Returns
|
|
80
|
+
* their ids, oldest first: aged by one minute each, so the purge walk takes them in this order.
|
|
81
|
+
*/
|
|
82
|
+
const dueRows = async (fresh, names) => {
|
|
83
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
84
|
+
const base = Date.now() - (PURGE_REQUEST_DAYS + 1) * DAY;
|
|
85
|
+
const ids = [];
|
|
86
|
+
for (const [n, name] of names.entries()) {
|
|
87
|
+
const id = `row-${String(n).padStart(3, '0')}-${ulid()}`;
|
|
88
|
+
const at = new Date(base + n * 60_000).toISOString();
|
|
89
|
+
await stub.invoke('purgereq/add', { id, name });
|
|
90
|
+
await stub.invoke('purgereq/trash', { rowId: id });
|
|
91
|
+
await raw(t, fresh, `INSERT INTO _substrat_state_moves (entity_type, entity_id) VALUES (?, ?)`, ['preq', id]);
|
|
92
|
+
await raw(t, fresh, `UPDATE purgereq_rows SET _substrat_trashed_at = ? WHERE id = ?`, [at, id]);
|
|
93
|
+
await raw(t, fresh, `DELETE FROM _substrat_state_moves WHERE entity_type = ? AND entity_id = ?`, ['preq', id]);
|
|
94
|
+
ids.push(id);
|
|
95
|
+
}
|
|
96
|
+
return ids;
|
|
97
|
+
};
|
|
98
|
+
/** Which of `ids` the purge deleted: re-adding a row that still exists is refused by its primary key. */
|
|
99
|
+
const purged = async (fresh, ids) => {
|
|
100
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const id of ids) {
|
|
103
|
+
try {
|
|
104
|
+
await stub.invoke('purgereq/add', { id, name: 'again' });
|
|
105
|
+
out.push(id);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// still there
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
};
|
|
113
|
+
/** The row ids the purges requested for, in no particular order. */
|
|
114
|
+
const requestedRows = async (fresh) => (await host.listPlatformRequestHistory(t, fresh, { kind: PURGE_REQUEST_KIND, limit: 200 }))
|
|
115
|
+
.filter(isPlatformRequest)
|
|
116
|
+
.map((r) => r.payload.rowId);
|
|
117
|
+
/** The platform's drain, as far as a test needs it: every pending request settles `done`. */
|
|
118
|
+
const drainAll = async (fresh) => {
|
|
119
|
+
for (const r of (await host.listPlatformRequests(t, fresh)).filter(isPlatformRequest)) {
|
|
120
|
+
await host.settlePlatformRequest(t, fresh, r.id, { status: 'done' });
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const purgeRequests = async (fresh) => (await host.listPlatformRequests(t, fresh)).filter(isPlatformRequest).filter((r) => r.kind === PURGE_REQUEST_KIND);
|
|
124
|
+
it('counts the requests every purge in the pass enqueued', async () => {
|
|
125
|
+
const fresh = await freshScope();
|
|
126
|
+
await dueRows(fresh, ['one', 'two']);
|
|
127
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
128
|
+
expect(report).toMatchObject({ fired: 1, failed: 0, errors: [], platformRequests: 2 });
|
|
129
|
+
// The journal agrees: both purges committed their request.
|
|
130
|
+
expect(await purgeRequests(fresh)).toHaveLength(2);
|
|
131
|
+
});
|
|
132
|
+
it('counts only the purges that enqueued one', async () => {
|
|
133
|
+
const fresh = await freshScope();
|
|
134
|
+
await dueRows(fresh, ['one', QUIET_PURGE_ROW]);
|
|
135
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
136
|
+
expect(report).toMatchObject({ fired: 1, failed: 0, platformRequests: 1 });
|
|
137
|
+
expect(await purgeRequests(fresh)).toHaveLength(1);
|
|
138
|
+
});
|
|
139
|
+
it('twin: a pass whose purges enqueue none reports no count', async () => {
|
|
140
|
+
const fresh = await freshScope();
|
|
141
|
+
await dueRows(fresh, [QUIET_PURGE_ROW, QUIET_PURGE_ROW]);
|
|
142
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
143
|
+
expect(report).toMatchObject({ fired: 1, failed: 0 });
|
|
144
|
+
expect(report.platformRequests).toBeUndefined();
|
|
145
|
+
expect(await purgeRequests(fresh)).toHaveLength(0);
|
|
146
|
+
});
|
|
147
|
+
// #2506: a batch (PURGE_BATCH, 50) can hold more due entities than the scope's queue has room
|
|
148
|
+
// for (MAX_PENDING_PLATFORM_REQUESTS, 32). Past the head of the pass, the cap is a "not yet",
|
|
149
|
+
// never a failure of the entity; AT the head it is a failure like any other, so nothing that
|
|
150
|
+
// needs no request, and nothing behind an entity that can never fit, is held up by it.
|
|
151
|
+
describe('a batch larger than the pending cap (#2506)', () => {
|
|
152
|
+
const OVER = MAX_PENDING_PLATFORM_REQUESTS + 8;
|
|
153
|
+
const names = (n, name = 'row') => Array.from({ length: n }, () => name);
|
|
154
|
+
const Q = QUIET_PURGE_ROW;
|
|
155
|
+
it('stops at the cap without failing, and the next pass after the drain finishes the lap', async () => {
|
|
156
|
+
const fresh = await freshScope();
|
|
157
|
+
const ids = await dueRows(fresh, names(OVER));
|
|
158
|
+
const first = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
159
|
+
// The pass filled the queue, purged what fit, and reported no failure: the rest is still due.
|
|
160
|
+
expect(first).toMatchObject({ fired: 1, failed: 0, errors: [], platformRequests: MAX_PENDING_PLATFORM_REQUESTS });
|
|
161
|
+
expect(await purgeRequests(fresh)).toHaveLength(MAX_PENDING_PLATFORM_REQUESTS);
|
|
162
|
+
// Oldest first, and exactly the ones that fit: nothing past the cap was purged.
|
|
163
|
+
expect(await purged(fresh, ids)).toEqual(ids.slice(0, MAX_PENDING_PLATFORM_REQUESTS));
|
|
164
|
+
await drainAll(fresh);
|
|
165
|
+
// The schedule stayed due (no cadence wait), and the lap resumes at the first deferred row.
|
|
166
|
+
const second = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
167
|
+
expect(second).toMatchObject({ fired: 1, failed: 0, errors: [], platformRequests: OVER - MAX_PENDING_PLATFORM_REQUESTS });
|
|
168
|
+
expect([...(await requestedRows(fresh))].sort()).toEqual([...ids].sort());
|
|
169
|
+
// The lap closed: every row is gone (the first ones were re-added above; the rest here).
|
|
170
|
+
expect(await purged(fresh, ids.slice(MAX_PENDING_PLATFORM_REQUESTS))).toEqual(ids.slice(MAX_PENDING_PLATFORM_REQUESTS));
|
|
171
|
+
});
|
|
172
|
+
it('a queue that stays full fails the entities it refuses once, and the lap waits its cadence', async () => {
|
|
173
|
+
const fresh = await freshScope();
|
|
174
|
+
const ids = await dueRows(fresh, names(OVER));
|
|
175
|
+
await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
176
|
+
// No drain: the second pass meets a full queue at its very first entity, as a failure.
|
|
177
|
+
const stuck = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
178
|
+
expect(stuck).toMatchObject({ fired: 0, failed: 1 });
|
|
179
|
+
expect(stuck.errors).toHaveLength(OVER - MAX_PENDING_PLATFORM_REQUESTS);
|
|
180
|
+
expect(stuck.errors[0]).toEqual({
|
|
181
|
+
operation: expect.stringContaining('purgereq/purge'),
|
|
182
|
+
error: expect.stringMatching(/too many pending platform requests \(\d+\)/),
|
|
183
|
+
});
|
|
184
|
+
expect(stuck.platformRequests).toBeUndefined();
|
|
185
|
+
expect(await purgeRequests(fresh)).toHaveLength(MAX_PENDING_PLATFORM_REQUESTS);
|
|
186
|
+
// The lap closed: it does not retry on every sweep tick, and nothing past the cap was lost.
|
|
187
|
+
await drainAll(fresh);
|
|
188
|
+
const waiting = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
189
|
+
expect(waiting).toMatchObject({ fired: 0, failed: 0 });
|
|
190
|
+
expect(await purged(fresh, ids.slice(MAX_PENDING_PLATFORM_REQUESTS))).toEqual([]);
|
|
191
|
+
});
|
|
192
|
+
it('twin: purges that enqueue nothing are not held to the cap, however many are due', async () => {
|
|
193
|
+
const fresh = await freshScope();
|
|
194
|
+
const ids = await dueRows(fresh, names(OVER, Q));
|
|
195
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
196
|
+
expect(report).toMatchObject({ fired: 1, failed: 0, errors: [] });
|
|
197
|
+
expect(report.platformRequests).toBeUndefined();
|
|
198
|
+
expect(await purged(fresh, ids)).toEqual(ids);
|
|
199
|
+
});
|
|
200
|
+
it('a purge that can never fit does not starve what is behind it', async () => {
|
|
201
|
+
const fresh = await freshScope();
|
|
202
|
+
// Oldest first: a quiet row, one that needs more slots than a scope has, two quiet rows.
|
|
203
|
+
const ids = await dueRows(fresh, [Q, GREEDY_PURGE_ROW, Q, Q]);
|
|
204
|
+
// Pass one is past its head when it meets the greedy row, so it only stops there...
|
|
205
|
+
const first = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
206
|
+
expect(first).toMatchObject({ fired: 1, failed: 0, errors: [] });
|
|
207
|
+
expect(await purged(fresh, [ids[0]])).toEqual([ids[0]]);
|
|
208
|
+
// ...and pass two, which stays due, has it as the head: a failure like any other, and the walk moves on.
|
|
209
|
+
const second = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
210
|
+
expect(second).toMatchObject({ fired: 0, failed: 1 });
|
|
211
|
+
expect(second.errors).toEqual([
|
|
212
|
+
{ operation: expect.stringContaining('purgereq/purge'), error: expect.stringMatching(/too many pending platform requests/) },
|
|
213
|
+
]);
|
|
214
|
+
expect(await purged(fresh, [ids[2], ids[3]])).toEqual([ids[2], ids[3]]);
|
|
215
|
+
// It never committed a request, and stays in the bin.
|
|
216
|
+
expect(await purgeRequests(fresh)).toHaveLength(0);
|
|
217
|
+
expect(await purged(fresh, [ids[1]])).toEqual([]);
|
|
218
|
+
});
|
|
219
|
+
it('twin: the same walk with an ordinary row in place of the greedy one purges everything without a failure', async () => {
|
|
220
|
+
const fresh = await freshScope();
|
|
221
|
+
const ids = await dueRows(fresh, [Q, 'row', Q, Q]);
|
|
222
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
223
|
+
expect(report).toMatchObject({ fired: 1, failed: 0, errors: [], platformRequests: 1 });
|
|
224
|
+
expect(await purged(fresh, ids)).toEqual(ids);
|
|
225
|
+
});
|
|
226
|
+
it('a queue held full by other traffic refuses the head, and the purges behind it that need no request still commit', async () => {
|
|
227
|
+
const fresh = await freshScope();
|
|
228
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
229
|
+
await stub.invoke('purgereq/enqueue', { count: MAX_PENDING_PLATFORM_REQUESTS });
|
|
230
|
+
// Oldest first: one that needs a request, then three that do not.
|
|
231
|
+
const ids = await dueRows(fresh, ['row', Q, Q, Q]);
|
|
232
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
233
|
+
expect(report).toMatchObject({ fired: 0, failed: 1 });
|
|
234
|
+
expect(report.errors).toHaveLength(1);
|
|
235
|
+
// As on a scope with no cap: the three quiet purges are not held up by the head.
|
|
236
|
+
expect(await purged(fresh, ids.slice(1))).toEqual(ids.slice(1));
|
|
237
|
+
expect(await purged(fresh, [ids[0]])).toEqual([]);
|
|
238
|
+
});
|
|
239
|
+
it('twin: with room in the queue the same head purges too', async () => {
|
|
240
|
+
const fresh = await freshScope();
|
|
241
|
+
const ids = await dueRows(fresh, ['row', Q, Q, Q]);
|
|
242
|
+
const report = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
243
|
+
expect(report).toMatchObject({ fired: 1, failed: 0, errors: [], platformRequests: 1 });
|
|
244
|
+
expect(await purged(fresh, ids)).toEqual(ids);
|
|
245
|
+
});
|
|
246
|
+
// Two purge horizons of one module run back to back in one call, with no drain between them
|
|
247
|
+
// (the sweeper kicks the drain once, after all of a scope's schedules).
|
|
248
|
+
describe('two horizons in one tick', () => {
|
|
249
|
+
/** Rows of one kind, binned and aged past the horizon, oldest first. */
|
|
250
|
+
const dueTwo = async (fresh, kind, rowNames) => {
|
|
251
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
252
|
+
const base = Date.now() - (PURGE_TWO_DAYS + 1) * DAY;
|
|
253
|
+
const entity = kind === 'a' ? 'pa' : 'pb';
|
|
254
|
+
const table = kind === 'a' ? 'purgetwo_a' : 'purgetwo_b';
|
|
255
|
+
const ids = [];
|
|
256
|
+
for (const [n, name] of rowNames.entries()) {
|
|
257
|
+
const id = `${kind}-${String(n).padStart(3, '0')}-${ulid()}`;
|
|
258
|
+
const at = new Date(base + n * 60_000).toISOString();
|
|
259
|
+
await stub.invoke(`purgetwo/add-${kind}`, { id, name });
|
|
260
|
+
await stub.invoke(`purgetwo/trash-${kind}`, { rowId: id });
|
|
261
|
+
await raw(t, fresh, `INSERT INTO _substrat_state_moves (entity_type, entity_id) VALUES (?, ?)`, [entity, id]);
|
|
262
|
+
await raw(t, fresh, `UPDATE ${table} SET _substrat_trashed_at = ? WHERE id = ?`, [at, id]);
|
|
263
|
+
await raw(t, fresh, `DELETE FROM _substrat_state_moves WHERE entity_type = ? AND entity_id = ?`, [entity, id]);
|
|
264
|
+
ids.push(id);
|
|
265
|
+
}
|
|
266
|
+
return ids;
|
|
267
|
+
};
|
|
268
|
+
const goneTwo = async (fresh, kind, ids) => {
|
|
269
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
270
|
+
const out = [];
|
|
271
|
+
for (const id of ids) {
|
|
272
|
+
try {
|
|
273
|
+
await stub.invoke(`purgetwo/add-${kind}`, { id, name: 'again' });
|
|
274
|
+
out.push(id);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// still there
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return out;
|
|
281
|
+
};
|
|
282
|
+
const requestsTwo = async (fresh) => (await host.listPlatformRequestHistory(t, fresh, { kind: PURGE_TWO_KIND, limit: 200 })).filter(isPlatformRequest);
|
|
283
|
+
// #2517: nothing drains the scope between the two horizons, so the second one's head met a
|
|
284
|
+
// queue the tick's own purges filled. That is "not yet", not a failure: it keeps its place
|
|
285
|
+
// and runs on the next tick, not after its whole cadence.
|
|
286
|
+
it('the second horizon meets the queue the first filled: its head is deferred to the next tick, not failed', async () => {
|
|
287
|
+
const fresh = await freshScope();
|
|
288
|
+
const first = await dueTwo(fresh, 'a', names(OVER));
|
|
289
|
+
// Oldest first: a row that needs a request, then two that do not.
|
|
290
|
+
const second = await dueTwo(fresh, 'b', ['row', QUIET_TWO_ROW, QUIET_TWO_ROW]);
|
|
291
|
+
const report = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
292
|
+
// The first horizon filled the queue and stopped there, still due; it did not fail.
|
|
293
|
+
expect(await requestsTwo(fresh)).toHaveLength(MAX_PENDING_PLATFORM_REQUESTS);
|
|
294
|
+
expect(await goneTwo(fresh, 'a', first)).toEqual(first.slice(0, MAX_PENDING_PLATFORM_REQUESTS));
|
|
295
|
+
// The second tried nothing and failed nothing: reported deferred, a skip, never fired.
|
|
296
|
+
// Each request is counted once, and all of them were the purges'.
|
|
297
|
+
// (`fired` counts the module's ordinary fill, which enqueues nothing here, and the first horizon.)
|
|
298
|
+
expect(report).toMatchObject({
|
|
299
|
+
fired: 2,
|
|
300
|
+
skipped: 1,
|
|
301
|
+
failed: 0,
|
|
302
|
+
deferred: 1,
|
|
303
|
+
errors: [],
|
|
304
|
+
platformRequests: MAX_PENDING_PLATFORM_REQUESTS,
|
|
305
|
+
purgeRequests: MAX_PENDING_PLATFORM_REQUESTS,
|
|
306
|
+
});
|
|
307
|
+
expect(report.runs).toEqual([
|
|
308
|
+
{ operation: 'purgetwo/fill', outcome: 'ok' },
|
|
309
|
+
{ operation: 'purgetwo/purge-a', outcome: 'ok' },
|
|
310
|
+
{ operation: 'purgetwo/purge-b', outcome: 'skipped' },
|
|
311
|
+
]);
|
|
312
|
+
expect(await goneTwo(fresh, 'b', second)).toEqual([]);
|
|
313
|
+
// After the drain the very next tick runs both: no cadence wait for either.
|
|
314
|
+
await drainAll(fresh);
|
|
315
|
+
const next = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
316
|
+
expect(next).toMatchObject({ fired: 2, failed: 0, errors: [] });
|
|
317
|
+
expect(next.deferred).toBeUndefined();
|
|
318
|
+
expect(await goneTwo(fresh, 'b', second)).toEqual(second);
|
|
319
|
+
expect(await goneTwo(fresh, 'a', first.slice(MAX_PENDING_PLATFORM_REQUESTS))).toEqual(first.slice(MAX_PENDING_PLATFORM_REQUESTS));
|
|
320
|
+
});
|
|
321
|
+
it('a head refused by a queue other traffic filled, with nothing enqueued earlier in the tick, still fails', async () => {
|
|
322
|
+
const fresh = await freshScope();
|
|
323
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
324
|
+
await stub.invoke('purgereq/enqueue', { count: MAX_PENDING_PLATFORM_REQUESTS });
|
|
325
|
+
// The first horizon purges without a request, so it filled nothing.
|
|
326
|
+
await dueTwo(fresh, 'a', [QUIET_TWO_ROW, QUIET_TWO_ROW]);
|
|
327
|
+
const second = await dueTwo(fresh, 'b', ['row', QUIET_TWO_ROW, QUIET_TWO_ROW]);
|
|
328
|
+
const report = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
329
|
+
expect(report).toMatchObject({ fired: 2, failed: 1 });
|
|
330
|
+
expect(report.errors).toHaveLength(1);
|
|
331
|
+
// As ever: nothing behind the head is starved.
|
|
332
|
+
expect(await goneTwo(fresh, 'b', second.slice(1))).toEqual(second.slice(1));
|
|
333
|
+
expect(await goneTwo(fresh, 'b', [second[0]])).toEqual([]);
|
|
334
|
+
});
|
|
335
|
+
it('twin: with room left by the first horizon, the second one purges its head too', async () => {
|
|
336
|
+
const fresh = await freshScope();
|
|
337
|
+
await dueTwo(fresh, 'a', [QUIET_TWO_ROW, 'row']);
|
|
338
|
+
const second = await dueTwo(fresh, 'b', ['row', QUIET_TWO_ROW, QUIET_TWO_ROW]);
|
|
339
|
+
const report = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
340
|
+
expect(report).toMatchObject({ fired: 3, failed: 0, errors: [] });
|
|
341
|
+
expect(await goneTwo(fresh, 'b', second)).toEqual(second);
|
|
342
|
+
});
|
|
343
|
+
// #2517: a sweep runs a scope's modules back to back with no drain either, and tells each
|
|
344
|
+
// call what the earlier calls' purges enqueued (`purgeRequests`).
|
|
345
|
+
const acrossModules = async (carry) => {
|
|
346
|
+
const fresh = await freshScope();
|
|
347
|
+
await dueRows(fresh, names(OVER));
|
|
348
|
+
const earlier = await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
349
|
+
expect(earlier).toMatchObject({ failed: 0, purgeRequests: MAX_PENDING_PLATFORM_REQUESTS });
|
|
350
|
+
const a = await dueTwo(fresh, 'a', ['row', QUIET_TWO_ROW]);
|
|
351
|
+
const b = await dueTwo(fresh, 'b', ['row', QUIET_TWO_ROW]);
|
|
352
|
+
const report = await host.runDueSchedules(PURGE_TWO, t, fresh, carry ? { earlierPurgeRequests: earlier.purgeRequests } : undefined);
|
|
353
|
+
return { fresh, a, b, report };
|
|
354
|
+
};
|
|
355
|
+
it('a module after one whose purges filled the queue defers its heads when the sweep says so', async () => {
|
|
356
|
+
const { fresh, a, b, report } = await acrossModules(true);
|
|
357
|
+
// The ordinary fill fires (and enqueues nothing); both horizons are deferred.
|
|
358
|
+
expect(report).toMatchObject({ fired: 1, skipped: 2, failed: 0, deferred: 2, errors: [] });
|
|
359
|
+
expect(report.runs?.map((r) => r.outcome)).toEqual(['ok', 'skipped', 'skipped']);
|
|
360
|
+
expect(await goneTwo(fresh, 'a', a)).toEqual([]);
|
|
361
|
+
expect(await goneTwo(fresh, 'b', b)).toEqual([]);
|
|
362
|
+
// Next tick, after the drain: the purge-request module finishes its lap, and this one runs.
|
|
363
|
+
await drainAll(fresh);
|
|
364
|
+
await host.runDueSchedules(PURGE_REQUEST, t, fresh);
|
|
365
|
+
await drainAll(fresh);
|
|
366
|
+
const next = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
367
|
+
expect(next).toMatchObject({ fired: 2, failed: 0, errors: [] });
|
|
368
|
+
expect(await goneTwo(fresh, 'a', a)).toEqual(a);
|
|
369
|
+
expect(await goneTwo(fresh, 'b', b)).toEqual(b);
|
|
370
|
+
});
|
|
371
|
+
it('twin (skew): told nothing — an older sweep — the same heads fail as before and nothing behind them waits', async () => {
|
|
372
|
+
const { fresh, a, b, report } = await acrossModules(false);
|
|
373
|
+
expect(report).toMatchObject({ fired: 1, failed: 2 });
|
|
374
|
+
expect(report.deferred).toBeUndefined();
|
|
375
|
+
expect(await goneTwo(fresh, 'a', a)).toEqual(a.slice(1));
|
|
376
|
+
expect(await goneTwo(fresh, 'b', b)).toEqual(b.slice(1));
|
|
377
|
+
});
|
|
378
|
+
// #2517's bound: only PURGE runs defer a head. An ordinary schedule may enqueue on every
|
|
379
|
+
// tick for ever, so if its requests counted, a head behind it would wait for ever, and so
|
|
380
|
+
// would everything behind the head (#2096).
|
|
381
|
+
it('an ordinary schedule that fills the queue never defers a head: it fails as before, and the purges behind it that need no request commit', async () => {
|
|
382
|
+
const fresh = await freshScope();
|
|
383
|
+
// A live (unbinned) row by this name makes the module's ordinary fill fill the queue.
|
|
384
|
+
const stub = await host.getScope(alice, t, fresh);
|
|
385
|
+
await stub.invoke('purgetwo/add-a', { id: `fill-${ulid()}`, name: FILL_TWO_ROW });
|
|
386
|
+
const b = await dueTwo(fresh, 'b', ['row', QUIET_TWO_ROW, QUIET_TWO_ROW]);
|
|
387
|
+
const report = await host.runDueSchedules(PURGE_TWO, t, fresh);
|
|
388
|
+
// The fill and the empty first horizon fire; the second horizon's head fails.
|
|
389
|
+
expect(report).toMatchObject({ fired: 2, failed: 1, platformRequests: MAX_PENDING_PLATFORM_REQUESTS });
|
|
390
|
+
expect(report.deferred).toBeUndefined();
|
|
391
|
+
expect(report.purgeRequests).toBeUndefined();
|
|
392
|
+
expect(report.errors).toEqual([
|
|
393
|
+
{ operation: expect.stringContaining('purgetwo/purge-b'), error: expect.stringMatching(/too many pending platform requests/) },
|
|
394
|
+
]);
|
|
395
|
+
expect(await goneTwo(fresh, 'b', b)).toEqual(b.slice(1));
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
});
|
|
53
400
|
});
|
|
54
401
|
}
|
|
55
402
|
//# sourceMappingURL=schedule-platform-requests-suite.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-platform-requests-suite.js","sourceRoot":"","sources":["../src/schedule-platform-requests-suite.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schedule-platform-requests-suite.js","sourceRoot":"","sources":["../src/schedule-platform-requests-suite.ts"],"names":[],"mappings":"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"}
|