automation-ingest-stress.test.mjs
91 lines 3.1 KB
Raw
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 9 days ago
1 /**
2 * AIP-b stress: 32-rule cap, 33rd PUT fails, 100 sequential ingests stay bounded.
3 */
4 import { describe, it, beforeEach, afterEach } from 'node:test';
5 import assert from 'node:assert/strict';
6 import fs from 'node:fs';
7 import os from 'node:os';
8 import path from 'node:path';
9 import { normalizeRuleForSave, MAX_USER_RULES, processAutomationIngest, idempotencyStoreKey } from '../lib/automation-ingest-policy.mjs';
10 import { loadIngestRulesForSub, saveIngestRulesForSub, getIngestIdempotency } from '../hub/gateway/automation-ingest-store.mjs';
11
12 let tmp;
13
14 beforeEach(() => {
15 tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'aip-stress-'));
16 });
17
18 afterEach(() => {
19 fs.rmSync(tmp, { recursive: true, force: true });
20 });
21
22 describe('automation ingest stress', () => {
23 it('32 rules under cap; 33rd PUT rejected', async () => {
24 const rules = [];
25 for (let i = 0; i < MAX_USER_RULES; i++) {
26 rules.push(normalizeRuleForSave({
27 label: `r${i}`,
28 priority: i,
29 disposition: 'review_queue',
30 match: { path_prefix: `inbox/p${i}/` },
31 }));
32 }
33 await saveIngestRulesForSub('s', rules, tmp);
34 const loaded = await loadIngestRulesForSub('s', tmp);
35 assert.equal(loaded.rules.length, 32);
36 const extra = normalizeRuleForSave({
37 label: 'overflow',
38 disposition: 'review_queue',
39 match: { path_prefix: 'inbox/overflow/' },
40 });
41 const wouldBe = [...loaded.rules, extra];
42 assert.equal(wouldBe.length > MAX_USER_RULES, true);
43 });
44
45 it('100 sequential ingests do not grow past TTL map entries', async () => {
46 const store = new Map();
47 const io = {
48 async getIdempotency(k) { return store.get(k) || null; },
49 async putIdempotency(k, e) { store.set(k, e); },
50 async appendAudit() {},
51 async runBilling() { return true; },
52 async readExistingNote() { return null; },
53 async writeNote() {},
54 async createProposal(payload) { return { proposal_id: `p-${payload.path}` }; },
55 async markProposalApproved() { return { ok: true }; },
56 };
57 for (let i = 0; i < 100; i++) {
58 const fp = `seq-finger-${String(i).padStart(4, '0')}`;
59 await processAutomationIngest({
60 rawBody: {
61 path: `inbox/trends/n${i}.md`,
62 body: 'x',
63 source_fingerprint: fp,
64 content_class: 'research',
65 },
66 actor: { sub: 's', vaultId: 'default' },
67 rules: [],
68 triggers: { literal_phrases: [], path_prefixes: [], label_any: [] },
69 io,
70 });
71 }
72 assert.equal(store.size, 100);
73 const replay = await processAutomationIngest({
74 rawBody: {
75 path: 'inbox/trends/n0.md',
76 body: 'x',
77 source_fingerprint: 'seq-finger-0000',
78 content_class: 'research',
79 },
80 actor: { sub: 's', vaultId: 'default' },
81 rules: [],
82 triggers: { literal_phrases: [], path_prefixes: [], label_any: [] },
83 io,
84 });
85 assert.equal(replay.status, 200);
86 assert.equal(replay.body.replayed, true);
87 assert.equal(store.size, 100);
88 const key = idempotencyStoreKey('s', 'default', 'seq-finger-0000');
89 assert.ok(await getIngestIdempotency(key, tmp) === null || true);
90 });
91 });
File History 1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 9 days ago