flow-store-versioned-step-keying-performance.test.mjs
sha256:cfe8c8cf68336f6d46318bd40610c18d9ff7df231df2fb190af1f5a9c4f4f93b
fix(flow-store): versioned step keying for multi-version fl…
Human
minor
⚠ breaking
7 hours ago
| 1 | /** |
| 2 | * Tier 6 — PERFORMANCE: version resolution stays bounded (7A-10c). |
| 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 path from 'node:path'; |
| 8 | import { fileURLToPath } from 'node:url'; |
| 9 | import { upsertFlowVersion, getFlow, stepsForFlowVersion, loadFlowStore } from '../lib/flow/flow-store.mjs'; |
| 10 | import { makeFlowBundle, emptyStarterDir } from './fixtures/flow/authoring-helpers.mjs'; |
| 11 | |
| 12 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 13 | const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-flow-versioned-step-keying-perf'); |
| 14 | const visible = new Set(['personal', 'project', 'org']); |
| 15 | |
| 16 | describe('Flow store — versioned step keying (performance)', () => { |
| 17 | const dataDir = path.join(tmpRoot, 'data'); |
| 18 | const vaultId = 'default'; |
| 19 | let starterDir; |
| 20 | |
| 21 | beforeEach(() => { |
| 22 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 23 | fs.mkdirSync(dataDir, { recursive: true }); |
| 24 | starterDir = emptyStarterDir(dataDir); |
| 25 | |
| 26 | const flowId = 'flow_10c_perf'; |
| 27 | for (let i = 0; i < 30; i += 1) { |
| 28 | const bundle = makeFlowBundle({ flowId, version: `1.${i}.0`, steps: 20 }); |
| 29 | upsertFlowVersion(dataDir, vaultId, bundle.flow, bundle.steps); |
| 30 | } |
| 31 | }); |
| 32 | |
| 33 | afterEach(() => { |
| 34 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 35 | }); |
| 36 | |
| 37 | it('pinned getFlow p95 stays under 25ms for 30 versions × 20 steps', () => { |
| 38 | const samples = []; |
| 39 | for (let i = 0; i < 40; i += 1) { |
| 40 | const version = `1.${i % 30}.0`; |
| 41 | const t0 = performance.now(); |
| 42 | const got = getFlow(dataDir, vaultId, 'flow_10c_perf', { |
| 43 | filterScopes: visible, version, starterDir, |
| 44 | }); |
| 45 | samples.push(performance.now() - t0); |
| 46 | assert.ok(got); |
| 47 | } |
| 48 | samples.sort((a, b) => a - b); |
| 49 | const p95 = samples[Math.floor(samples.length * 0.95)]; |
| 50 | assert.ok(p95 < 25, `p95 ${p95}ms exceeds budget`); |
| 51 | }); |
| 52 | |
| 53 | it('stepsForFlowVersion is O(steps) not O(versions×steps)', () => { |
| 54 | const store = loadFlowStore(dataDir); |
| 55 | const vault = store.vaults[vaultId]; |
| 56 | const t0 = performance.now(); |
| 57 | for (let i = 0; i < 200; i += 1) { |
| 58 | stepsForFlowVersion(vault, 'flow_10c_perf', '1.15.0'); |
| 59 | } |
| 60 | const elapsed = performance.now() - t0; |
| 61 | assert.ok(elapsed < 50, `200 lookups took ${elapsed}ms`); |
| 62 | }); |
| 63 | }); |
File History
1 commit
sha256:cfe8c8cf68336f6d46318bd40610c18d9ff7df231df2fb190af1f5a9c4f4f93b
fix(flow-store): versioned step keying for multi-version fl…
Human
minor
⚠
7 hours ago