Skip to content

Commit

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

This PR allow states in IoT Events detector model to set event on input and exit.
This PR is in roadmap of aws#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 authored and TheRealAmazonKendra committed Mar 11, 2022
1 parent 7e2a69b commit b4ee0cb
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 b4ee0cb

Please sign in to comment.