DAG: execute recompute levels concurrently

This commit is contained in:
2026-08-02 17:52:26 -04:00
parent 0c8efc8b69
commit cb6877be36
5 changed files with 108 additions and 42 deletions

View File

@@ -277,6 +277,50 @@ test('generation-aware recompute cancels an older run before accepting its resul
version = 2
})
test('recompute executes independent dependency levels concurrently and merges in stable order', async () => {
const document: DocumentSnapshot = {
...recomputeDocumentFixture(),
tree: [
{ id: 'root', label: 'Root', type: 'feature', state: 'dirty' },
{ id: 'left', label: 'Left', type: 'feature', state: 'dirty' },
{ id: 'right', label: 'Right', type: 'feature', state: 'dirty' },
],
objects: [
{ id: 'root', typeId: 'Part::Feature', properties: [] },
{ id: 'left', typeId: 'Part::Feature', properties: [] },
{ id: 'right', typeId: 'Part::Feature', properties: [] },
],
dependencies: [
{ sourceId: 'left', targetId: 'root', relation: 'link' },
{ sourceId: 'right', targetId: 'root', relation: 'link' },
],
recompute: {
generation: 0,
status: 'idle',
objectStates: { root: 'touched', left: 'touched', right: 'touched' },
dirtyObjects: ['root'],
order: [],
errors: [],
},
}
let active = 0
let maximumActive = 0
const coordinator = new RecomputeCoordinator(async (object) => {
active += 1
maximumActive = Math.max(maximumActive, active)
await new Promise((resolve) => setTimeout(resolve, 5))
active -= 1
return { status: 'success', updatedObject: object }
}, () => 1)
const result = await coordinator.run(document)
assert.equal(result.status, 'completed')
assert.equal(maximumActive, 2)
assert.deepEqual(result.order, ['root', 'left', 'right'])
assert.deepEqual(result.completed, ['root', 'left', 'right'])
assert.deepEqual(result.levels, [['root'], ['left', 'right']])
})
test('recompute rejects results from an obsolete document version', async () => {
let version = 1
const coordinator = new RecomputeCoordinator(async () => {
@@ -395,6 +439,17 @@ test('manifest commands without a Bitbybit executor are explicitly unsupported',
assert.equal(facade.getState().document.version, before)
})
test('implemented commands enforce their FreeCAD workbench preconditions', () => {
const facade = createMockFacade()
facade.gui.workbench.setActive('Sketcher')
assert.equal(facade.gui.command.getState('create-body').status, 'disabled')
assert.match(facade.gui.command.getState('create-body').reason || '', /Part Design/)
assert.equal(facade.gui.command.getState('new-sketch').status, 'enabled')
facade.gui.workbench.setActive('Part Design')
assert.equal(facade.gui.command.getState('new-sketch').status, 'disabled')
assert.equal(facade.gui.command.getState('pocket').status, 'enabled')
})
test('command events carry a document-scoped request context', () => {
const facade = createMockFacade()
const events: string[] = []