From 22cc6ef0af8275c0a3ae4f6df11e972020ea97d7 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Sat, 5 Mar 2022 13:29:49 +0900 Subject: [PATCH] feat(iot-events): support input action and exit action --- .../integ.lambda-invoke-action.expected.json | 1 + packages/@aws-cdk/aws-iotevents/README.md | 10 ++++- packages/@aws-cdk/aws-iotevents/lib/state.ts | 40 +++++++++++++++---- .../aws-iotevents/test/detector-model.test.ts | 20 ++++++++++ .../test/integ.detector-model.expected.json | 38 ++++++++++++++++++ .../test/integ.detector-model.ts | 14 +++++++ 6 files changed, 115 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json index be70d65360d32..d5b3fe5b44565 100644 --- a/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json +++ b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json @@ -144,6 +144,7 @@ } ] }, + "OnExit": {}, "OnInput": {}, "StateName": "MyState" } diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 0c7e491c65fae..bcbdeb92587e2 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -64,10 +64,18 @@ const input = new iotevents.Input(this, 'MyInput', { const warmState = new iotevents.State({ stateName: 'warm', onEnter: [{ - eventName: 'test-event', + eventName: 'test-enter-event', condition: iotevents.Expression.currentInput(input), actions: [new actions.LambdaInvokeAction(func)], // optional }], + onInput: [{ + eventName: 'test-input-event', + actions: [new actions.LambdaInvokeAction(func)], // optional + }], + onExit: [{ + eventName: 'test-exit-event', + actions: [new actions.LambdaInvokeAction(func)], // optional + }], }); const coldState = new iotevents.State({ stateName: 'cold', diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 0159628c4a4ff..b0aae93f00d95 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -66,12 +66,28 @@ export interface StateProps { readonly stateName: string; /** - * Specifies the events on enter. the conditions of the events are evaluated when the state is entered. - * If the condition is `TRUE`, the actions of the event are performed. + * Specifies the events on enter. The conditions of the events will be evaluated when entering this state. + * If the condition of the event evaluates to `true`, the actions of the event will be executed. * - * @default - events on enter will not be set + * @default - no events will trigger on entering this state */ readonly onEnter?: Event[]; + + /** + * Specifies the events on input. The conditions of the events will be evaluated when any input is received. + * If the condition of the event evaluates to `true`, the actions of the event will be executed. + * + * @default - no events will trigger on input in this state + */ + readonly onInput?: Event[]; + + /** + * Specifies the events on exit. The conditions of the events are evaluated when an exiting this state. + * If the condition evaluates to `true`, the actions of the event will be executed. + * + * @default - no events will trigger on exiting this state + */ + readonly onExit?: Event[]; } /** @@ -141,13 +157,19 @@ export class State { } private toStateJson(scope: Construct, actionBindOptions: ActionBindOptions): CfnDetectorModel.StateProperty { - const { onEnter } = this.props; + const { onEnter, onInput, onExit } = this.props; return { stateName: this.stateName, - onEnter: onEnter && { events: toEventsJson(scope, actionBindOptions, onEnter) }, + onEnter: { + events: toEventsJson(scope, actionBindOptions, onEnter), + }, onInput: { + events: toEventsJson(scope, actionBindOptions, onInput), transitionEvents: toTransitionEventsJson(scope, actionBindOptions, this.transitionEvents), }, + onExit: { + events: toEventsJson(scope, actionBindOptions, onExit), + }, }; } } @@ -155,8 +177,12 @@ export class State { function toEventsJson( scope: Construct, actionBindOptions: ActionBindOptions, - events: Event[], -): CfnDetectorModel.EventProperty[] { + events?: Event[], +): CfnDetectorModel.EventProperty[] | undefined { + if (!events) { + return undefined; + } + return events.map(event => ({ eventName: event.eventName, condition: event.condition?.evaluate(), diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts index ec754f25c1aad..e3844ce7915ba 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -176,6 +176,26 @@ test('can set actions to events', () => { }); }); +test.each([ + ['onInput', { onInput: [{ eventName: 'test-eventName1' }] }, { OnInput: { Events: [{ EventName: 'test-eventName1' }] } }], + ['onExit', { onExit: [{ eventName: 'test-eventName1' }] }, { OnExit: { Events: [{ EventName: 'test-eventName1' }] } }], +])('can set %s to State', (_, events, expected) => { + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ eventName: 'test-eventName1', condition: iotevents.Expression.currentInput(input) }], + ...events, + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [Match.objectLike(expected)], + }, + }); +}); test('can set an action to multiple detector models', () => { // GIVEN an action diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index 888869a41e68e..4081ff326b3e1 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -63,7 +63,43 @@ } ] }, + "OnExit": { + "Events": [ + { + "Condition": { + "Fn::Join": [ + "", + [ + "$input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature == 31.7" + ] + ] + }, + "EventName": "test-exit-event" + } + ] + }, "OnInput": { + "Events": [ + { + "Condition": { + "Fn::Join": [ + "", + [ + "$input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature == 31.6" + ] + ] + }, + "EventName": "test-input-event" + } + ], "TransitionEvents": [ { "Condition": { @@ -86,6 +122,8 @@ "StateName": "online" }, { + "OnEnter": {}, + "OnExit": {}, "OnInput": { "TransitionEvents": [ { diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts index 5f6d2839f3a93..1c3996b226623 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -23,6 +23,20 @@ class TestStack extends cdk.Stack { ), ), }], + onInput: [{ + eventName: 'test-input-event', + condition: iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('31.6'), + ), + }], + onExit: [{ + eventName: 'test-exit-event', + condition: iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('31.7'), + ), + }], }); const offlineState = new iotevents.State({ stateName: 'offline',