Initial import of verae-zapier-simulator from zapier monorepo
This commit is contained in:
commit
e727cc34d2
10 changed files with 1642 additions and 0 deletions
134
test/pipeline.test.js
Normal file
134
test/pipeline.test.js
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { Simulator, sha256Hex } from '../src/pipeline.js';
|
||||
|
||||
describe('Zapier simulator pipeline', () => {
|
||||
it('signup then connect then register+wait with metadata', async () => {
|
||||
const s = new Simulator();
|
||||
const sign = await s.run({ action: 'signup', input: { email: 'ada@example.com', plan: 'pro' } });
|
||||
assert.ok(sign.response.apiKey.startsWith('zpk_'));
|
||||
const conn = await s.run({ action: 'connect_zapier', input: { apiKey: sign.response.apiKey } });
|
||||
assert.equal(conn.response.connected, true);
|
||||
const wait = await s.run({
|
||||
action: 'timestamp_and_wait',
|
||||
includeAttached: true,
|
||||
input: { data: 'hello from zapier', publicMetadata: { source: 'zap' } },
|
||||
});
|
||||
assert.equal(wait.response.status, 'completed');
|
||||
assert.equal(wait.response.receipts[0].kind, 'seal');
|
||||
assert.ok(wait.response.receipts.some((r) => r.kind === 'metadata-attach'));
|
||||
assert.ok(wait.trace.some((e) => e.address === 'verae.zapier.jobs.watch'));
|
||||
assert.ok(wait.trace.some((e) => e.address === 'verae.zapier.jobs.events'));
|
||||
assert.ok(wait.trace.some((e) => e.address === 'verae.archive.put'));
|
||||
assert.ok(wait.trace.some((e) => e.address === 'verae.archive.query'));
|
||||
const zapNats = wait.trace.filter(
|
||||
(e) => e.module === 'zapier-platform-app' && String(e.address).startsWith('verae.'),
|
||||
);
|
||||
assert.equal(zapNats.length, 0);
|
||||
assert.equal(wait.monitor.findings.find((f) => f.id === 'zapier-no-nats').ok, true);
|
||||
assert.equal(wait.monitor.findings.find((f) => f.id === 'chain-no-bytes').ok, true);
|
||||
});
|
||||
|
||||
it('async create returns jobId; second register returns original seal', async () => {
|
||||
const s = new Simulator();
|
||||
const a = await s.run({ action: 'create_timestamp', input: { data: 'once' } });
|
||||
assert.equal(a.response.status, 'accepted');
|
||||
const b = await s.run({ action: 'create_timestamp', input: { data: 'once' } });
|
||||
assert.equal(b.response.existing, true);
|
||||
assert.equal(b.response.jobId, a.response.jobId);
|
||||
});
|
||||
|
||||
it('central lookup finds itemized hash and misses a bulk leaf', async () => {
|
||||
const s = new Simulator();
|
||||
const reg = await s.run({ action: 'timestamp_and_wait', input: { data: 'solo' } });
|
||||
const hit = await s.run({ action: 'hash_lookup', input: { sha256: reg.response.sha256 } });
|
||||
assert.equal(hit.response.exists, true);
|
||||
assert.equal(hit.response.itemizedOnMainChain, true);
|
||||
|
||||
const batch = await s.run({
|
||||
action: 'batch_timestamp',
|
||||
input: { items: 'invoice-1001\ninvoice-1002\ninvoice-1003' },
|
||||
});
|
||||
assert.equal(batch.response.leafCount, 3);
|
||||
const leaf = batch.response.leaves[0];
|
||||
assert.equal(leaf, sha256Hex('invoice-1001'));
|
||||
const miss = await s.run({ action: 'hash_lookup', input: { sha256: leaf } });
|
||||
assert.equal(miss.response.exists, false);
|
||||
assert.ok(miss.monitor.suggestions.some((x) => x.id === 'tree-lookup-action'));
|
||||
});
|
||||
|
||||
it('tree lookup proves a leaf that is only in the bulk summary', async () => {
|
||||
const s = new Simulator();
|
||||
const batch = await s.run({
|
||||
action: 'batch_timestamp',
|
||||
input: { items: ['alpha-doc', 'beta-doc', 'gamma-doc'] },
|
||||
});
|
||||
const leaf = batch.response.leaves[1];
|
||||
const found = await s.run({ action: 'tree_lookup', input: { sha256: leaf } });
|
||||
assert.equal(found.response.exists, true);
|
||||
assert.equal(found.response.itemizedOnMainChain, false);
|
||||
assert.equal(found.response.proofOk, true);
|
||||
assert.equal(found.response.merkleRoot, batch.response.merkleRoot);
|
||||
assert.ok(found.response.receipts.some((r) => r.kind === 'tree-leaf'));
|
||||
assert.ok(found.response.receipts.some((r) => r.kind === 'seal' && r.of === 'merkleRoot'));
|
||||
assert.ok(found.trace.some((e) => e.status === 'silent'));
|
||||
assert.ok(found.trace.some((e) => String(e.address).startsWith('verae.archive.reply.')));
|
||||
const bloomLeak = found.trace.filter((e) => e.status === 'silent' && String(e.address).includes('archive.reply'));
|
||||
assert.equal(bloomLeak.length, 0);
|
||||
});
|
||||
|
||||
it('402 quota is traced and suggested', async () => {
|
||||
const s = new Simulator();
|
||||
const r = await s.run({ action: 'create_timestamp', input: { data: 'x' }, faults: { failEdge402: true } });
|
||||
assert.equal(r.response.status, 402);
|
||||
assert.ok(r.monitor.suggestions.some((x) => x.id === '402-upgrade-url'));
|
||||
});
|
||||
|
||||
it('NATS events drop then recovery retry', async () => {
|
||||
const s = new Simulator();
|
||||
const fail = await s.run({
|
||||
action: 'timestamp_and_wait',
|
||||
input: { data: 'drop' },
|
||||
faults: { failNatsDropEvents: true },
|
||||
});
|
||||
assert.equal(fail.response.status, 'pending');
|
||||
assert.ok(fail.monitor.suggestions.some((x) => x.id === 'wait-timeout' || x.id === 'add-retry'));
|
||||
|
||||
const ok = await s.run({
|
||||
action: 'timestamp_and_wait',
|
||||
input: { data: 'drop-recover' },
|
||||
faults: { failNatsDropEvents: true, recover: true },
|
||||
});
|
||||
assert.equal(ok.response.status, 'completed');
|
||||
assert.ok(ok.trace.some((e) => e.status === 'retry'));
|
||||
});
|
||||
|
||||
it('chain delay is monitored', async () => {
|
||||
const s = new Simulator();
|
||||
const r = await s.run({
|
||||
action: 'create_timestamp',
|
||||
input: { data: 'slow' },
|
||||
faults: { chainMs: 220 },
|
||||
});
|
||||
assert.equal(r.response.status, 'accepted');
|
||||
assert.ok(r.monitor.findings.some((f) => f.kind === 'delay' && f.ok === false));
|
||||
});
|
||||
|
||||
it('files never appear on the chain hop payload', async () => {
|
||||
const s = new Simulator();
|
||||
const r = await s.run({
|
||||
action: 'timestamp_and_wait',
|
||||
includeAttached: true,
|
||||
input: {
|
||||
data: 'with-file',
|
||||
files: [{ path: 'a.txt', data: 'bytes' }],
|
||||
},
|
||||
});
|
||||
const chain = r.trace.filter((e) => e.module === 'verae-chain-client');
|
||||
for (const e of chain) {
|
||||
assert.equal(e.payload?.files, undefined);
|
||||
assert.equal(e.payload?.contentBase64, undefined);
|
||||
}
|
||||
assert.ok(r.response.files.length >= 1);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue