-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CLI: adding more validation to workflow (#696)
* Fixing: #604 * added new test for statePropsToRemove * runtime: adding more validation to workflow.json * removing ws-worker changes * removing ws-worker changes * runtime: added new tests to validate-plan.test.ts * log function switched to openfn/logger * completed: requested changes * moved validtion to CLI * removed @ts-ignore and changed error and test messages. * fixing workflow error message
- Loading branch information
1 parent
015b7f2
commit 7cf4171
Showing
6 changed files
with
170 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { ExecutionPlan, Step, WorkflowOptions } from "@openfn/lexicon"; | ||
import { Logger } from "@openfn/logger"; | ||
|
||
const assertWorkflowStructure = (plan: ExecutionPlan, logger: Logger) => { | ||
const { workflow, options } = plan; | ||
|
||
if (!workflow || typeof workflow !== 'object') { | ||
throw new Error(`Missing or invalid "workflow" key in execution plan`); | ||
} | ||
|
||
if (!Array.isArray(workflow.steps)) { | ||
throw new Error('The workflow.steps key must be an array'); | ||
} | ||
|
||
if (workflow.steps.length === 0) { | ||
logger.warn('The workflow.steps array is empty'); | ||
} | ||
|
||
workflow.steps.forEach((step, index) => { | ||
assertStepStructure(step, index); | ||
}); | ||
|
||
assertOptionsStructure(options, logger); | ||
}; | ||
|
||
const assertStepStructure = (step: Step, index: number) => { | ||
const allowedKeys = ['id', 'name', 'next', 'previous', 'adaptor', 'expression', 'state', 'configuration', 'linker']; | ||
|
||
for (const key in step) { | ||
if (!allowedKeys.includes(key)) { | ||
throw new Error(`Invalid key "${key}" in step ${step.id || index}`); | ||
} | ||
} | ||
|
||
if ('adaptor' in step && !('expression' in step)) { | ||
throw new Error(`Step ${step.id ?? index} with an adaptor must also have an expression`); | ||
} | ||
}; | ||
|
||
const assertOptionsStructure = (options: WorkflowOptions = {}, logger: Logger) => { | ||
const allowedKeys = ['timeout', 'stepTimeout', 'start', 'end', 'sanitize']; | ||
|
||
for (const key in options) { | ||
if (!allowedKeys.includes(key)) { | ||
logger.warn(`Unrecognized option "${key}" in options object`); | ||
} | ||
} | ||
}; | ||
|
||
export default assertWorkflowStructure; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import test from 'ava'; | ||
import { createMockLogger } from '@openfn/logger'; | ||
import type { ExecutionPlan } from '@openfn/lexicon'; | ||
import validate from '../../src/util/validate-plan'; | ||
|
||
const logger = createMockLogger('', { level: 'debug' }); | ||
|
||
test.afterEach(() => { | ||
logger._reset(); | ||
}) | ||
|
||
test('throws for missing workflow', (t) => { | ||
const plan = { | ||
options: { | ||
start: 'a', | ||
} | ||
} as ExecutionPlan; | ||
|
||
t.throws(() => validate(plan, logger), { | ||
message: `Missing or invalid "workflow" key in execution plan`, | ||
}); | ||
}); | ||
|
||
test('throws for steps not an array', (t) => { | ||
|
||
const plan = { | ||
options: { | ||
start: 'a', | ||
}, | ||
workflow: { | ||
steps: { | ||
id: 'a' | ||
} | ||
}, | ||
} as unknown as ExecutionPlan; | ||
|
||
t.throws(() => validate(plan, logger), { | ||
message: 'The workflow.steps key must be an array', | ||
}); | ||
}); | ||
|
||
test('throws for a step with an adaptor but no expression', (t) => { | ||
const plan = { | ||
options: { | ||
start: 'a', | ||
}, | ||
workflow: { | ||
steps: [ | ||
{ | ||
id: 'a', | ||
adaptor: 'z' | ||
} | ||
], | ||
}, | ||
} as unknown as ExecutionPlan; | ||
|
||
t.throws(() => validate(plan, logger), { | ||
message: 'Step a with an adaptor must also have an expression', | ||
}); | ||
}); | ||
|
||
test('throws for unknown key in a step', (t) => { | ||
const plan = { | ||
options: { | ||
start: 'a', | ||
}, | ||
workflow: { | ||
steps: [ | ||
{ | ||
id: 'a', | ||
key: 'z' | ||
} | ||
], | ||
}, | ||
}as unknown as ExecutionPlan; | ||
|
||
t.throws(() => validate(plan, logger), { | ||
message: 'Invalid key "key" in step a', | ||
}); | ||
}); | ||
|
||
test.serial('should warn if no steps are defined', (t) => { | ||
const plan: ExecutionPlan = { | ||
options: { | ||
start: 'a', | ||
}, | ||
workflow: { | ||
steps: [], | ||
}, | ||
}; | ||
validate(plan, logger); | ||
const { message, level } = logger._parse(logger._history[0]); | ||
t.is(level, 'warn'); | ||
t.regex(message as string, /The workflow.steps array is empty/); | ||
}) | ||
|
||
test.serial('should warn if unknown key is passed in options', (t) => { | ||
const plan = { | ||
options: { | ||
start: 'a', | ||
key: 'z', | ||
}, | ||
workflow: { | ||
steps: [{ | ||
id: 'a', | ||
}], | ||
}, | ||
} as unknown as ExecutionPlan; | ||
validate(plan, logger); | ||
const { message, level } = logger._parse(logger._history[0]); | ||
t.is(level, 'warn'); | ||
t.regex(message as string, /Unrecognized option "key" in options object/); | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters