From 95ee9068cbbf931f3df0aa0330a9913ae0a18ffa Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Tue, 7 Mar 2023 13:45:23 +0000 Subject: [PATCH 1/3] push nodes impl --- packages/signia/src/Computed.ts | 4 ++ .../signia/src/__tests__/computed.test.ts | 21 ++++++++ .../signia/src/__tests__/fuzz.tlstate.test.ts | 50 ++++++++++++++----- packages/signia/src/transactions.ts | 42 +++++++++++++--- 4 files changed, 99 insertions(+), 18 deletions(-) diff --git a/packages/signia/src/Computed.ts b/packages/signia/src/Computed.ts index 31b3537..a8cd1d8 100644 --- a/packages/signia/src/Computed.ts +++ b/packages/signia/src/Computed.ts @@ -98,6 +98,8 @@ export interface ComputedOptions { * @returns */ isEqual?: (a: any, b: any) => boolean + + isPush?: boolean } /** @@ -140,6 +142,7 @@ export class _Computed implements Computed { } historyBuffer?: HistoryBuffer + isPush: boolean // The last-computed value of this signal. private state: Value = UNINITIALIZED as unknown as Value @@ -167,6 +170,7 @@ export class _Computed implements Computed { } this.computeDiff = options?.computeDiff this.isEqual = options?.isEqual ?? null + this.isPush = options?.isPush ?? false } __unsafe__getWithoutCapture(): Value { diff --git a/packages/signia/src/__tests__/computed.test.ts b/packages/signia/src/__tests__/computed.test.ts index 10e7e57..279b3b9 100644 --- a/packages/signia/src/__tests__/computed.test.ts +++ b/packages/signia/src/__tests__/computed.test.ts @@ -587,3 +587,24 @@ describe(getComputedInstance, () => { expect(bInst).toBeInstanceOf(_Computed) }) }) + +describe('push computeds', () => { + it('prevent traversal', () => { + const user = atom('', { id: 1, name: 'steve' }) + const name = computed('', () => user.value.name, { isPush: true }) + const nameLength = computed('', () => name.value.length) + let numNameLengthReactions = 0 + const r = reactor('', () => { + numNameLengthReactions++ + nameLength.value + }) + r.start() + expect(numNameLengthReactions).toBe(1) + const lastTraversed = r.scheduler.lastTraversedEpoch + + user.set({ id: 2, name: 'steve' }) + + expect(numNameLengthReactions).toBe(1) + expect(r.scheduler.lastTraversedEpoch).toBe(lastTraversed) + }) +}) diff --git a/packages/signia/src/__tests__/fuzz.tlstate.test.ts b/packages/signia/src/__tests__/fuzz.tlstate.test.ts index 7d8a6d2..b8c1b23 100644 --- a/packages/signia/src/__tests__/fuzz.tlstate.test.ts +++ b/packages/signia/src/__tests__/fuzz.tlstate.test.ts @@ -98,7 +98,7 @@ const MAX_DERIVATIONS_IN_DERIVATIONS = 10 const MAX_ATOMS_IN_DERIVATIONS = 10 const MAX_REACTORS = 10 const MAX_DEPENDENCIES_PER_ATOM = 3 -const MAX_OPS_IN_TRANSACTION = 10 +const MAX_OPS_IN_TRANSACTION = 2 class Test { source: RandomSource @@ -160,7 +160,9 @@ class Test { times(this.source.nextIntInRange(1, MAX_ATOMS_IN_DERIVATIONS), () => { const derivationId = this.source.nextId() const atom = this.source.selectOne(Object.values(this.systemState.atoms)) - this.systemState.atomsInDerivations[derivationId] = computed(derivationId, () => atom) + this.systemState.atomsInDerivations[derivationId] = computed(derivationId, () => atom, { + isPush: this.source.selectOne([true, false, undefined]), + }) }) times(this.source.nextIntInRange(1, MAX_DERIVATIONS), () => { @@ -176,13 +178,19 @@ class Test { const inputC = this.source.selectOne(derivables) const inputD = this.source.selectOne(derivables) this.systemState.derivations[derivationId] = { - derivation: computed(derivationId, () => { - if (unpack(inputA) === unpack(inputB)) { - return unpack(inputC) - } else { - return unpack(inputD) + derivation: computed( + derivationId, + () => { + if (unpack(inputA) === unpack(inputB)) { + return unpack(inputC) + } else { + return unpack(inputD) + } + }, + { + isPush: this.source.selectOne([true, false, undefined]), } - }), + ), sneakyGet: () => { if (this.unpack_sneaky(inputA) === this.unpack_sneaky(inputB)) { return this.unpack_sneaky(inputC) @@ -195,8 +203,15 @@ class Test { times(this.source.nextIntInRange(1, MAX_DERIVATIONS_IN_DERIVATIONS), () => { const derivationId = this.source.nextId() - this.systemState.derivationsInDerivations[derivationId] = computed(derivationId, () => - this.source.selectOne(Object.values(this.systemState.derivations).map((d) => d.derivation)) + this.systemState.derivationsInDerivations[derivationId] = computed( + derivationId, + () => + this.source.selectOne( + Object.values(this.systemState.derivations).map((d) => d.derivation) + ), + { + isPush: this.source.selectOne([true, false, undefined]), + } ) }) @@ -352,13 +367,24 @@ class Test { const NUM_TESTS = 100 const NUM_OPS_PER_TEST = 1000 -function runTest(seed: number) { +function runTest(seed: number, ops?: Op[]) { const test = new Test(seed) + if (ops) { + ops.forEach((op) => test.applyOp(op)) + const { expected, actual } = test.getResultComparisons() + expect(expected).toEqual(actual) + return + } // console.log(test.systemState) for (let i = 0; i < NUM_OPS_PER_TEST; i++) { test.tick() const { expected, actual } = test.getResultComparisons() - expect(expected).toEqual(actual) + try { + expect(expected).toEqual(actual) + } catch (e) { + console.log(JSON.stringify(test.ops, null, 2)) + throw e + } } } diff --git a/packages/signia/src/transactions.ts b/packages/signia/src/transactions.ts index 3b5e1e9..15927dc 100644 --- a/packages/signia/src/transactions.ts +++ b/packages/signia/src/transactions.ts @@ -1,7 +1,8 @@ import { _Atom } from './Atom' +import { _Computed } from './Computed' import { GLOBAL_START_EPOCH } from './constants' import { EffectScheduler } from './EffectScheduler' -import { Child, Signal } from './types' +import { Child } from './types' // The current epoch (global to all atoms). export let globalEpoch = GLOBAL_START_EPOCH + 1 @@ -13,6 +14,8 @@ export function advanceGlobalEpoch() { globalEpoch++ } +let rootTransactionEpoch = GLOBAL_START_EPOCH + class Transaction { constructor(public readonly parent: Transaction | null) {} initialAtomValues = new Map<_Atom, any>() @@ -83,22 +86,27 @@ function flushChanges(atoms: Iterable<_Atom>) { const reactors = new Set>() // Visit each descendant of the atom, collecting reactors. - const traverse = (node: Child) => { + const traverse = (node: Child, isPush: boolean) => { if (node.lastTraversedEpoch === globalEpoch) { return } node.lastTraversedEpoch = globalEpoch - if ('maybeScheduleEffect' in node) { + if (node instanceof EffectScheduler) { reactors.add(node) - } else { - ;(node as any as Signal).children.visit(traverse) + } else if (node instanceof _Computed) { + if (isPush && node.isPush && node.lastChangedEpoch < rootTransactionEpoch) { + // don't traverse push nodes that didn't change + // need to make sure that there is an unbroken chain of push nodes to the root atom here + } else { + node.children.visit((child) => traverse(child, node.isPush)) + } } } for (const atom of atoms) { - atom.children.visit(traverse) + atom.children.visit((node) => traverse(node, true)) } // Run each reactor. @@ -110,6 +118,23 @@ function flushChanges(atoms: Iterable<_Atom>) { } } +/** + * flush push computations immediately + */ +function flushPushes(atom: _Atom) { + const traverse = (node: Child) => { + if (node instanceof _Computed && node.isPush) { + const lastChangedEpoch = node.lastChangedEpoch + node.__unsafe__getWithoutCapture() + if (node.lastChangedEpoch !== lastChangedEpoch) { + node.children.visit(traverse) + } + } + } + + atom.children.visit(traverse) +} + /** * Handle a change to an atom. * @@ -119,7 +144,9 @@ function flushChanges(atoms: Iterable<_Atom>) { * @internal */ export function atomDidChange(atom: _Atom, previousValue: any) { + flushPushes(atom) if (!currentTransaction) { + rootTransactionEpoch = globalEpoch flushChanges([atom]) } else if (!currentTransaction.initialAtomValues.has(atom)) { currentTransaction.initialAtomValues.set(atom, previousValue) @@ -207,6 +234,9 @@ export let currentTransaction = null as Transaction | null * @public */ export function transaction(fn: (rollback: () => void) => T) { + if (!currentTransaction) { + rootTransactionEpoch = globalEpoch + } const txn = new Transaction(currentTransaction) // Set the current transaction to the transaction From 95ae28262c590745d0e2ec68a27d7b1fa13ea60b Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Wed, 8 Mar 2023 16:20:45 +0000 Subject: [PATCH 2/3] improve fuzz tests --- .../signia/src/__tests__/fuzz.tlstate.test.ts | 230 ++++++++++++------ 1 file changed, 153 insertions(+), 77 deletions(-) diff --git a/packages/signia/src/__tests__/fuzz.tlstate.test.ts b/packages/signia/src/__tests__/fuzz.tlstate.test.ts index b8c1b23..32c8d46 100644 --- a/packages/signia/src/__tests__/fuzz.tlstate.test.ts +++ b/packages/signia/src/__tests__/fuzz.tlstate.test.ts @@ -1,9 +1,8 @@ import { times } from 'lodash' -import { atom, Atom, isAtom } from '../Atom' -import { computed, Computed, isComputed } from '../Computed' +import { atom, Atom } from '../Atom' +import { computed, Computed } from '../Computed' import { Reactor, reactor } from '../EffectScheduler' -import { transact } from '../transactions' -import { Signal } from '../types' +import { transaction } from '../transactions' class RandomSource { private seed: number @@ -62,23 +61,58 @@ class RandomSource { } } -const LETTERS = ['a', 'b', 'c', 'd', 'e', 'f'] as const +const LETTERS = ['a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'] as const type Letter = (typeof LETTERS)[number] -const unpack = (value: unknown): Letter => { - if (isComputed(value) || isAtom(value)) { - return unpack(value.value) as Letter - } - return value as Letter +const toUpper = (letter: Letter): Letter => letter.toUpperCase() as Letter +const toLower = (letter: Letter): Letter => letter.toLowerCase() as Letter + +const conversions = { + toUpper, + toLower, + none: (x: Letter) => x, +} +type Conversion = keyof typeof conversions + +type AtomDep = { type: 'atom'; atom: Atom; value: Letter } +type AtomInAtomDep = { type: 'atomInAtom'; atomInAtom: Atom>; innerAtomId: string } +type DerivationDep = { + type: 'derivation' + derivation: Computed + sneakyGet: () => Letter + conversion: Conversion + isPush: boolean +} +type DerivationInDerivationDep = { + type: 'derivationInDerivation' + derivationInDerivation: Computed> + innerDerivationId: string + isPush: boolean } +type AtomInDerivationDep = { + type: 'atomInDerivation' + atomInDerivation: Computed> + innerAtomId: string + isPush: boolean +} + +type Dep = AtomDep | AtomInAtomDep | DerivationDep | DerivationInDerivationDep | AtomInDerivationDep type FuzzSystemState = { - atoms: Record> - atomsInAtoms: Record>> - derivations: Record; sneakyGet: () => Letter }> - derivationsInDerivations: Record>> - atomsInDerivations: Record>> - reactors: Record[] }> + atoms: Record + atomsInAtoms: Record + derivations: Record + derivationsInDerivations: Record + atomsInDerivations: Record + reactors: Record< + string, + { + reactor: Reactor + result: string + dependencies: Dep[] + sneakyResult: string + } + > } type Op = @@ -97,8 +131,8 @@ const MAX_DERIVATIONS = 10 const MAX_DERIVATIONS_IN_DERIVATIONS = 10 const MAX_ATOMS_IN_DERIVATIONS = 10 const MAX_REACTORS = 10 -const MAX_DEPENDENCIES_PER_ATOM = 3 -const MAX_OPS_IN_TRANSACTION = 2 +const MAX_DEPENDENCIES_PER_REACTOR = 3 +const MAX_OPS_IN_TRANSACTION = 10 class Test { source: RandomSource @@ -111,18 +145,34 @@ class Test { reactors: {}, } - unpack_sneaky = (value: unknown): Letter => { - if (isComputed(value)) { - if (this.systemState.derivations[value.name]) { - return this.systemState.derivations[value.name].sneakyGet() - } - // @ts-expect-error - return this.unpack_sneaky(value.state) as Letter - } else if (isAtom(value)) { - // @ts-expect-error - return this.unpack_sneaky(value.current) as Letter + unpack = (value: Dep): Letter => { + switch (value.type) { + case 'atom': + return value.atom.value + case 'atomInAtom': + return value.atomInAtom.value.value + case 'derivation': + return value.derivation.value + case 'derivationInDerivation': + return value.derivationInDerivation.value.value + case 'atomInDerivation': + return value.atomInDerivation.value.value + } + } + + unpack_sneaky = (value: Dep): Letter => { + switch (value.type) { + case 'atom': + return value.value + case 'atomInAtom': + return this.systemState.atoms[value.innerAtomId].value + case 'derivation': + return value.sneakyGet() + case 'derivationInDerivation': + return this.systemState.derivations[value.innerDerivationId].sneakyGet() + case 'atomInDerivation': + return this.systemState.atoms[value.innerAtomId].value } - return value as Letter } getResultComparisons() { @@ -130,11 +180,11 @@ class Test { expected: {}, actual: {}, } - for (const [reactorId, { reactor, result: actualResult, dependencies }] of Object.entries( - this.systemState.reactors - )) { - if (!reactor.scheduler.isActivelyListening) continue - result.expected[reactorId] = dependencies.map(this.unpack_sneaky).join(':') + for (const [ + reactorId, + { result: actualResult, sneakyResult: expectedResult }, + ] of Object.entries(this.systemState.reactors)) { + result.expected[reactorId] = expectedResult result.actual[reactorId] = actualResult } @@ -146,23 +196,32 @@ class Test { times(this.source.nextIntInRange(1, MAX_ATOMS), () => { const atomId = this.source.nextId() - this.systemState.atoms[atomId] = atom(atomId, this.source.selectOne(LETTERS)) + const initial = this.source.selectOne(LETTERS) + this.systemState.atoms[atomId] = { type: 'atom', atom: atom(atomId, initial), value: initial } }) times(this.source.nextIntInRange(1, MAX_ATOMS_IN_ATOMS), () => { const atomId = this.source.nextId() - this.systemState.atomsInAtoms[atomId] = atom( - atomId, - this.source.selectOne(Object.values(this.systemState.atoms)) - ) + const innerAtomId = this.source.selectOne(Object.keys(this.systemState.atoms)) + this.systemState.atomsInAtoms[atomId] = { + type: 'atomInAtom', + atomInAtom: atom(atomId, this.systemState.atoms[innerAtomId].atom), + innerAtomId, + } }) times(this.source.nextIntInRange(1, MAX_ATOMS_IN_DERIVATIONS), () => { const derivationId = this.source.nextId() - const atom = this.source.selectOne(Object.values(this.systemState.atoms)) - this.systemState.atomsInDerivations[derivationId] = computed(derivationId, () => atom, { - isPush: this.source.selectOne([true, false, undefined]), - }) + const innerAtomId = this.source.selectOne(Object.keys(this.systemState.atoms)) + const isPush = this.source.selectOne([false, false]) + this.systemState.atomsInDerivations[derivationId] = { + type: 'atomInDerivation', + atomInDerivation: computed(derivationId, () => this.systemState.atoms[innerAtomId].atom, { + isPush, + }), + innerAtomId, + isPush, + } }) times(this.source.nextIntInRange(1, MAX_DERIVATIONS), () => { @@ -177,25 +236,30 @@ class Test { const inputB = this.source.selectOne(derivables) const inputC = this.source.selectOne(derivables) const inputD = this.source.selectOne(derivables) + const conversion = this.source.selectOne(Object.keys(conversions)) as Conversion + const isPush = this.source.selectOne([false, false]) this.systemState.derivations[derivationId] = { + type: 'derivation', derivation: computed( derivationId, () => { - if (unpack(inputA) === unpack(inputB)) { - return unpack(inputC) + if (this.unpack(inputA) === this.unpack(inputB)) { + return conversions[conversion](this.unpack(inputC)) } else { - return unpack(inputD) + return conversions[conversion](this.unpack(inputD)) } }, { - isPush: this.source.selectOne([true, false, undefined]), + isPush, } ), + isPush, + conversion, sneakyGet: () => { if (this.unpack_sneaky(inputA) === this.unpack_sneaky(inputB)) { - return this.unpack_sneaky(inputC) + return conversions[conversion](this.unpack_sneaky(inputC)) } else { - return this.unpack_sneaky(inputD) + return conversions[conversion](this.unpack_sneaky(inputD)) } }, } @@ -203,23 +267,27 @@ class Test { times(this.source.nextIntInRange(1, MAX_DERIVATIONS_IN_DERIVATIONS), () => { const derivationId = this.source.nextId() - this.systemState.derivationsInDerivations[derivationId] = computed( - derivationId, - () => - this.source.selectOne( - Object.values(this.systemState.derivations).map((d) => d.derivation) - ), - { - isPush: this.source.selectOne([true, false, undefined]), - } - ) + const innerDerivationId = this.source.selectOne(Object.keys(this.systemState.derivations)) + const isPush = this.source.selectOne([false, false]) + this.systemState.derivationsInDerivations[derivationId] = { + type: 'derivationInDerivation', + derivationInDerivation: computed( + derivationId, + () => this.systemState.derivations[innerDerivationId].derivation, + { + isPush, + } + ), + isPush, + innerDerivationId, + } }) times(this.source.nextIntInRange(1, MAX_REACTORS), () => { const reactorId = this.source.nextId() - const dependencies: Signal[] = [] + const dependencies: Dep[] = [] - times(this.source.nextIntInRange(1, MAX_DEPENDENCIES_PER_ATOM), () => { + times(this.source.nextIntInRange(1, MAX_DEPENDENCIES_PER_REACTOR), () => { this.source.executeOne({ 'add a random atom': () => { dependencies.push(this.source.selectOne(Object.values(this.systemState.atoms))) @@ -228,11 +296,7 @@ class Test { dependencies.push(this.source.selectOne(Object.values(this.systemState.atomsInAtoms))) }, 'add a random derivation': () => { - dependencies.push( - this.source.selectOne( - Object.values(this.systemState.derivations).map((d) => d.derivation) - ) - ) + dependencies.push(this.source.selectOne(Object.values(this.systemState.derivations))) }, 'add a random derivation in derivation': () => { dependencies.push( @@ -250,8 +314,9 @@ class Test { this.systemState.reactors[reactorId] = { reactor: reactor(reactorId, () => { - this.systemState.reactors[reactorId].result = dependencies.map(unpack).join(':') + this.systemState.reactors[reactorId].result = dependencies.map(this.unpack).join(':') }), + sneakyResult: '', result: '', dependencies, } @@ -318,11 +383,12 @@ class Test { applyOp(op: Op) { switch (op.type) { case 'update_atom': { - this.systemState.atoms[op.id].set(op.value) + this.systemState.atoms[op.id].atom.set(op.value) + this.systemState.atoms[op.id].value = op.value break } case 'deref_atom_in_derivation': { - this.systemState.atomsInDerivations[op.id].value + this.systemState.atomsInDerivations[op.id].atomInDerivation.value break } case 'deref_derivation': { @@ -330,21 +396,27 @@ class Test { break } case 'deref_derivation_in_derivation': { - this.systemState.derivationsInDerivations[op.id].value + this.systemState.derivationsInDerivations[op.id].derivationInDerivation.value break } case 'update_atom_in_atom': { - this.systemState.atomsInAtoms[op.id].set(this.systemState.atoms[op.atomId]) + this.systemState.atomsInAtoms[op.id].atomInAtom.set(this.systemState.atoms[op.atomId].atom) + this.systemState.atomsInAtoms[op.id].innerAtomId = op.atomId break } case 'run_several_ops_in_transaction': { - transact(() => { + transaction(() => { op.ops.forEach((op) => this.applyOp(op)) }) break } case 'start_reactor': { this.systemState.reactors[op.id].reactor.start() + this.systemState.reactors[op.id].sneakyResult = this.systemState.reactors[ + op.id + ].dependencies + .map(this.unpack_sneaky) + .join(':') break } case 'stop_reactor': { @@ -357,20 +429,24 @@ class Test { } } - tick() { - const op = this.getNextOp() + tick(op = this.getNextOp()) { this.ops.push(op) this.applyOp(op) + for (const reactor of Object.values(this.systemState.reactors)) { + if (reactor.reactor.scheduler.isActivelyListening) { + reactor.sneakyResult = reactor.dependencies.map(this.unpack_sneaky).join(':') + } + } } } -const NUM_TESTS = 100 -const NUM_OPS_PER_TEST = 1000 +const NUM_TESTS = 1000 +const NUM_OPS_PER_TEST = 300 function runTest(seed: number, ops?: Op[]) { const test = new Test(seed) if (ops) { - ops.forEach((op) => test.applyOp(op)) + ops.forEach((op) => test.tick(op)) const { expected, actual } = test.getResultComparisons() expect(expected).toEqual(actual) return From 9d665c6696a04240ea7d066b2128ab62aef3f6de Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 13 Mar 2023 09:47:55 +0000 Subject: [PATCH 3/3] stash failing test --- .../signia/src/__tests__/fuzz.tlstate.test.ts | 108 ++++++++++-------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/packages/signia/src/__tests__/fuzz.tlstate.test.ts b/packages/signia/src/__tests__/fuzz.tlstate.test.ts index 32c8d46..bd16246 100644 --- a/packages/signia/src/__tests__/fuzz.tlstate.test.ts +++ b/packages/signia/src/__tests__/fuzz.tlstate.test.ts @@ -213,7 +213,7 @@ class Test { times(this.source.nextIntInRange(1, MAX_ATOMS_IN_DERIVATIONS), () => { const derivationId = this.source.nextId() const innerAtomId = this.source.selectOne(Object.keys(this.systemState.atoms)) - const isPush = this.source.selectOne([false, false]) + const isPush = this.source.selectOne([false, true]) this.systemState.atomsInDerivations[derivationId] = { type: 'atomInDerivation', atomInDerivation: computed(derivationId, () => this.systemState.atoms[innerAtomId].atom, { @@ -237,7 +237,7 @@ class Test { const inputC = this.source.selectOne(derivables) const inputD = this.source.selectOne(derivables) const conversion = this.source.selectOne(Object.keys(conversions)) as Conversion - const isPush = this.source.selectOne([false, false]) + const isPush = this.source.selectOne([false, true]) this.systemState.derivations[derivationId] = { type: 'derivation', derivation: computed( @@ -327,13 +327,13 @@ class Test { getNextOp(): Op { return this.source.executeOne({ - 'update atom': () => { - return { - type: 'update_atom', - id: this.source.selectOne(Object.keys(this.systemState.atoms)), - value: this.source.selectOne(LETTERS), - } - }, + // 'update atom': () => { + // return { + // type: 'update_atom', + // id: this.source.selectOne(Object.keys(this.systemState.atoms)), + // value: this.source.selectOne(LETTERS), + // } + // }, 'update atom in atom': () => { return { type: 'update_atom_in_atom', @@ -341,42 +341,42 @@ class Test { atomId: this.source.selectOne(Object.keys(this.systemState.atoms)), } }, - 'deref atom in derivation': () => { - return { - type: 'deref_atom_in_derivation', - id: this.source.selectOne(Object.keys(this.systemState.atomsInDerivations)), - } - }, - 'deref derivation in derivation': () => { - return { - type: 'deref_derivation_in_derivation', - id: this.source.selectOne(Object.keys(this.systemState.derivationsInDerivations)), - } - }, - 'deref derivation': () => { - return { - type: 'deref_derivation', - id: this.source.selectOne(Object.keys(this.systemState.derivations)), - } - }, - 'run several ops in a transaction': () => { - return { - type: 'run_several_ops_in_transaction', - ops: times(this.source.nextIntInRange(2, MAX_OPS_IN_TRANSACTION), () => this.getNextOp()), - } - }, + // 'deref atom in derivation': () => { + // return { + // type: 'deref_atom_in_derivation', + // id: this.source.selectOne(Object.keys(this.systemState.atomsInDerivations)), + // } + // }, + // 'deref derivation in derivation': () => { + // return { + // type: 'deref_derivation_in_derivation', + // id: this.source.selectOne(Object.keys(this.systemState.derivationsInDerivations)), + // } + // }, + // 'deref derivation': () => { + // return { + // type: 'deref_derivation', + // id: this.source.selectOne(Object.keys(this.systemState.derivations)), + // } + // }, + // 'run several ops in a transaction': () => { + // return { + // type: 'run_several_ops_in_transaction', + // ops: times(this.source.nextIntInRange(2, MAX_OPS_IN_TRANSACTION), () => this.getNextOp()), + // } + // }, start_reactor: () => { return { type: 'start_reactor', id: this.source.selectOne(Object.keys(this.systemState.reactors)), } }, - stop_reactor: () => { - return { - type: 'stop_reactor', - id: this.source.selectOne(Object.keys(this.systemState.reactors)), - } - }, + // stop_reactor: () => { + // return { + // type: 'stop_reactor', + // id: this.source.selectOne(Object.keys(this.systemState.reactors)), + // } + // }, }) } @@ -440,8 +440,8 @@ class Test { } } -const NUM_TESTS = 1000 -const NUM_OPS_PER_TEST = 300 +const NUM_TESTS = 10000 +const NUM_OPS_PER_TEST = 2 function runTest(seed: number, ops?: Op[]) { const test = new Test(seed) @@ -464,9 +464,23 @@ function runTest(seed: number, ops?: Op[]) { } } -for (let i = 0; i < NUM_TESTS; i++) { - const seed = Math.floor(Math.random() * 1000000) - test('fuzzzzzz ' + seed, () => { - runTest(seed) - }) -} +// for (let i = 0; i < NUM_TESTS; i++) { +// const seed = Math.floor(Math.random() * 1000000) +// test('fuzzzzzz ' + seed, () => { +// runTest(seed) +// }) +// } + +test('fuzz', () => { + runTest(486560, [ + { + type: 'start_reactor', + id: 'q5ettr39t4', + }, + { + type: 'update_atom_in_atom', + id: '1h47iho0ey6', + atomId: '1fjwzc6mf3w', + }, + ]) +})