@substrat-run/contract-tests 0.118.0 → 0.119.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/capability-attachment-suite.d.ts +3 -0
- package/dist/capability-attachment-suite.d.ts.map +1 -0
- package/dist/capability-attachment-suite.js +284 -0
- package/dist/capability-attachment-suite.js.map +1 -0
- package/dist/capability-expiry-suite.d.ts.map +1 -1
- package/dist/capability-expiry-suite.js +40 -1
- package/dist/capability-expiry-suite.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/modules.d.ts +400 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +94 -1
- package/dist/modules.js.map +1 -1
- package/dist/peer-suite.d.ts +8 -0
- package/dist/peer-suite.d.ts.map +1 -0
- package/dist/peer-suite.js +357 -0
- package/dist/peer-suite.js.map +1 -0
- package/dist/system-switch-suite.d.ts.map +1 -1
- package/dist/system-switch-suite.js +57 -1
- package/dist/system-switch-suite.js.map +1 -1
- package/dist/vertical-events-suite.d.ts +282 -0
- package/dist/vertical-events-suite.d.ts.map +1 -0
- package/dist/vertical-events-suite.js +584 -0
- package/dist/vertical-events-suite.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
|
2
|
+
import { dataSubjectId, eventId, moduleManifest, permissionKey, platformActorId, principalId, scopeId, tenantId, z, } from '@substrat-run/contracts';
|
|
3
|
+
import { assertAllowed, runPlatformSweep, ulid, } from '@substrat-run/kernel';
|
|
4
|
+
// -- the two fixture verticals ------------------------------------------------
|
|
5
|
+
//
|
|
6
|
+
// Named as the verticals of one tenant would be: a CRM that owns customers, and a board-room
|
|
7
|
+
// app that keeps an association per customer. They live in two DEPLOYMENTS (two hosts over
|
|
8
|
+
// one directory), so every decision the suite asserts is made by the code of the side that
|
|
9
|
+
// owns it: what leaves by the producer's own exports, and what runs by the consumer's own
|
|
10
|
+
// imports.
|
|
11
|
+
//
|
|
12
|
+
// A ping-pong is built in on purpose: board exports `board.association-linked`, crm imports
|
|
13
|
+
// it and answers with `crm.customer-touched`, which crm exports and board imports. Only
|
|
14
|
+
// `crm/touch` starts it. It is the loop the hop cap exists to break.
|
|
15
|
+
export const CRM_VERTICAL = 'acme/crm';
|
|
16
|
+
export const BOARD_VERTICAL = 'acme/board';
|
|
17
|
+
const key = (k) => permissionKey.parse(k);
|
|
18
|
+
export const crmExportModManifest = moduleManifest.parse({
|
|
19
|
+
id: '@test/crm-export',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
kernelContract: '^0.0.1',
|
|
22
|
+
permissions: [
|
|
23
|
+
{ key: 'customer:read', description: 'read customers — what a receiving vertical must hold' },
|
|
24
|
+
{ key: 'customer:write', description: 'create customers' },
|
|
25
|
+
],
|
|
26
|
+
events: {
|
|
27
|
+
emits: [
|
|
28
|
+
{ type: 'crm.customer-created', schemaVersion: 1 },
|
|
29
|
+
{ type: 'crm.customer-noted', schemaVersion: 1 },
|
|
30
|
+
{ type: 'crm.customer-touched', schemaVersion: 1 },
|
|
31
|
+
],
|
|
32
|
+
consumes: [{ from: BOARD_VERTICAL, type: 'board.association-linked', schemaVersion: 1 }],
|
|
33
|
+
exports: [
|
|
34
|
+
{ type: 'crm.customer-created', schemaVersion: 1, readPermission: 'customer:read' },
|
|
35
|
+
{ type: 'crm.customer-touched', schemaVersion: 1, readPermission: 'customer:read' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
// #1706's grant, used for both directions of the edge. board holds `customer:read` here,
|
|
39
|
+
// which releases crm's exports to it. It is admitted as a peer when it delivers into crm (the
|
|
40
|
+
// loop's return leg), where its handler checks `customer:write`. It may invoke nothing.
|
|
41
|
+
peers: [{ vertical: BOARD_VERTICAL, operations: [], permissions: ['customer:read', 'customer:write'] }],
|
|
42
|
+
migrations: { journalDir: './migrations', compatibleFrom: '1.0.0' },
|
|
43
|
+
attachmentTargets: [],
|
|
44
|
+
entitlementKey: 'crm-export',
|
|
45
|
+
});
|
|
46
|
+
const createInput = z.object({
|
|
47
|
+
name: z.string().min(1),
|
|
48
|
+
pii: z.enum(['none', 'direct']).optional(),
|
|
49
|
+
schemaVersion: z.number().int().positive().optional(),
|
|
50
|
+
});
|
|
51
|
+
const crmCreate = async (ctx, raw) => {
|
|
52
|
+
assertAllowed(await ctx.check(key('customer:write')));
|
|
53
|
+
const input = createInput.parse(raw);
|
|
54
|
+
const id = ulid();
|
|
55
|
+
ctx.sql.exec('INSERT INTO crm_customers (id, name) VALUES (?, ?)', [id, input.name]);
|
|
56
|
+
const entity = { entityType: 'customer', entityId: id };
|
|
57
|
+
const payload = { id, name: input.name };
|
|
58
|
+
const schemaVersion = input.schemaVersion ?? 1;
|
|
59
|
+
if (input.pii === 'direct') {
|
|
60
|
+
ctx.emit({
|
|
61
|
+
type: 'crm.customer-created',
|
|
62
|
+
schemaVersion,
|
|
63
|
+
entity,
|
|
64
|
+
piiClass: 'direct',
|
|
65
|
+
subjectId: dataSubjectId.parse(id),
|
|
66
|
+
payload,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
ctx.emit({ type: 'crm.customer-created', schemaVersion, entity, piiClass: 'none', payload });
|
|
71
|
+
}
|
|
72
|
+
return { id };
|
|
73
|
+
};
|
|
74
|
+
/** Emits a type crm does NOT export. Asked for by board all the same. */
|
|
75
|
+
const crmNote = async (ctx, input) => {
|
|
76
|
+
assertAllowed(await ctx.check(key('customer:write')));
|
|
77
|
+
ctx.emit({
|
|
78
|
+
type: 'crm.customer-noted',
|
|
79
|
+
schemaVersion: 1,
|
|
80
|
+
entity: { entityType: 'customer', entityId: input.id },
|
|
81
|
+
piiClass: 'none',
|
|
82
|
+
payload: { id: input.id },
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
/** Starts the ping-pong. */
|
|
86
|
+
const crmTouch = async (ctx, input) => {
|
|
87
|
+
assertAllowed(await ctx.check(key('customer:write')));
|
|
88
|
+
ctx.emit({
|
|
89
|
+
type: 'crm.customer-touched',
|
|
90
|
+
schemaVersion: 1,
|
|
91
|
+
entity: { entityType: 'customer', entityId: input.id },
|
|
92
|
+
piiClass: 'none',
|
|
93
|
+
payload: { id: input.id },
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
export const crmExportMod = {
|
|
97
|
+
manifest: crmExportModManifest,
|
|
98
|
+
migrations: [{ version: '0001-init', sql: 'CREATE TABLE crm_customers (id TEXT PRIMARY KEY, name TEXT NOT NULL)' }],
|
|
99
|
+
operations: {
|
|
100
|
+
'crm/create': crmCreate,
|
|
101
|
+
'crm/note': crmNote,
|
|
102
|
+
'crm/touch': crmTouch,
|
|
103
|
+
},
|
|
104
|
+
imports: {
|
|
105
|
+
[BOARD_VERTICAL]: {
|
|
106
|
+
// The loop's other half: every link board announces is answered with a touch.
|
|
107
|
+
'board.association-linked': async (ctx, event) => {
|
|
108
|
+
assertAllowed(await ctx.check(key('customer:write')));
|
|
109
|
+
const { crmId } = z.object({ crmId: z.string() }).parse(event.payload);
|
|
110
|
+
ctx.emit({
|
|
111
|
+
type: 'crm.customer-touched',
|
|
112
|
+
schemaVersion: 1,
|
|
113
|
+
entity: { entityType: 'customer', entityId: crmId },
|
|
114
|
+
piiClass: 'none',
|
|
115
|
+
payload: { id: crmId },
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
export const boardImportModManifest = moduleManifest.parse({
|
|
122
|
+
id: '@test/board-import',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
kernelContract: '^0.0.1',
|
|
125
|
+
permissions: [
|
|
126
|
+
{ key: 'association:read', description: 'read associations' },
|
|
127
|
+
{ key: 'association:sync', description: 'keep associations in step with the CRM' },
|
|
128
|
+
],
|
|
129
|
+
events: {
|
|
130
|
+
emits: [
|
|
131
|
+
{ type: 'board.association-created', schemaVersion: 1 },
|
|
132
|
+
{ type: 'board.association-linked', schemaVersion: 1 },
|
|
133
|
+
],
|
|
134
|
+
consumes: [
|
|
135
|
+
{ from: CRM_VERTICAL, type: 'crm.customer-created', schemaVersion: 1 },
|
|
136
|
+
// crm emits this and does not export it. Declaring it must not be enough to receive it.
|
|
137
|
+
{ from: CRM_VERTICAL, type: 'crm.customer-noted', schemaVersion: 1 },
|
|
138
|
+
{ from: CRM_VERTICAL, type: 'crm.customer-touched', schemaVersion: 1 },
|
|
139
|
+
],
|
|
140
|
+
exports: [{ type: 'board.association-linked', schemaVersion: 1, readPermission: 'association:read' }],
|
|
141
|
+
},
|
|
142
|
+
// crm is admitted to deliver here, and its handlers' checks run against `association:sync`.
|
|
143
|
+
// `association:read` releases board's own export back to crm.
|
|
144
|
+
peers: [{ vertical: CRM_VERTICAL, operations: [], permissions: ['association:sync', 'association:read'] }],
|
|
145
|
+
migrations: { journalDir: './migrations', compatibleFrom: '1.0.0' },
|
|
146
|
+
attachmentTargets: [],
|
|
147
|
+
entitlementKey: 'board-import',
|
|
148
|
+
});
|
|
149
|
+
const customerCreated = z.object({ id: z.string(), name: z.string() });
|
|
150
|
+
const boardRead = async (ctx) => {
|
|
151
|
+
assertAllowed(await ctx.check(key('association:read')));
|
|
152
|
+
return {
|
|
153
|
+
associations: ctx.sql.query('SELECT crm_id, name FROM board_associations ORDER BY rowid'),
|
|
154
|
+
noted: (ctx.sql.query('SELECT COUNT(*) AS n FROM board_noted')[0]?.n ?? 0),
|
|
155
|
+
// Module code may READ the spine (rule 3); these reads are what an operator's view is.
|
|
156
|
+
imports: ctx.sql.query('SELECT event_id, source_vertical, source_scope_id, type, hops, withheld FROM _substrat_imports ORDER BY event_id'),
|
|
157
|
+
deliveries: ctx.sql.query('SELECT event_id, consumer_module, error FROM _substrat_deliveries ORDER BY event_id, consumer_module'),
|
|
158
|
+
outbox: ctx.sql.query('SELECT id, type, caused_by, actor FROM _substrat_outbox ORDER BY id'),
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
export const boardImportMod = {
|
|
162
|
+
manifest: boardImportModManifest,
|
|
163
|
+
migrations: [
|
|
164
|
+
{
|
|
165
|
+
version: '0001-init',
|
|
166
|
+
sql: `
|
|
167
|
+
CREATE TABLE board_associations (crm_id TEXT PRIMARY KEY, name TEXT NOT NULL);
|
|
168
|
+
CREATE TABLE board_noted (event_id TEXT PRIMARY KEY);
|
|
169
|
+
`,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
operations: { 'board/read': boardRead },
|
|
173
|
+
imports: {
|
|
174
|
+
[CRM_VERTICAL]: {
|
|
175
|
+
'crm.customer-created': async (ctx, event) => {
|
|
176
|
+
assertAllowed(await ctx.check(key('association:sync')));
|
|
177
|
+
const c = customerCreated.parse(event.payload);
|
|
178
|
+
if (c.name === 'poison')
|
|
179
|
+
throw new Error('board refuses the poison customer');
|
|
180
|
+
ctx.sql.exec(`INSERT INTO board_associations (crm_id, name) VALUES (?, ?)
|
|
181
|
+
ON CONFLICT (crm_id) DO UPDATE SET name = excluded.name`, [c.id, c.name]);
|
|
182
|
+
ctx.emit({
|
|
183
|
+
type: 'board.association-created',
|
|
184
|
+
schemaVersion: 1,
|
|
185
|
+
entity: { entityType: 'association', entityId: c.id },
|
|
186
|
+
piiClass: 'none',
|
|
187
|
+
payload: { crmId: c.id },
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
'crm.customer-noted': async (ctx, event) => {
|
|
191
|
+
// Never runs: crm does not export the type. Recorded if it ever does.
|
|
192
|
+
ctx.sql.exec('INSERT INTO board_noted (event_id) VALUES (?)', [event.id]);
|
|
193
|
+
},
|
|
194
|
+
'crm.customer-touched': async (ctx, event) => {
|
|
195
|
+
assertAllowed(await ctx.check(key('association:sync')));
|
|
196
|
+
const { id } = z.object({ id: z.string() }).parse(event.payload);
|
|
197
|
+
ctx.emit({
|
|
198
|
+
type: 'board.association-linked',
|
|
199
|
+
schemaVersion: 1,
|
|
200
|
+
entity: { entityType: 'association', entityId: id },
|
|
201
|
+
piiClass: 'none',
|
|
202
|
+
payload: { crmId: id },
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
const noFetch = async () => new Response('unused', { status: 200 });
|
|
209
|
+
/**
|
|
210
|
+
* Cross-vertical event delivery (#1705), against a real pair of deployments. Every claim the
|
|
211
|
+
* design rests on is here with its positive twin:
|
|
212
|
+
*
|
|
213
|
+
* - same-tenant only: a consumer receives its own tenant's producer, never another's;
|
|
214
|
+
* - not exported, not delivered, whatever the consumer declares;
|
|
215
|
+
* - only `piiClass: 'none'` crosses, and a classified instance is named but never carried;
|
|
216
|
+
* - at-least-once across the edge, one effect per (event, module): a redelivered batch runs
|
|
217
|
+
* nothing twice, and a handler that throws does not stop the events behind it;
|
|
218
|
+
* - the watermark belongs to the consumer and moves only forward, under a compare-and-set;
|
|
219
|
+
* - backfill: a consumer installed after the producer receives the history;
|
|
220
|
+
* - `caused_by` crosses the edge and resolves to its source;
|
|
221
|
+
* - a P ↔ C loop is cut at the hop cap;
|
|
222
|
+
* - a fork is neither read nor fed, and two primary installs are refused, not guessed.
|
|
223
|
+
*/
|
|
224
|
+
export function verticalEventsContractSuite(adapterName, makeFixture) {
|
|
225
|
+
// A sweep pass is real work on workerd (every active scope in the directory is looked at),
|
|
226
|
+
// and a slow CI runner is several times slower than a laptop, so the suite gets room.
|
|
227
|
+
describe(`cross-vertical events (#1705): ${adapterName}`, { timeout: 30_000 }, () => {
|
|
228
|
+
let fx;
|
|
229
|
+
const staff = platformActorId.parse(ulid());
|
|
230
|
+
const writer = principalId.parse(ulid());
|
|
231
|
+
const reader = principalId.parse(ulid());
|
|
232
|
+
beforeAll(async () => {
|
|
233
|
+
fx = await makeFixture();
|
|
234
|
+
});
|
|
235
|
+
afterAll(async () => {
|
|
236
|
+
await fx.cleanup();
|
|
237
|
+
});
|
|
238
|
+
const hostFor = (vertical) => (vertical === CRM_VERTICAL ? fx.producer : fx.consumer);
|
|
239
|
+
const hostOf = async (t, s) => {
|
|
240
|
+
const rec = await fx.consumer.admin.getScopeRecord(staff, t, s);
|
|
241
|
+
return hostFor(rec?.vertical ?? '');
|
|
242
|
+
};
|
|
243
|
+
// The reach a deployment-per-vertical platform has: each scope reached through the
|
|
244
|
+
// deployment serving it, resolved from the directory. The control plane does the same
|
|
245
|
+
// over `/internal`.
|
|
246
|
+
//
|
|
247
|
+
// Scoped to the tenants THIS test created. The directory is shared, so without this a
|
|
248
|
+
// test's passes would also move every earlier test's edges. Worse, a test that timed out
|
|
249
|
+
// keeps sweeping in the background (vitest does not cancel it), and would deliver the next
|
|
250
|
+
// test's events before that test's own pass could.
|
|
251
|
+
// The scoping is the phase's own narrowing hook (`candidates`), the one the control plane
|
|
252
|
+
// fills from the registry, so the suite also proves that a scope it drops is never called.
|
|
253
|
+
const current = new Set();
|
|
254
|
+
beforeEach(() => current.clear());
|
|
255
|
+
const reach = {
|
|
256
|
+
candidates: (scopes) => scopes.filter((s) => current.has(s.tenantId)),
|
|
257
|
+
importState: async (t, s) => (await hostOf(t, s)).admin.importState(staff, t, s),
|
|
258
|
+
readExports: async (t, s, input) => (await hostOf(t, s)).admin.readExportedEvents(staff, t, s, input),
|
|
259
|
+
deliver: async (t, s, batch) => (await hostOf(t, s)).deliverToPeer(t, s, batch),
|
|
260
|
+
};
|
|
261
|
+
const newTenant = async () => {
|
|
262
|
+
const t = tenantId.parse(ulid());
|
|
263
|
+
await fx.producer.admin.createTenant(staff, { id: t, slug: `ve-${t.toLowerCase()}`, name: 'Vertical events' });
|
|
264
|
+
await fx.producer.admin.grantEntitlement(staff, t, 'crm-export');
|
|
265
|
+
await fx.producer.admin.grantEntitlement(staff, t, 'board-import');
|
|
266
|
+
current.add(t);
|
|
267
|
+
return t;
|
|
268
|
+
};
|
|
269
|
+
const install = async (t, vertical) => {
|
|
270
|
+
const s = scopeId.parse(ulid());
|
|
271
|
+
const host = hostFor(vertical);
|
|
272
|
+
await host.provisionScope(staff, { tenantId: t, scopeId: s, vertical });
|
|
273
|
+
await host.admin.activateScope(staff, t, s);
|
|
274
|
+
const perms = vertical === CRM_VERTICAL ? ['customer:write'] : ['association:read'];
|
|
275
|
+
for (const p of perms) {
|
|
276
|
+
await host.admin.grant(staff, {
|
|
277
|
+
principalId: vertical === CRM_VERTICAL ? writer : reader,
|
|
278
|
+
permission: key(p),
|
|
279
|
+
node: { tenantId: t, scopeId: s },
|
|
280
|
+
grantedBy: writer,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
return s;
|
|
284
|
+
};
|
|
285
|
+
const crm = async (t, s, op, input) => (await fx.producer.getScope(writer, t, s)).invoke(op, input);
|
|
286
|
+
const create = async (t, s, name, extra = {}) => (await crm(t, s, 'crm/create', { name, ...extra })).id;
|
|
287
|
+
const board = async (t, s) => (await (await fx.consumer.getScope(reader, t, s)).invoke('board/read', undefined));
|
|
288
|
+
const sweep = async () => {
|
|
289
|
+
const runs = [];
|
|
290
|
+
const report = await runPlatformSweep(fx.consumer, {
|
|
291
|
+
actor: staff,
|
|
292
|
+
fetch: noFetch,
|
|
293
|
+
sweepers: {},
|
|
294
|
+
// Only this phase: the others would open scopes through whichever host the sweep
|
|
295
|
+
// was handed, which in a two-deployment world is the wrong one for half of them.
|
|
296
|
+
drainRetries: false,
|
|
297
|
+
gcSnapshots: false,
|
|
298
|
+
reconcileMigrations: false,
|
|
299
|
+
runSchedules: false,
|
|
300
|
+
recordSweepRun: (e) => runs.push(e),
|
|
301
|
+
crossVertical: { reach },
|
|
302
|
+
});
|
|
303
|
+
return { report, runs };
|
|
304
|
+
};
|
|
305
|
+
const edgesOf = (report, t) => (report.crossVertical?.edges ?? []).filter((e) => e.tenantId === t);
|
|
306
|
+
/** The edge INTO one consumer scope. crm imports from board too, so a tenant has two. */
|
|
307
|
+
const into = (report, consumer) => (report.crossVertical?.edges ?? []).find((e) => e.consumer.scopeId === consumer);
|
|
308
|
+
it('delivers an exported event to the same tenant\'s consumer, in order, and moves the consumer\'s watermark', async () => {
|
|
309
|
+
const t = await newTenant();
|
|
310
|
+
const p = await install(t, CRM_VERTICAL);
|
|
311
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
312
|
+
const a = await create(t, p, 'Alpha');
|
|
313
|
+
const b = await create(t, p, 'Beta');
|
|
314
|
+
const { report } = await sweep();
|
|
315
|
+
expect(into(report, c)).toMatchObject({
|
|
316
|
+
state: 'delivered',
|
|
317
|
+
delivered: 2,
|
|
318
|
+
producer: { vertical: CRM_VERTICAL, scopeId: p },
|
|
319
|
+
});
|
|
320
|
+
expect((await board(t, c)).associations).toEqual([
|
|
321
|
+
{ crm_id: a, name: 'Alpha' },
|
|
322
|
+
{ crm_id: b, name: 'Beta' },
|
|
323
|
+
]);
|
|
324
|
+
const state = await fx.consumer.admin.importState(staff, t, c);
|
|
325
|
+
expect(state.cursors).toEqual([expect.objectContaining({ source: p, vertical: CRM_VERTICAL })]);
|
|
326
|
+
// Caught up: the next pass is idle and moves nothing.
|
|
327
|
+
const again = edgesOf((await sweep()).report, t);
|
|
328
|
+
expect(again.length).toBeGreaterThan(0);
|
|
329
|
+
expect(again.every((e) => e.state === 'idle' && e.delivered === 0)).toBe(true);
|
|
330
|
+
expect((await board(t, c)).associations).toHaveLength(2);
|
|
331
|
+
});
|
|
332
|
+
it('never crosses a tenant: each consumer receives its own tenant\'s producer, and none from another', async () => {
|
|
333
|
+
const t = await newTenant();
|
|
334
|
+
const u = await newTenant();
|
|
335
|
+
const v = await newTenant();
|
|
336
|
+
const pt = await install(t, CRM_VERTICAL);
|
|
337
|
+
const ct = await install(t, BOARD_VERTICAL);
|
|
338
|
+
const pu = await install(u, CRM_VERTICAL);
|
|
339
|
+
const cu = await install(u, BOARD_VERTICAL);
|
|
340
|
+
const cv = await install(v, BOARD_VERTICAL); // a board with NO crm in its tenant
|
|
341
|
+
await create(t, pt, 'Only-T');
|
|
342
|
+
await create(u, pu, 'Only-U');
|
|
343
|
+
const { report, runs } = await sweep();
|
|
344
|
+
expect((await board(t, ct)).associations.map((r) => r.name)).toEqual(['Only-T']);
|
|
345
|
+
expect((await board(u, cu)).associations.map((r) => r.name)).toEqual(['Only-U']);
|
|
346
|
+
// The tenant with no producer receives nothing, and the edge says why.
|
|
347
|
+
expect((await board(v, cv)).associations).toEqual([]);
|
|
348
|
+
expect(into(report, cv)).toMatchObject({
|
|
349
|
+
state: 'unresolved',
|
|
350
|
+
reason: `'${CRM_VERTICAL}' is not installed in this tenant`,
|
|
351
|
+
});
|
|
352
|
+
// ...durably, where a person reads it.
|
|
353
|
+
expect(runs).toContainEqual(expect.objectContaining({
|
|
354
|
+
kind: 'vertical-events',
|
|
355
|
+
unit: `${cv}:${CRM_VERTICAL}`,
|
|
356
|
+
outcome: 'skipped',
|
|
357
|
+
error: `'${CRM_VERTICAL}' is not installed in this tenant`,
|
|
358
|
+
}));
|
|
359
|
+
});
|
|
360
|
+
it('an event its producer does not export is never delivered, however it is asked for', async () => {
|
|
361
|
+
const t = await newTenant();
|
|
362
|
+
const p = await install(t, CRM_VERTICAL);
|
|
363
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
364
|
+
const id = await create(t, p, 'Exported');
|
|
365
|
+
await crm(t, p, 'crm/note', { id });
|
|
366
|
+
const { report } = await sweep();
|
|
367
|
+
const view = await board(t, c);
|
|
368
|
+
expect(view.associations.map((r) => r.name)).toEqual(['Exported']); // positive twin
|
|
369
|
+
expect(view.noted).toBe(0);
|
|
370
|
+
expect(view.imports.map((i) => i.type)).toEqual(['crm.customer-created']);
|
|
371
|
+
expect(into(report, c)?.unexported).toEqual([{ type: 'crm.customer-noted', schemaVersion: 1 }]);
|
|
372
|
+
// Asked for directly, with nothing else: the producer's own code refuses it.
|
|
373
|
+
const direct = await fx.producer.admin.readExportedEvents(staff, t, p, {
|
|
374
|
+
consumer: BOARD_VERTICAL,
|
|
375
|
+
after: null,
|
|
376
|
+
wants: [{ type: 'crm.customer-noted', schemaVersion: 1 }],
|
|
377
|
+
limit: 100,
|
|
378
|
+
});
|
|
379
|
+
expect(direct).toMatchObject({ events: [], withheld: [], unexported: [{ type: 'crm.customer-noted', schemaVersion: 1 }] });
|
|
380
|
+
});
|
|
381
|
+
it('only piiClass none crosses: a classified instance is withheld, named at the consumer, never carried', async () => {
|
|
382
|
+
const t = await newTenant();
|
|
383
|
+
const p = await install(t, CRM_VERTICAL);
|
|
384
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
385
|
+
const person = await create(t, p, 'A Person', { pii: 'direct' });
|
|
386
|
+
const org = await create(t, p, 'An Association'); // positive twin
|
|
387
|
+
const { report } = await sweep();
|
|
388
|
+
const view = await board(t, c);
|
|
389
|
+
expect(view.associations).toEqual([{ crm_id: org, name: 'An Association' }]);
|
|
390
|
+
expect(into(report, c)).toMatchObject({ state: 'delivered', delivered: 1, withheld: 1 });
|
|
391
|
+
const withheld = view.imports.find((i) => i.withheld !== null);
|
|
392
|
+
expect(withheld).toMatchObject({ type: 'crm.customer-created', withheld: 'pii' });
|
|
393
|
+
// The dead letter says what happened and carries nothing of the person.
|
|
394
|
+
const dead = view.deliveries.find((d) => d.event_id === withheld.event_id);
|
|
395
|
+
expect(dead?.error).toMatch(/withheld by 'acme\/crm'.*personal data/);
|
|
396
|
+
expect(dead?.error).not.toContain('A Person');
|
|
397
|
+
expect(JSON.stringify(view)).not.toContain('A Person');
|
|
398
|
+
expect(person).toBeTruthy();
|
|
399
|
+
// The operator's dead-letter read shows the withheld import beside local ones.
|
|
400
|
+
const letters = await fx.consumer.admin.deadLetters(staff, t, c, {});
|
|
401
|
+
expect(letters.entries).toContainEqual(expect.objectContaining({ eventId: withheld.event_id, eventType: 'crm.customer-created' }));
|
|
402
|
+
});
|
|
403
|
+
it('a version other than the one declared is withheld, never handed to a handler (K-39)', async () => {
|
|
404
|
+
const t = await newTenant();
|
|
405
|
+
const p = await install(t, CRM_VERTICAL);
|
|
406
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
407
|
+
await create(t, p, 'Version two', { schemaVersion: 2 });
|
|
408
|
+
await create(t, p, 'Version one'); // positive twin
|
|
409
|
+
await sweep();
|
|
410
|
+
const view = await board(t, c);
|
|
411
|
+
expect(view.associations.map((r) => r.name)).toEqual(['Version one']);
|
|
412
|
+
expect(view.imports.filter((i) => i.withheld === 'version')).toHaveLength(1);
|
|
413
|
+
});
|
|
414
|
+
it('a handler that throws is dead-lettered, and the events behind it still arrive', async () => {
|
|
415
|
+
const t = await newTenant();
|
|
416
|
+
const p = await install(t, CRM_VERTICAL);
|
|
417
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
418
|
+
const poison = await create(t, p, 'poison');
|
|
419
|
+
await create(t, p, 'After the poison');
|
|
420
|
+
const { report } = await sweep();
|
|
421
|
+
expect(into(report, c)).toMatchObject({ state: 'delivered', delivered: 1, deadLettered: 1 });
|
|
422
|
+
const view = await board(t, c);
|
|
423
|
+
expect(view.associations.map((r) => r.name)).toEqual(['After the poison']);
|
|
424
|
+
const refused = view.imports.find((i) => i.type === 'crm.customer-created' && i.withheld === null && view.deliveries.some((d) => d.event_id === i.event_id && d.error?.includes('poison')));
|
|
425
|
+
expect(refused).toBeTruthy();
|
|
426
|
+
expect(poison).toBeTruthy();
|
|
427
|
+
});
|
|
428
|
+
it('at-least-once across the edge: a batch delivered twice runs each handler once', async () => {
|
|
429
|
+
const t = await newTenant();
|
|
430
|
+
const p = await install(t, CRM_VERTICAL);
|
|
431
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
432
|
+
await create(t, p, 'Once');
|
|
433
|
+
const read = await fx.producer.admin.readExportedEvents(staff, t, p, {
|
|
434
|
+
consumer: BOARD_VERTICAL,
|
|
435
|
+
after: null,
|
|
436
|
+
wants: [{ type: 'crm.customer-created', schemaVersion: 1 }],
|
|
437
|
+
limit: 100,
|
|
438
|
+
});
|
|
439
|
+
const batch = {
|
|
440
|
+
source: { vertical: CRM_VERTICAL, scopeId: p },
|
|
441
|
+
after: null,
|
|
442
|
+
next: read.next,
|
|
443
|
+
events: read.events,
|
|
444
|
+
withheld: read.withheld,
|
|
445
|
+
};
|
|
446
|
+
const first = await fx.consumer.deliverToPeer(t, c, batch);
|
|
447
|
+
expect(first).toMatchObject({ delivered: 1, duplicates: 0, stale: false, cursor: read.next });
|
|
448
|
+
// The same batch again, from where the watermark now stands: every event is already
|
|
449
|
+
// journaled, so nothing runs a second time.
|
|
450
|
+
const second = await fx.consumer.deliverToPeer(t, c, { ...batch, after: read.next });
|
|
451
|
+
expect(second).toMatchObject({ delivered: 0, duplicates: 1, stale: false });
|
|
452
|
+
const view = await board(t, c);
|
|
453
|
+
expect(view.associations).toHaveLength(1);
|
|
454
|
+
expect(view.outbox.filter((o) => o.type === 'board.association-created')).toHaveLength(1);
|
|
455
|
+
// A pass that read from a stale watermark is refused whole, and moves nothing backwards.
|
|
456
|
+
const stale = await fx.consumer.deliverToPeer(t, c, batch);
|
|
457
|
+
expect(stale).toMatchObject({ stale: true, delivered: 0, cursor: read.next });
|
|
458
|
+
});
|
|
459
|
+
it('backfill: a consumer installed after the producer receives the exported history', async () => {
|
|
460
|
+
const t = await newTenant();
|
|
461
|
+
const p = await install(t, CRM_VERTICAL);
|
|
462
|
+
const early = [await create(t, p, 'Early 1'), await create(t, p, 'Early 2'), await create(t, p, 'Early 3')];
|
|
463
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
464
|
+
await sweep();
|
|
465
|
+
expect((await board(t, c)).associations.map((r) => r.crm_id)).toEqual(early);
|
|
466
|
+
});
|
|
467
|
+
it('causedBy crosses the edge: what the handler emits names the producer\'s event, which resolves to its source', async () => {
|
|
468
|
+
const t = await newTenant();
|
|
469
|
+
const p = await install(t, CRM_VERTICAL);
|
|
470
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
471
|
+
await create(t, p, 'Caused');
|
|
472
|
+
await sweep();
|
|
473
|
+
const view = await board(t, c);
|
|
474
|
+
const imported = view.imports.find((i) => i.withheld === null);
|
|
475
|
+
const reaction = view.outbox.find((o) => o.type === 'board.association-created');
|
|
476
|
+
expect(reaction.caused_by).toBe(imported.event_id);
|
|
477
|
+
// The producer acted here, through the door, as itself (#1706's actor) — not as a person,
|
|
478
|
+
// and not as this module's own system principal.
|
|
479
|
+
expect(JSON.parse(reaction.actor)).toEqual({ vertical: CRM_VERTICAL, scope: p });
|
|
480
|
+
expect(imported).toMatchObject({ source_vertical: CRM_VERTICAL, source_scope_id: p, hops: 1 });
|
|
481
|
+
// The walk says where the trail went, rather than calling the record broken.
|
|
482
|
+
const chain = await fx.consumer.admin.eventCause(staff, t, c, { eventId: eventId.parse(reaction.id) });
|
|
483
|
+
expect(chain).toMatchObject({
|
|
484
|
+
terminal: 'imported',
|
|
485
|
+
imported: { eventId: imported.event_id, vertical: CRM_VERTICAL, scopeId: p },
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
it('a ping-pong between two verticals is cut at the hop cap, and the cut is visible', async () => {
|
|
489
|
+
const t = await newTenant();
|
|
490
|
+
const p = await install(t, CRM_VERTICAL);
|
|
491
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
492
|
+
const id = await create(t, p, 'Looped');
|
|
493
|
+
await crm(t, p, 'crm/touch', { id });
|
|
494
|
+
let quiet = false;
|
|
495
|
+
for (let pass = 0; pass < 20 && !quiet; pass++) {
|
|
496
|
+
const edges = edgesOf((await sweep()).report, t);
|
|
497
|
+
quiet = edges.every((e) => e.state === 'idle');
|
|
498
|
+
}
|
|
499
|
+
expect(quiet).toBe(true); // it stopped
|
|
500
|
+
// A touch crosses crm → board on the odd hops, a link board → crm on the even ones, so
|
|
501
|
+
// the ninth crossing, the first past the cap of 8, is a touch arriving at board.
|
|
502
|
+
const view = await board(t, c);
|
|
503
|
+
const touches = view.imports.filter((i) => i.type === 'crm.customer-touched');
|
|
504
|
+
expect(touches.filter((i) => i.withheld === null).map((i) => i.hops)).toEqual([1, 3, 5, 7]);
|
|
505
|
+
expect(touches.filter((i) => i.withheld === 'cascade')).toHaveLength(1);
|
|
506
|
+
// Cut where the operator of the receiving app will see it.
|
|
507
|
+
const letters = await fx.consumer.admin.deadLetters(staff, t, c, {});
|
|
508
|
+
expect(letters.entries.some((l) => l.error.includes('vertical boundaries'))).toBe(true);
|
|
509
|
+
});
|
|
510
|
+
it('a peer switched off on the PRODUCER pauses the edge, and nothing is lost when it is switched back on', async () => {
|
|
511
|
+
const t = await newTenant();
|
|
512
|
+
const p = await install(t, CRM_VERTICAL);
|
|
513
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
514
|
+
const reason = 'incident: pause exports to the board app';
|
|
515
|
+
await fx.producer.admin.revokeFromPeer(staff, { vertical: BOARD_VERTICAL, node: { tenantId: t, scopeId: p }, reason });
|
|
516
|
+
const during = await create(t, p, 'While paused');
|
|
517
|
+
const paused = await sweep();
|
|
518
|
+
expect(into(paused.report, c)).toMatchObject({
|
|
519
|
+
state: 'paused',
|
|
520
|
+
reason: expect.stringContaining(`does not grant vertical:${BOARD_VERTICAL} customer:read`),
|
|
521
|
+
});
|
|
522
|
+
expect((await board(t, c)).associations).toEqual([]);
|
|
523
|
+
// Nothing was read, so the watermark did not move past what arrived while paused.
|
|
524
|
+
expect((await fx.consumer.admin.importState(staff, t, c)).cursors).toEqual([]);
|
|
525
|
+
// Visible where a person reads it, not only in a report nobody keeps.
|
|
526
|
+
expect(paused.runs).toContainEqual(expect.objectContaining({ kind: 'vertical-events', unit: `${c}:${CRM_VERTICAL}`, outcome: 'skipped' }));
|
|
527
|
+
await fx.producer.admin.restoreToPeer(staff, {
|
|
528
|
+
vertical: BOARD_VERTICAL,
|
|
529
|
+
node: { tenantId: t, scopeId: p },
|
|
530
|
+
reason: 'resolved',
|
|
531
|
+
});
|
|
532
|
+
const after = await create(t, p, 'After restore');
|
|
533
|
+
expect(into((await sweep()).report, c)).toMatchObject({ state: 'delivered', delivered: 2 });
|
|
534
|
+
expect((await board(t, c)).associations.map((r) => r.crm_id)).toEqual([during, after]);
|
|
535
|
+
});
|
|
536
|
+
it('a peer switched off on the CONSUMER is refused at its door, and nothing is lost when it is switched back on', async () => {
|
|
537
|
+
const t = await newTenant();
|
|
538
|
+
const p = await install(t, CRM_VERTICAL);
|
|
539
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
540
|
+
await fx.consumer.admin.revokeFromPeer(staff, {
|
|
541
|
+
vertical: CRM_VERTICAL,
|
|
542
|
+
node: { tenantId: t, scopeId: c },
|
|
543
|
+
reason: 'the board app stops taking CRM changes for now',
|
|
544
|
+
});
|
|
545
|
+
const during = await create(t, p, 'While refused');
|
|
546
|
+
const refused = await sweep();
|
|
547
|
+
expect(into(refused.report, c)).toMatchObject({
|
|
548
|
+
state: 'paused',
|
|
549
|
+
reason: expect.stringContaining(`consumer '${BOARD_VERTICAL}' refused '${CRM_VERTICAL}'`),
|
|
550
|
+
});
|
|
551
|
+
const view = await board(t, c);
|
|
552
|
+
expect(view.associations).toEqual([]);
|
|
553
|
+
expect(view.imports).toEqual([]); // not even journaled: the door refused before anything ran
|
|
554
|
+
await fx.consumer.admin.restoreToPeer(staff, {
|
|
555
|
+
vertical: CRM_VERTICAL,
|
|
556
|
+
node: { tenantId: t, scopeId: c },
|
|
557
|
+
reason: 'resolved',
|
|
558
|
+
});
|
|
559
|
+
await sweep();
|
|
560
|
+
expect((await board(t, c)).associations.map((r) => r.crm_id)).toEqual([during]);
|
|
561
|
+
});
|
|
562
|
+
it('a fork is neither read nor fed, and two primary installs are refused rather than guessed between', async () => {
|
|
563
|
+
const t = await newTenant();
|
|
564
|
+
const p = await install(t, CRM_VERTICAL);
|
|
565
|
+
const c = await install(t, BOARD_VERTICAL);
|
|
566
|
+
await create(t, p, 'Before the fork');
|
|
567
|
+
await fx.producer.snapshotScope(staff, t, p); // a copy of crm in the same tenant
|
|
568
|
+
const first = await sweep();
|
|
569
|
+
// The fork did not make the producer ambiguous, and was not read.
|
|
570
|
+
expect(into(first.report, c)).toMatchObject({ state: 'delivered', producer: { scopeId: p } });
|
|
571
|
+
expect((await board(t, c)).associations.map((r) => r.name)).toEqual(['Before the fork']);
|
|
572
|
+
// A SECOND primary crm install: which one is "the" CRM is now a choice nobody made.
|
|
573
|
+
await install(t, CRM_VERTICAL);
|
|
574
|
+
await create(t, p, 'After the second install');
|
|
575
|
+
const { report } = await sweep();
|
|
576
|
+
expect(into(report, c)).toMatchObject({
|
|
577
|
+
state: 'unresolved',
|
|
578
|
+
reason: expect.stringContaining(`more than one primary instance of '${CRM_VERTICAL}'`),
|
|
579
|
+
});
|
|
580
|
+
expect((await board(t, c)).associations).toHaveLength(1);
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
//# sourceMappingURL=vertical-events-suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vertical-events-suite.js","sourceRoot":"","sources":["../src/vertical-events-suite.ts"],"names":[],"mappings":"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"}
|