Skip to content

Commit ffa9e0d

Browse files
authored
feat(iotevents): support setting Events on input and exit for State (#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*
1 parent dc7a17c commit ffa9e0d

File tree

6 files changed

+110
-11
lines changed

6 files changed

+110
-11
lines changed

packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json

-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@
144144
}
145145
]
146146
},
147-
"OnInput": {},
148147
"StateName": "MyState"
149148
}
150149
]

packages/@aws-cdk/aws-iotevents/README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,18 @@ const input = new iotevents.Input(this, 'MyInput', {
6464
const warmState = new iotevents.State({
6565
stateName: 'warm',
6666
onEnter: [{
67-
eventName: 'test-event',
67+
eventName: 'test-enter-event',
6868
condition: iotevents.Expression.currentInput(input),
6969
actions: [new actions.LambdaInvokeAction(func)], // optional
7070
}],
71+
onInput: [{ // optional
72+
eventName: 'test-input-event',
73+
actions: [new actions.LambdaInvokeAction(func)],
74+
}],
75+
onExit: [{ // optional
76+
eventName: 'test-exit-event',
77+
actions: [new actions.LambdaInvokeAction(func)],
78+
}],
7179
});
7280
const coldState = new iotevents.State({
7381
stateName: 'cold',

packages/@aws-cdk/aws-iotevents/lib/state.ts

+31-9
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,28 @@ export interface StateProps {
6666
readonly stateName: string;
6767

6868
/**
69-
* Specifies the events on enter. the conditions of the events are evaluated when the state is entered.
70-
* If the condition is `TRUE`, the actions of the event are performed.
69+
* Specifies the events on enter. The conditions of the events will be evaluated when entering this state.
70+
* If the condition of the event evaluates to `true`, the actions of the event will be executed.
7171
*
72-
* @default - events on enter will not be set
72+
* @default - no events will trigger on entering this state
7373
*/
7474
readonly onEnter?: Event[];
75+
76+
/**
77+
* Specifies the events on input. The conditions of the events will be evaluated when any input is received.
78+
* If the condition of the event evaluates to `true`, the actions of the event will be executed.
79+
*
80+
* @default - no events will trigger on input in this state
81+
*/
82+
readonly onInput?: Event[];
83+
84+
/**
85+
* Specifies the events on exit. The conditions of the events are evaluated when an exiting this state.
86+
* If the condition evaluates to `true`, the actions of the event will be executed.
87+
*
88+
* @default - no events will trigger on exiting this state
89+
*/
90+
readonly onExit?: Event[];
7591
}
7692

7793
/**
@@ -141,12 +157,18 @@ export class State {
141157
}
142158

143159
private toStateJson(scope: Construct, actionBindOptions: ActionBindOptions): CfnDetectorModel.StateProperty {
144-
const { onEnter } = this.props;
160+
const { onEnter, onInput, onExit } = this.props;
145161
return {
146162
stateName: this.stateName,
147-
onEnter: onEnter && { events: toEventsJson(scope, actionBindOptions, onEnter) },
148-
onInput: {
163+
onEnter: onEnter && {
164+
events: toEventsJson(scope, actionBindOptions, onEnter),
165+
},
166+
onInput: (onInput || this.transitionEvents.length !== 0) ? {
167+
events: toEventsJson(scope, actionBindOptions, onInput),
149168
transitionEvents: toTransitionEventsJson(scope, actionBindOptions, this.transitionEvents),
169+
} : undefined,
170+
onExit: onExit && {
171+
events: toEventsJson(scope, actionBindOptions, onExit),
150172
},
151173
};
152174
}
@@ -155,9 +177,9 @@ export class State {
155177
function toEventsJson(
156178
scope: Construct,
157179
actionBindOptions: ActionBindOptions,
158-
events: Event[],
159-
): CfnDetectorModel.EventProperty[] {
160-
return events.map(event => ({
180+
events?: Event[],
181+
): CfnDetectorModel.EventProperty[] | undefined {
182+
return events?.map(event => ({
161183
eventName: event.eventName,
162184
condition: event.condition?.evaluate(),
163185
actions: event.actions?.map(action => action.bind(scope, actionBindOptions).configuration),

packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,26 @@ test('can set actions to events', () => {
176176
});
177177
});
178178

179+
test.each([
180+
['onInput', { onInput: [{ eventName: 'test-eventName1' }] }, { OnInput: { Events: [{ EventName: 'test-eventName1' }] } }],
181+
['onExit', { onExit: [{ eventName: 'test-eventName1' }] }, { OnExit: { Events: [{ EventName: 'test-eventName1' }] } }],
182+
])('can set %s to State', (_, events, expected) => {
183+
// WHEN
184+
new iotevents.DetectorModel(stack, 'MyDetectorModel', {
185+
initialState: new iotevents.State({
186+
stateName: 'test-state',
187+
onEnter: [{ eventName: 'test-eventName1', condition: iotevents.Expression.currentInput(input) }],
188+
...events,
189+
}),
190+
});
191+
192+
// THEN
193+
Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', {
194+
DetectorModelDefinition: {
195+
States: [Match.objectLike(expected)],
196+
},
197+
});
198+
});
179199

180200
test('can set an action to multiple detector models', () => {
181201
// GIVEN an action

packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json

+36
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,43 @@
6363
}
6464
]
6565
},
66+
"OnExit": {
67+
"Events": [
68+
{
69+
"Condition": {
70+
"Fn::Join": [
71+
"",
72+
[
73+
"$input.",
74+
{
75+
"Ref": "MyInput08947B23"
76+
},
77+
".payload.temperature == 31.7"
78+
]
79+
]
80+
},
81+
"EventName": "test-exit-event"
82+
}
83+
]
84+
},
6685
"OnInput": {
86+
"Events": [
87+
{
88+
"Condition": {
89+
"Fn::Join": [
90+
"",
91+
[
92+
"$input.",
93+
{
94+
"Ref": "MyInput08947B23"
95+
},
96+
".payload.temperature == 31.6"
97+
]
98+
]
99+
},
100+
"EventName": "test-input-event"
101+
}
102+
],
67103
"TransitionEvents": [
68104
{
69105
"Condition": {

packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts

+14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ class TestStack extends cdk.Stack {
2323
),
2424
),
2525
}],
26+
onInput: [{
27+
eventName: 'test-input-event',
28+
condition: iotevents.Expression.eq(
29+
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
30+
iotevents.Expression.fromString('31.6'),
31+
),
32+
}],
33+
onExit: [{
34+
eventName: 'test-exit-event',
35+
condition: iotevents.Expression.eq(
36+
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
37+
iotevents.Expression.fromString('31.7'),
38+
),
39+
}],
2640
});
2741
const offlineState = new iotevents.State({
2842
stateName: 'offline',

0 commit comments

Comments
 (0)