Skip to content

Commit

Permalink
feat(iotevents): support setting Events on input and exit for State (#…
Browse files Browse the repository at this point in the history
…19249)

This PR allow states in IoT Events detector model to set event on input and exit.
This PR is in roadmap of #17711.
<img width="530" alt="スクリーンショット 2022-03-05 13 40 57" src="https://user-images.githubusercontent.com/11013683/156868196-a37f5926-05e2-4d3b-a881-17520b465518.png">


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
yamatatsu committed Mar 8, 2022
1 parent dc7a17c commit ffa9e0d
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@
}
]
},
"OnInput": {},
"StateName": "MyState"
}
]
Expand Down
10 changes: 9 additions & 1 deletion packages/@aws-cdk/aws-iotevents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: [{ // optional
eventName: 'test-input-event',
actions: [new actions.LambdaInvokeAction(func)],
}],
onExit: [{ // optional
eventName: 'test-exit-event',
actions: [new actions.LambdaInvokeAction(func)],
}],
});
const coldState = new iotevents.State({
stateName: 'cold',
Expand Down
40 changes: 31 additions & 9 deletions packages/@aws-cdk/aws-iotevents/lib/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
}

/**
Expand Down Expand Up @@ -141,12 +157,18 @@ 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) },
onInput: {
onEnter: onEnter && {
events: toEventsJson(scope, actionBindOptions, onEnter),
},
onInput: (onInput || this.transitionEvents.length !== 0) ? {
events: toEventsJson(scope, actionBindOptions, onInput),
transitionEvents: toTransitionEventsJson(scope, actionBindOptions, this.transitionEvents),
} : undefined,
onExit: onExit && {
events: toEventsJson(scope, actionBindOptions, onExit),
},
};
}
Expand All @@ -155,9 +177,9 @@ export class State {
function toEventsJson(
scope: Construct,
actionBindOptions: ActionBindOptions,
events: Event[],
): CfnDetectorModel.EventProperty[] {
return events.map(event => ({
events?: Event[],
): CfnDetectorModel.EventProperty[] | undefined {
return events?.map(event => ({
eventName: event.eventName,
condition: event.condition?.evaluate(),
actions: event.actions?.map(action => action.bind(scope, actionBindOptions).configuration),
Expand Down
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit ffa9e0d

Please sign in to comment.