@wmfs/statelint
Version:
Validator for Amazon States Language JSON files.
382 lines (351 loc) • 10.5 kB
JavaScript
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const stateLint = require('../lib')
describe('StateMachineLint', () => {
describe('Fail states', () => {
verify(
'Allow Fail states to omit optional Cause/Error fields',
require('./fixtures/minimal-fail-state.json')
)
verify(
'Allow Fail states to use ErrorPath and CausePath fields',
require('./fixtures/fail-with-error-and-cause-path.json')
)
verify(
'Allow Fail states to use ErrorPath and CausePath fields with intrinsic functions',
require('./fixtures/fail-with-error-and-cause-path-using-intrinsic-functions.json')
)
verify(
'Reject Fail state with both static and dynamic error',
require('./fixtures/fail-with-static-and-dynamic-error.json'),
'may have only one of Error,ErrorPath'
)
verify(
'Reject Fail state with both static and dynamic cause',
require('./fixtures/fail-with-static-and-dynamic-cause.json'),
'may have only one of Cause,CausePath'
)
})
describe('Delay and Jitter', () => {
verify(
'Allow Retry to with MaxDelaySeconds and JitterStrategy',
require('./fixtures/backoff-with-jitter-on-retry.json')
)
verify(
'Reject invalid JitterStrategy',
require('./fixtures/backoff-with-invalid-jitter-on-retry.json'),
'not one of the allowed values FULL,NONE'
)
verify(
'Reject invalid MaxDelaySeconds',
require('./fixtures/invalid-backoff-with-jitter-on-retry.json'),
'allowed floor is 0'
)
})
describe('Empty ErrorEquals clauses', () => {
verify(
'Reject empty ErrorEquals on Catch',
require('./fixtures/empty-error-equals-on-catch'),
'non-empty required'
)
verify(
'Reject empty ErrorEquals on Retry',
require('./fixtures/empty-error-equals-on-retry'),
'non-empty required'
)
})
describe('Parameters only valid on Pass, Task, Parallel, and Map', () => {
verify(
'Pass with Parameters',
require('./fixtures/pass-with-parameters')
)
verify(
'Task with Parameters',
require('./fixtures/task-with-parameters')
)
verify(
'Parallel with Parameters',
require('./fixtures/parallel-with-parameters')
)
verify(
'Map with Parameters',
require('./fixtures/map-with-parameters')
)
})
describe('Parameters not valid on all other state types', () => {
verify(
'Choice With Parameters',
require('./fixtures/choice-with-parameters'),
'"Parameters'
)
verify(
'Wait With Parameters',
require('./fixtures/wait-with-parameters'),
'"Parameters'
)
verify(
'Succeed With Parameters',
require('./fixtures/succeed-with-parameters'),
'"Parameters'
)
verify(
'Fail With Parameters',
require('./fixtures/fail-with-parameters'),
'"Parameters'
)
})
describe('Parameter paths', () => {
verify(
'reject non-Path constructs in Parameter fields ending in ".$"',
require('./fixtures/parameter-path-problems'),
'bad1',
'bad2',
'bad3',
'bad4'
)
})
describe('ResultPath only valid on Pass, Task, Parallel', () => {
verify(
'Pass with ResultPath',
require('./fixtures/pass-with-resultpath')
)
verify(
'Task with ResultPath',
require('./fixtures/task-with-resultpath')
)
verify(
'Parallel with ResultPath',
require('./fixtures/parallel-with-resultpath')
)
})
describe('ResultPath not valid on all other State types', () => {
verify(
'Choice with ResultPath',
require('./fixtures/choice-with-resultpath'),
'"ResultPath"'
)
verify(
'Wait with ResultPath',
require('./fixtures/wait-with-resultpath'),
'"ResultPath"'
)
verify(
'Succeed with ResultPath',
require('./fixtures/succeed-with-resultpath'),
'"ResultPath"'
)
verify(
'Fail with ResultPath',
require('./fixtures/fail-with-resultpath'),
'"ResultPath"'
)
})
describe('Context object', () => {
verify(
'Allow context object access in InputPath and OutputPath',
require('./fixtures/pass-with-io-path-context-object.json')
)
verify(
'Allow context object access in Choice state Variable',
require('./fixtures/choice-with-context-object.json')
)
verify(
'Allow context object access in Map state ItemsPath',
require('./fixtures/map-with-itemspath-context-object.json')
)
})
describe('Timeouts', () => {
verify(
'Allow dynamic timeout fields in Task state',
require('./fixtures/task-with-dynamic-timeouts.json')
)
verify(
'Reject task with static and dynamic timeouts',
require('./fixtures/task-with-static-and-dynamic-timeout.json'),
'may have only one of TimeoutSeconds,TimeoutSecondsPath'
)
verify(
'Reject task with static and dynamic timeouts',
require('./fixtures/task-with-static-and-dynamic-heartbeat.json'),
'may have only one of HeartbeatSeconds,HeartbeatSecondsPath'
)
})
describe('Null paths', () => {
verify(
'Allow null values in InputPath',
require('./fixtures/pass-with-null-inputpath.json')
)
verify(
'Allow null values in OutputPath',
require('./fixtures/pass-with-null-outputpath.json')
)
verify(
'Not allow null value in Map state ItemsPath',
require('./fixtures/map-with-null-itemspath.json'),
'ItemsPath'
)
})
describe('ResultSelector', () => {
verify(
'Allow ResultSelector on Task',
require('./fixtures/task-with-resultselector.json')
)
verify(
'Allow ResultSelector on Parallel',
require('./fixtures/parallel-with-resultselector.json')
)
verify(
'Allow ResultSelector on Map',
require('./fixtures/map-with-resultselector.json')
)
verify(
'Reject ResultSelector on Pass',
require('./fixtures/pass-with-resultselector.json'),
'"ResultSelector"'
)
verify(
'Reject ResultSelector on Wait',
require('./fixtures/wait-with-resultselector.json'),
'"ResultSelector"'
)
verify(
'Reject ResultSelector on Fail',
require('./fixtures/fail-with-resultselector.json'),
'"ResultSelector"'
)
verify(
'Reject ResultSelector on Succeed',
require('./fixtures/succeed-with-resultselector.json'),
'"ResultSelector"'
)
verify(
'Reject ResultSelector on Choice',
require('./fixtures/choice-with-resultselector.json'),
'"ResultSelector"'
)
})
describe('Intrinsic function invocation in payload builder fields', () => {
verify(
'States Array invocation',
require('./fixtures/states-array-invocation.json')
)
verify(
'States Format invocation',
require('./fixtures/states-format-invocation.json')
)
verify(
'States StringToJson invocation',
require('./fixtures/states-stringtojson-invocation.json')
)
verify(
'States JsonToString invocation',
require('./fixtures/states-jsontostring-invocation.json')
)
verify(
'Reject invalid States Array invocation',
require('./fixtures/states-array-invocation-leftpad.json'),
'not a JSONPath or intrinsic function expression'
)
verify(
'Reject invalid Function invocation',
require('./fixtures/invalid-function-invocation.json'),
'not a JSONPath or intrinsic function expression'
)
verify(
'Reject intrinsic function inputpath',
require('./fixtures/pass-with-intrinsic-function-inputpath.json'),
'"InputPath"'
)
})
describe('Functions added in 2022', () => {
verify(
'Array intrinsic function',
require('./fixtures/states-array-intrinsic-functions.json')
)
verify(
'Encoding/decoding intrinsic function',
require('./fixtures/states-encoding-decoding-intrinsic-functions.json')
)
verify(
'Hash intrinsic function',
require('./fixtures/states-hash-intrinsic-functions.json')
)
verify(
'Json intrinsic function',
require('./fixtures/states-json-intrinsic-functions.json')
)
verify(
'Math intrinsic function',
require('./fixtures/states-math-intrinsic-functions.json')
)
verify(
'String intrinsic function',
require('./fixtures/states-string-intrinsic-functions.json')
)
verify(
'UUID intrinsic function',
require('./fixtures/states-uuid-intrinsic-functions.json')
)
})
describe('Comment', () => {
verify(
'Allow Choice Rule to use Comment',
require('./fixtures/choice-rule-with-comment.json')
)
verify(
'Allow a Comment field in Catcher',
require('./fixtures/succeed-with-comment-in-catcher.json')
)
})
describe('Map state', () => {
verify(
'Allow ItemProcessor in Map',
require('./fixtures/map-with-itemprocessor.json')
)
verify(
'Reject Map state with both Iterator and ItemProcessor',
require('./fixtures/map-with-itemprocessor-and-iterator.json'),
'may have only one of Iterator,ItemProcessor'
)
verify(
'Reject Map state with both Parameters and ItemSelector',
require('./fixtures/map-with-parameters-and-itemselector.json'),
'may have only one of ItemSelector,Parameters'
)
})
describe('Task state', () => {
verify(
'Allow Credentials in Task',
require('./fixtures/task-with-credentials.json')
)
verify(
'Reject invalid Credentials in Task',
require('./fixtures/task-with-invalid-credentials.json'),
'should be an Object'
)
})
describe('Validate Catch', () => {
verify(
'Catch States.ALL',
require('./fixtures/hello-world-with-caught-failures')
)
})
describe('Real-life state machines', () => {
verify(
'BackoffRate maybe an integer',
require('./fixtures/j2119_issues_37')
)
})
})
function verify (label, json, ...msg) {
it(label, () => {
const linter = stateLint()
const problems = linter.validate(json)
expect(problems.length).to.eql(msg.length)
for (let i = 0; i !== msg.length; ++i) {
expect(problems[i]).to.include(msg[i])
}
})
}